Repository: BG-Software-LLC/SuperiorSkyblock2 Branch: dev Commit: b9ab67ed679e Files: 1742 Total size: 8.1 MB Directory structure: gitextract_b7lsuvt_/ ├── .claudeignore ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.yaml │ │ └── config.yml │ └── workflows/ │ └── gemini.yml ├── .gitignore ├── API/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── bgsoftware/ │ └── superiorskyblock/ │ └── api/ │ ├── SuperiorSkyblock.java │ ├── SuperiorSkyblockAPI.java │ ├── commands/ │ │ └── SuperiorCommand.java │ ├── config/ │ │ └── SettingsManager.java │ ├── data/ │ │ ├── DatabaseBridge.java │ │ ├── DatabaseBridgeMode.java │ │ ├── DatabaseFilter.java │ │ └── IDatabaseBridgeHolder.java │ ├── entity/ │ │ └── EntityCategory.java │ ├── enums/ │ │ ├── BankAction.java │ │ ├── BorderColor.java │ │ ├── HitActionResult.java │ │ ├── MemberRemoveReason.java │ │ ├── Rating.java │ │ ├── SyncStatus.java │ │ └── TopIslandMembersSorting.java │ ├── events/ │ │ ├── AttemptPlayerSendMessageEvent.java │ │ ├── BlockStackEvent.java │ │ ├── BlockUnstackEvent.java │ │ ├── IslandBanEvent.java │ │ ├── IslandBankDepositEvent.java │ │ ├── IslandBankWithdrawEvent.java │ │ ├── IslandBiomeChangeEvent.java │ │ ├── IslandChangeBankLimitEvent.java │ │ ├── IslandChangeBlockLimitEvent.java │ │ ├── IslandChangeBorderSizeEvent.java │ │ ├── IslandChangeCoopLimitEvent.java │ │ ├── IslandChangeCropGrowthEvent.java │ │ ├── IslandChangeDescriptionEvent.java │ │ ├── IslandChangeDiscordEvent.java │ │ ├── IslandChangeEffectLevelEvent.java │ │ ├── IslandChangeEntityLimitEvent.java │ │ ├── IslandChangeGeneratorRateEvent.java │ │ ├── IslandChangeLevelBonusEvent.java │ │ ├── IslandChangeMembersLimitEvent.java │ │ ├── IslandChangeMobDropsEvent.java │ │ ├── IslandChangePaypalEvent.java │ │ ├── IslandChangePlayerPrivilegeEvent.java │ │ ├── IslandChangeRoleLimitEvent.java │ │ ├── IslandChangeRolePrivilegeEvent.java │ │ ├── IslandChangeSpawnerRatesEvent.java │ │ ├── IslandChangeWarpCategoryIconEvent.java │ │ ├── IslandChangeWarpCategorySlotEvent.java │ │ ├── IslandChangeWarpIconEvent.java │ │ ├── IslandChangeWarpLocationEvent.java │ │ ├── IslandChangeWarpsLimitEvent.java │ │ ├── IslandChangeWorthBonusEvent.java │ │ ├── IslandChatEvent.java │ │ ├── IslandChunkResetEvent.java │ │ ├── IslandClearFlagsEvent.java │ │ ├── IslandClearGeneratorRatesEvent.java │ │ ├── IslandClearPlayerPrivilegesEvent.java │ │ ├── IslandClearRatingsEvent.java │ │ ├── IslandClearRolesPrivilegesEvent.java │ │ ├── IslandCloseEvent.java │ │ ├── IslandCloseWarpEvent.java │ │ ├── IslandCoopPlayerEvent.java │ │ ├── IslandCreateEvent.java │ │ ├── IslandCreateWarpCategoryEvent.java │ │ ├── IslandCreateWarpEvent.java │ │ ├── IslandDeleteWarpEvent.java │ │ ├── IslandDisableFlagEvent.java │ │ ├── IslandDisbandEvent.java │ │ ├── IslandEnableFlagEvent.java │ │ ├── IslandEnterEvent.java │ │ ├── IslandEnterPortalEvent.java │ │ ├── IslandEnterProtectedEvent.java │ │ ├── IslandEvent.java │ │ ├── IslandGenerateBlockEvent.java │ │ ├── IslandHomeTeleportEvent.java │ │ ├── IslandInviteEvent.java │ │ ├── IslandJoinEvent.java │ │ ├── IslandKickEvent.java │ │ ├── IslandLeaveEvent.java │ │ ├── IslandLeaveProtectedEvent.java │ │ ├── IslandLockWorldEvent.java │ │ ├── IslandOpenEvent.java │ │ ├── IslandOpenWarpEvent.java │ │ ├── IslandQuitEvent.java │ │ ├── IslandRateEvent.java │ │ ├── IslandRemoveBlockLimitEvent.java │ │ ├── IslandRemoveEffectEvent.java │ │ ├── IslandRemoveEntityLimitEvent.java │ │ ├── IslandRemoveGeneratorRateEvent.java │ │ ├── IslandRemoveRatingEvent.java │ │ ├── IslandRemoveRoleLimitEvent.java │ │ ├── IslandRemoveVisitorHomeEvent.java │ │ ├── IslandRenameEvent.java │ │ ├── IslandRenameWarpCategoryEvent.java │ │ ├── IslandRenameWarpEvent.java │ │ ├── IslandRestrictMoveEvent.java │ │ ├── IslandSchematicPasteEvent.java │ │ ├── IslandSetHomeEvent.java │ │ ├── IslandSetVisitorHomeEvent.java │ │ ├── IslandTransferEvent.java │ │ ├── IslandUnbanEvent.java │ │ ├── IslandUncoopPlayerEvent.java │ │ ├── IslandUnlockWorldEvent.java │ │ ├── IslandUpgradeEvent.java │ │ ├── IslandVisitorHomeTeleportEvent.java │ │ ├── IslandWarpTeleportEvent.java │ │ ├── IslandWorldResetEvent.java │ │ ├── IslandWorthCalculatedEvent.java │ │ ├── IslandWorthUpdateEvent.java │ │ ├── MissionCompleteEvent.java │ │ ├── MissionResetEvent.java │ │ ├── PlayerChangeBorderColorEvent.java │ │ ├── PlayerChangeLanguageEvent.java │ │ ├── PlayerChangeNameEvent.java │ │ ├── PlayerChangeRoleEvent.java │ │ ├── PlayerCloseMenuEvent.java │ │ ├── PlayerOpenMenuEvent.java │ │ ├── PlayerReplaceEvent.java │ │ ├── PlayerToggleBlocksStackerEvent.java │ │ ├── PlayerToggleBorderEvent.java │ │ ├── PlayerToggleBypassEvent.java │ │ ├── PlayerToggleFlyEvent.java │ │ ├── PlayerTogglePanelEvent.java │ │ ├── PlayerToggleSpyEvent.java │ │ ├── PlayerToggleTeamChatEvent.java │ │ ├── PluginInitializeEvent.java │ │ ├── PluginInitializedEvent.java │ │ ├── PluginLoadDataEvent.java │ │ ├── PostIslandCreateEvent.java │ │ ├── PreIslandCreateEvent.java │ │ └── SendMessageEvent.java │ ├── factory/ │ │ ├── BanksFactory.java │ │ ├── DatabaseBridgeFactory.java │ │ ├── DelegateBanksFactory.java │ │ ├── DelegateDatabaseBridgeFactory.java │ │ ├── DelegateIslandsFactory.java │ │ ├── DelegatePlayersFactory.java │ │ ├── IslandsFactory.java │ │ └── PlayersFactory.java │ ├── handlers/ │ │ ├── BlockValuesManager.java │ │ ├── CommandsManager.java │ │ ├── FactoriesManager.java │ │ ├── GridManager.java │ │ ├── KeysManager.java │ │ ├── MenusManager.java │ │ ├── MissionsManager.java │ │ ├── ModulesManager.java │ │ ├── PlayersManager.java │ │ ├── ProvidersManager.java │ │ ├── RolesManager.java │ │ ├── SchematicManager.java │ │ ├── StackedBlocksManager.java │ │ └── UpgradesManager.java │ ├── hooks/ │ │ ├── AFKProvider.java │ │ ├── ChunksProvider.java │ │ ├── EconomyProvider.java │ │ ├── EntitiesProvider.java │ │ ├── LazyWorldsProvider.java │ │ ├── MenusProvider.java │ │ ├── PermissionsProvider.java │ │ ├── PricesProvider.java │ │ ├── SpawnersProvider.java │ │ ├── SpawnersSnapshotProvider.java │ │ ├── StackedBlocksProvider.java │ │ ├── StackedBlocksSnapshotProvider.java │ │ ├── VanishProvider.java │ │ ├── WorldsProvider.java │ │ ├── listener/ │ │ │ ├── ISkinsListener.java │ │ │ ├── IStackedBlocksListener.java │ │ │ ├── IWorldLoadListener.java │ │ │ └── IWorldsListener.java │ │ └── world/ │ │ └── WorldLoadFlags.java │ ├── island/ │ │ ├── BlockChangeResult.java │ │ ├── DelegateIsland.java │ │ ├── DelegateIslandChest.java │ │ ├── DelegateIslandPreview.java │ │ ├── DelegatePermissionNode.java │ │ ├── Island.java │ │ ├── IslandBlockFlags.java │ │ ├── IslandChest.java │ │ ├── IslandChunkFlags.java │ │ ├── IslandFlag.java │ │ ├── IslandPreview.java │ │ ├── IslandPrivilege.java │ │ ├── PermissionNode.java │ │ ├── PlayerRole.java │ │ ├── SortingType.java │ │ ├── algorithms/ │ │ │ ├── DelegateIslandBlocksTrackerAlgorithm.java │ │ │ ├── DelegateIslandCalculationAlgorithm.java │ │ │ ├── DelegateIslandEntitiesTrackerAlgorithm.java │ │ │ ├── IslandBlocksTrackerAlgorithm.java │ │ │ ├── IslandCalculationAlgorithm.java │ │ │ └── IslandEntitiesTrackerAlgorithm.java │ │ ├── bank/ │ │ │ ├── BankTransaction.java │ │ │ ├── DelegateBankTransaction.java │ │ │ ├── DelegateIslandBank.java │ │ │ └── IslandBank.java │ │ ├── cache/ │ │ │ ├── IslandCache.java │ │ │ └── IslandCacheKey.java │ │ ├── container/ │ │ │ ├── DelegateIslandsContainer.java │ │ │ └── IslandsContainer.java │ │ └── warps/ │ │ ├── DelegateIslandWarp.java │ │ ├── DelegateWarpCategory.java │ │ ├── IslandWarp.java │ │ └── WarpCategory.java │ ├── key/ │ │ ├── CustomKeyParser.java │ │ ├── Key.java │ │ ├── KeyMap.java │ │ └── KeySet.java │ ├── menu/ │ │ ├── BaseMenu.java │ │ ├── ISuperiorMenu.java │ │ ├── Menu.java │ │ ├── MenuCommands.java │ │ ├── MenuIslandCreationConfig.java │ │ ├── PagedMenu.java │ │ ├── button/ │ │ │ ├── MenuTemplateButton.java │ │ │ ├── MenuViewButton.java │ │ │ ├── PagedMenuTemplateButton.java │ │ │ └── PagedMenuViewButton.java │ │ ├── layout/ │ │ │ ├── MenuLayout.java │ │ │ └── PagedMenuLayout.java │ │ ├── parser/ │ │ │ ├── MenuParseException.java │ │ │ └── MenuParser.java │ │ └── view/ │ │ ├── BaseMenuView.java │ │ ├── BasePagedMenuView.java │ │ ├── MenuView.java │ │ ├── PagedMenuView.java │ │ └── ViewArgs.java │ ├── missions/ │ │ ├── IMissionsHolder.java │ │ ├── Mission.java │ │ ├── MissionCategory.java │ │ └── MissionLoadException.java │ ├── modules/ │ │ ├── ModuleInitializeData.java │ │ ├── ModuleLoadTime.java │ │ ├── ModuleLogger.java │ │ ├── ModuleResources.java │ │ └── PluginModule.java │ ├── objects/ │ │ ├── Enumerable.java │ │ └── Pair.java │ ├── persistence/ │ │ ├── DelegatePersistentDataContainer.java │ │ ├── IPersistentDataHolder.java │ │ ├── PersistentDataContainer.java │ │ ├── PersistentDataType.java │ │ └── PersistentDataTypeContext.java │ ├── platform/ │ │ └── IEventsDispatcher.java │ ├── player/ │ │ ├── DelegateSuperiorPlayer.java │ │ ├── PlayerStatus.java │ │ ├── algorithm/ │ │ │ ├── DelegatePlayerTeleportAlgorithm.java │ │ │ └── PlayerTeleportAlgorithm.java │ │ ├── cache/ │ │ │ ├── PlayerCache.java │ │ │ └── PlayerCacheKey.java │ │ ├── container/ │ │ │ ├── DelegatePlayersContainer.java │ │ │ └── PlayersContainer.java │ │ ├── inventory/ │ │ │ └── ClearAction.java │ │ └── respawn/ │ │ └── RespawnAction.java │ ├── schematic/ │ │ ├── Schematic.java │ │ ├── SchematicOptions.java │ │ └── parser/ │ │ ├── SchematicParseException.java │ │ └── SchematicParser.java │ ├── scripts/ │ │ └── IScriptEngine.java │ ├── service/ │ │ ├── bossbar/ │ │ │ ├── BossBar.java │ │ │ └── BossBarsService.java │ │ ├── dragon/ │ │ │ ├── DragonBattleResetResult.java │ │ │ └── DragonBattleService.java │ │ ├── hologram/ │ │ │ ├── Hologram.java │ │ │ └── HologramsService.java │ │ ├── message/ │ │ │ ├── IMessageComponent.java │ │ │ └── MessagesService.java │ │ ├── placeholders/ │ │ │ ├── IslandPlaceholderParser.java │ │ │ ├── PlaceholdersService.java │ │ │ └── PlayerPlaceholderParser.java │ │ ├── portals/ │ │ │ ├── EntityPortalResult.java │ │ │ └── PortalsManagerService.java │ │ ├── region/ │ │ │ ├── InteractionResult.java │ │ │ ├── MoveResult.java │ │ │ └── RegionManagerService.java │ │ ├── stackedblocks/ │ │ │ ├── InteractionResult.java │ │ │ └── StackedBlocksInteractionService.java │ │ └── world/ │ │ ├── RecordResult.java │ │ ├── WorldRecordFlags.java │ │ └── WorldRecordService.java │ ├── upgrades/ │ │ ├── Upgrade.java │ │ ├── UpgradeLevel.java │ │ └── cost/ │ │ ├── UpgradeCost.java │ │ ├── UpgradeCostLoadException.java │ │ └── UpgradeCostLoader.java │ ├── world/ │ │ ├── Dimension.java │ │ ├── GameSound.java │ │ ├── WorldInfo.java │ │ └── algorithm/ │ │ ├── DelegateIslandCreationAlgorithm.java │ │ └── IslandCreationAlgorithm.java │ └── wrappers/ │ ├── BlockOffset.java │ ├── BlockPosition.java │ ├── SuperiorPlayer.java │ └── WorldPosition.java ├── Hooks/ │ ├── AdvancedSlimePaper/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── AdvancedSlimePaperHook.java │ ├── AdvancedSpawners/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_AdvancedSpawners.java │ ├── CMI/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ ├── afk/ │ │ │ └── AFKProvider_CMI.java │ │ └── vanish/ │ │ └── VanishProvider_CMI.java │ ├── CandcSilkSpawners/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_CandcSilkSpawners.java │ ├── ChangeSkin/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── ChangeSkinHook.java │ ├── CoreProtect/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── CoreProtectHook.java │ ├── CraftEngine/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── CraftEngineHook.java │ ├── EpicSpawners6/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_EpicSpawners6.java │ ├── EpicSpawners7/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_EpicSpawners7.java │ ├── EpicSpawners8/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_EpicSpawners8.java │ ├── EpicSpawners9/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_EpicSpawners9.java │ ├── Essentials/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ ├── afk/ │ │ │ └── AFKProvider_Essentials.java │ │ └── vanish/ │ │ └── VanishProvider_Essentials.java │ ├── FastAsyncWorldEdit/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── world/ │ │ └── schematic/ │ │ ├── impl/ │ │ │ └── WorldEditSchematic.java │ │ └── parser/ │ │ └── FAWESchematicParser.java │ ├── ItemsAdder/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── ItemsAdderHook.java │ ├── JetsMinions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── JetsMinionsHook.java │ ├── LuckPerms/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── permissions/ │ │ └── PermissionsProvider_LuckPerms.java │ ├── MVdWPlaceholderAPI/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── placeholders/ │ │ └── PlaceholdersProvider_MVdWPlaceholderAPI.java │ ├── MergedSpawner/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_MergedSpawner.java │ ├── MiniMessage/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── MiniMessageHook.java │ ├── Nexo/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── NexoHook.java │ ├── OpenJdkNashornEngine/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── core/ │ │ └── engine/ │ │ └── OpenJdkNashornEngine.java │ ├── Oraxen/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── OraxenHook.java │ ├── PaperMC/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ ├── async/ │ │ │ └── AsyncProvider_Paper.java │ │ ├── chunks/ │ │ │ └── ChunksProvider_Paper.java │ │ └── remapper/ │ │ └── PluginRemapperFilesLookupProvider.java │ ├── PlaceholderAPI/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── placeholders/ │ │ └── PlaceholdersProvider_PlaceholderAPI.java │ ├── Plan/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── PlanHook.java │ ├── ProtocolLib/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── ProtocolLibHook.java │ ├── PvpingSpawners/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_PvpingSpawners.java │ ├── RoseStacker/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ ├── entities/ │ │ │ └── EntitiesProvider_RoseStacker.java │ │ ├── spawners/ │ │ │ └── SpawnersProvider_RoseStacker.java │ │ └── stackedblocks/ │ │ └── StackedBlocksProvider_RoseStacker.java │ ├── SkinsRestorer/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── SkinsRestorerHook.java │ ├── SkinsRestorer14/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── SkinsRestorer14Hook.java │ ├── SkinsRestorer15/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── SkinsRestorer15Hook.java │ ├── SlimeWorldManager/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── SlimeWorldManagerHook.java │ ├── Slimefun/ │ │ ├── ProtectionModule_Dev999/ │ │ │ ├── build.gradle │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bgsoftware/ │ │ │ └── superiorskyblock/ │ │ │ └── external/ │ │ │ └── slimefun/ │ │ │ └── ProtectionModule_Dev999.java │ │ ├── ProtectionModule_RC13/ │ │ │ ├── build.gradle │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bgsoftware/ │ │ │ └── superiorskyblock/ │ │ │ └── external/ │ │ │ └── slimefun/ │ │ │ └── ProtectionModule_RC13.java │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── SlimefunHook.java │ ├── SmoothTimber/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── SmoothTimberHook.java │ ├── SuperVanish/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── vanish/ │ │ └── VanishProvider_SuperVanish.java │ ├── TimbruSilkSpawners/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ ├── TimbruSilkSpawnersHook.java │ │ └── spawners/ │ │ └── SpawnersProvider_TimbruSilkSpawners.java │ ├── UltimateStacker/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_UltimateStacker.java │ ├── UltimateStacker3/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_UltimateStacker3.java │ ├── UltimateStacker4/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── spawners/ │ │ └── SpawnersProvider_UltimateStacker4.java │ ├── VanishNoPacket/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── vanish/ │ │ └── VanishProvider_VanishNoPacket.java │ ├── Vault/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── external/ │ │ └── economy/ │ │ └── EconomyProvider_Vault.java │ ├── WildStacker/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ ├── external/ │ │ │ ├── WildStackerSnapshotsContainer.java │ │ │ ├── spawners/ │ │ │ │ └── SpawnersProvider_WildStacker.java │ │ │ └── stackedblocks/ │ │ │ └── StackedBlocksProvider_WildStacker.java │ │ └── module/ │ │ └── upgrades/ │ │ └── listeners/ │ │ └── WildStackerListener.java │ └── build.gradle ├── LICENSE ├── Missions/ │ ├── BlocksMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ ├── BlocksMissions.java │ │ └── blocks/ │ │ ├── BlocksTracker.java │ │ ├── BlocksTrackingComponent.java │ │ ├── ChunkBitSet.java │ │ └── TrackedBlocksData.java │ ├── BrewingMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ └── BrewingMissions.java │ ├── CraftingMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ └── CraftingMissions.java │ ├── EnchantingMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ └── EnchantingMissions.java │ ├── FarmingMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ ├── FarmingMissions.java │ │ └── farming/ │ │ ├── PlantType.java │ │ ├── PlantsTracker.java │ │ ├── PlantsTrackingComponent.java │ │ └── TrackedPlantsData.java │ ├── FishingMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ └── FishingMissions.java │ ├── IslandMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ ├── IslandMissions.java │ │ └── island/ │ │ ├── DynamicRegisteredListener.java │ │ ├── EventsHelper.java │ │ └── timings/ │ │ ├── DummyTimings.java │ │ ├── ITimings.java │ │ ├── LegacyTimingsWrapper.java │ │ └── TimingsWrapper.java │ ├── ItemsMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ └── ItemsMissions.java │ ├── KillsMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ └── KillsMissions.java │ ├── StatisticsMissions/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── missions/ │ │ └── StatisticsMissions.java │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── bgsoftware/ │ └── superiorskyblock/ │ └── missions/ │ └── common/ │ ├── BuiltinMission.java │ ├── Placeholders.java │ ├── requirements/ │ │ ├── CustomRequirements.java │ │ ├── IRequirements.java │ │ ├── KeyRequirements.java │ │ ├── Requirements.java │ │ └── RequirementsAbstract.java │ └── tracker/ │ ├── DataTracker.java │ ├── KeyDataTracker.java │ └── RawDataTracker.java ├── NMS/ │ ├── Paper/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── algorithms/ │ │ └── PaperGlowEnchantment.java │ ├── Paper-1_20_3/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_20_3/ │ │ └── algorithms/ │ │ └── PaperGlowEnchantment.java │ ├── Spigot/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── algorithms/ │ │ ├── NMSCachedBlock.java │ │ └── SpigotGlowEnchantment.java │ ├── Spigot-1_20_3/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_20_3/ │ │ └── algorithms/ │ │ ├── NMSCachedBlock.java │ │ └── SpigotGlowEnchantment.java │ ├── build.gradle │ ├── src/ │ │ └── main/ │ │ └── templates/ │ │ ├── AbstractNMSAlgorithms.java.template │ │ ├── AbstractNMSChunks.java.template │ │ ├── AbstractNMSEntities.java.template │ │ ├── AbstractNMSTags.java.template │ │ ├── AbstractNMSWorld.java.template │ │ ├── NMSDragonFightImpl.java.template │ │ ├── NMSHologramsImpl.java.template │ │ ├── NMSPlayersImpl.java.template │ │ ├── NMSUtils.java.template │ │ ├── crops/ │ │ │ ├── CropsBlockEntity.java.template │ │ │ ├── CropsTickingBlockEntity.java.template │ │ │ └── CropsTickingMethod.java.template │ │ ├── dragon/ │ │ │ ├── AbstractIslandEntityEnderDragon.java.template │ │ │ ├── DragonUtils.java.template │ │ │ ├── EndWorldEndDragonFightHandler.java.template │ │ │ ├── IslandEndDragonFight.java.template │ │ │ └── SpikesCache.java.template │ │ ├── generator/ │ │ │ └── IslandsGeneratorImpl.java.template │ │ ├── hologram/ │ │ │ └── AbstractEntityHologram.java.template │ │ ├── menu/ │ │ │ ├── MenuBrewingStandBlockEntity.java.template │ │ │ ├── MenuDispenserBlockEntity.java.template │ │ │ ├── MenuFurnaceBlockEntity.java.template │ │ │ └── MenuHopperBlockEntity.java.template │ │ ├── player/ │ │ │ └── OfflinePlayerDataImpl.java.template │ │ ├── spawners/ │ │ │ └── TickingSpawnerBlockEntityNotifier.java.template │ │ ├── utils/ │ │ │ ├── SetBlockContext.java.template │ │ │ └── TickingBlockList.java.template │ │ └── world/ │ │ ├── BlockEntityCache.java.template │ │ ├── ChunkReaderImpl.java.template │ │ ├── KeyBlocksCache.java.template │ │ ├── PropertiesMapper.java.template │ │ ├── WorldEditSessionDataImpl.java.template │ │ └── WorldEditSessionImpl.java.template │ ├── v1_12_R1/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_12_R1/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSCachedBlock.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSDragonFightImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSHologramsImpl.java │ │ ├── NMSPlayersImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSUtils.java │ │ ├── NMSWorldImpl.java │ │ ├── chunks/ │ │ │ ├── CropsTickingTileEntity.java │ │ │ └── EmptyCounterChunkSection.java │ │ ├── dragon/ │ │ │ ├── DragonUtils.java │ │ │ ├── EndWorldEnderDragonBattleHandler.java │ │ │ ├── IslandEnderDragonBattle.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── generator/ │ │ │ └── IslandsGeneratorImpl.java │ │ ├── player/ │ │ │ └── OfflinePlayerDataImpl.java │ │ ├── spawners/ │ │ │ └── MobSpawnerAbstractNotifier.java │ │ └── world/ │ │ ├── BlockEntityCache.java │ │ ├── ChunkReaderImpl.java │ │ ├── KeyBlocksCache.java │ │ ├── WorldEditSessionDataImpl.java │ │ └── WorldEditSessionImpl.java │ ├── v1_16_R3/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_16_R3/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSDragonFightImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSHologramsImpl.java │ │ ├── NMSPlayersImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSUtils.java │ │ ├── NMSWorldImpl.java │ │ ├── crops/ │ │ │ ├── CropsTickingMethod.java │ │ │ └── CropsTickingTileEntity.java │ │ ├── dragon/ │ │ │ ├── DragonUtils.java │ │ │ ├── EndWorldEnderDragonBattleHandler.java │ │ │ ├── IslandEnderDragonBattle.java │ │ │ ├── IslandEntityEnderDragon.java │ │ │ └── SpikesCache.java │ │ ├── generator/ │ │ │ └── IslandsGeneratorImpl.java │ │ ├── menu/ │ │ │ ├── MenuTileEntityBrewing.java │ │ │ ├── MenuTileEntityDispenser.java │ │ │ ├── MenuTileEntityFurnace.java │ │ │ └── MenuTileEntityHopper.java │ │ ├── player/ │ │ │ └── OfflinePlayerDataImpl.java │ │ ├── spawners/ │ │ │ └── TileEntityMobSpawnerNotifier.java │ │ └── world/ │ │ ├── BlockEntityCache.java │ │ ├── BlockStatesMapper.java │ │ ├── BlockTickListServerTracker.java │ │ ├── ChunkReaderImpl.java │ │ ├── KeyBlocksCache.java │ │ ├── WorldEditSessionDataImpl.java │ │ └── WorldEditSessionImpl.java │ ├── v1_17/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_17/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandSculkSensorBlockEntity.java │ │ └── world/ │ │ ├── BlockServerTickListTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_18/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_18/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandSculkSensorBlockEntity.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_19/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_19/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandSculkSensorBlockEntity.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_20_3/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_20_3/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_20_4/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_20_4/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_21/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_21/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── trial/ │ │ │ └── IslandPlayerDetector.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_21_10/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_21_10/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── trial/ │ │ │ └── IslandPlayerDetector.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_21_3/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_21_3/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── trial/ │ │ │ └── IslandPlayerDetector.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_21_4/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_21_4/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── trial/ │ │ │ └── IslandPlayerDetector.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_21_5/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_21_5/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── trial/ │ │ │ └── IslandPlayerDetector.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_21_7/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_21_7/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── trial/ │ │ │ └── IslandPlayerDetector.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_21_9/ │ │ ├── build.gradle │ │ ├── properties │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_21_9/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSWorldImpl.java │ │ ├── dragon/ │ │ │ ├── EndDragonFightWrapper.java │ │ │ └── IslandEntityEnderDragon.java │ │ ├── hologram/ │ │ │ └── EntityHologram.java │ │ ├── trial/ │ │ │ └── IslandPlayerDetector.java │ │ ├── utils/ │ │ │ └── NMSUtilsVersioned.java │ │ ├── vibration/ │ │ │ └── IslandVibrationUser.java │ │ └── world/ │ │ ├── BlockLevelTicksTracker.java │ │ ├── CollectingNeighborUpdaterTracker.java │ │ └── PropertiesMapperVersioned.java │ ├── v1_8_R3/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── bgsoftware/ │ │ └── superiorskyblock/ │ │ └── nms/ │ │ └── v1_8_R3/ │ │ ├── NMSAlgorithmsImpl.java │ │ ├── NMSCachedBlock.java │ │ ├── NMSChunksImpl.java │ │ ├── NMSEntitiesImpl.java │ │ ├── NMSHologramsImpl.java │ │ ├── NMSPlayersImpl.java │ │ ├── NMSTagsImpl.java │ │ ├── NMSUtils.java │ │ ├── NMSWorldImpl.java │ │ ├── chunks/ │ │ │ └── CropsTickingTileEntity.java │ │ ├── generator/ │ │ │ └── IslandsGeneratorImpl.java │ │ ├── player/ │ │ │ └── OfflinePlayerDataImpl.java │ │ ├── spawners/ │ │ │ └── MobSpawnerAbstractNotifier.java │ │ └── world/ │ │ ├── BlockEntityCache.java │ │ ├── ChunkReaderImpl.java │ │ ├── KeyBlocksCache.java │ │ ├── WorldEditSessionDataImpl.java │ │ └── WorldEditSessionImpl.java │ └── v26_1/ │ ├── build.gradle │ ├── properties │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── bgsoftware/ │ └── superiorskyblock/ │ └── nms/ │ └── v26_1/ │ ├── NMSAlgorithmsImpl.java │ ├── NMSChunksImpl.java │ ├── NMSEntitiesImpl.java │ ├── NMSTagsImpl.java │ ├── NMSWorldImpl.java │ ├── dragon/ │ │ ├── EndDragonFightWrapper.java │ │ └── IslandEntityEnderDragon.java │ ├── hologram/ │ │ └── EntityHologram.java │ ├── trial/ │ │ └── IslandPlayerDetector.java │ ├── utils/ │ │ └── NMSUtilsVersioned.java │ ├── vibration/ │ │ └── IslandVibrationUser.java │ └── world/ │ ├── BlockLevelTicksTracker.java │ ├── CollectingNeighborUpdaterTracker.java │ └── PropertiesMapperVersioned.java ├── README.md ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src/ └── main/ ├── java/ │ └── com/ │ └── bgsoftware/ │ └── superiorskyblock/ │ ├── SuperiorSkyblockPlugin.java │ ├── commands/ │ │ ├── CommandTabCompletes.java │ │ ├── CommandsHelper.java │ │ ├── CommandsManagerImpl.java │ │ ├── CommandsMap.java │ │ ├── IAdminIslandCommand.java │ │ ├── IAdminPlayerCommand.java │ │ ├── IPermissibleCommand.java │ │ ├── ISuperiorCommand.java │ │ ├── admin/ │ │ │ ├── AdminCommandsMap.java │ │ │ ├── CmdAdminAdd.java │ │ │ ├── CmdAdminAddBonus.java │ │ │ ├── CmdAdminAddCoopLimit.java │ │ │ ├── CmdAdminAddDisbands.java │ │ │ ├── CmdAdminAddSize.java │ │ │ ├── CmdAdminAddTeamLimit.java │ │ │ ├── CmdAdminAddWarpsLimit.java │ │ │ ├── CmdAdminBypass.java │ │ │ ├── CmdAdminChest.java │ │ │ ├── CmdAdminClose.java │ │ │ ├── CmdAdminCmdAll.java │ │ │ ├── CmdAdminCount.java │ │ │ ├── CmdAdminData.java │ │ │ ├── CmdAdminDebug.java │ │ │ ├── CmdAdminDelWarp.java │ │ │ ├── CmdAdminDemote.java │ │ │ ├── CmdAdminDisband.java │ │ │ ├── CmdAdminFly.java │ │ │ ├── CmdAdminIgnore.java │ │ │ ├── CmdAdminJoin.java │ │ │ ├── CmdAdminKick.java │ │ │ ├── CmdAdminModules.java │ │ │ ├── CmdAdminMsg.java │ │ │ ├── CmdAdminMsgAll.java │ │ │ ├── CmdAdminName.java │ │ │ ├── CmdAdminOpen.java │ │ │ ├── CmdAdminOpenMenu.java │ │ │ ├── CmdAdminPromote.java │ │ │ ├── CmdAdminPurge.java │ │ │ ├── CmdAdminRecalc.java │ │ │ ├── CmdAdminReload.java │ │ │ ├── CmdAdminRemoveRatings.java │ │ │ ├── CmdAdminResetPermissions.java │ │ │ ├── CmdAdminResetSettings.java │ │ │ ├── CmdAdminResetWorld.java │ │ │ ├── CmdAdminSchematic.java │ │ │ ├── CmdAdminSetBiome.java │ │ │ ├── CmdAdminSetBlockAmount.java │ │ │ ├── CmdAdminSetBonus.java │ │ │ ├── CmdAdminSetChestRow.java │ │ │ ├── CmdAdminSetCoopLimit.java │ │ │ ├── CmdAdminSetDisbands.java │ │ │ ├── CmdAdminSetIslandPreview.java │ │ │ ├── CmdAdminSetLeader.java │ │ │ ├── CmdAdminSetPermission.java │ │ │ ├── CmdAdminSetRate.java │ │ │ ├── CmdAdminSetRoleLimit.java │ │ │ ├── CmdAdminSetSettings.java │ │ │ ├── CmdAdminSetSize.java │ │ │ ├── CmdAdminSetSpawn.java │ │ │ ├── CmdAdminSetTeamLimit.java │ │ │ ├── CmdAdminSetWarpsLimit.java │ │ │ ├── CmdAdminSettings.java │ │ │ ├── CmdAdminShow.java │ │ │ ├── CmdAdminSpawn.java │ │ │ ├── CmdAdminSpy.java │ │ │ ├── CmdAdminStats.java │ │ │ ├── CmdAdminSyncBonus.java │ │ │ ├── CmdAdminTeleport.java │ │ │ ├── CmdAdminTitle.java │ │ │ ├── CmdAdminTitleAll.java │ │ │ ├── CmdAdminUnignore.java │ │ │ └── CmdAdminUnlockWorld.java │ │ ├── arguments/ │ │ │ ├── Argument.java │ │ │ ├── CommandArguments.java │ │ │ ├── IslandArgument.java │ │ │ ├── IslandsListArgument.java │ │ │ └── NumberArgument.java │ │ └── player/ │ │ ├── CmdAccept.java │ │ ├── CmdAdmin.java │ │ ├── CmdBan.java │ │ ├── CmdBans.java │ │ ├── CmdBiome.java │ │ ├── CmdBorder.java │ │ ├── CmdChest.java │ │ ├── CmdClose.java │ │ ├── CmdCoop.java │ │ ├── CmdCoops.java │ │ ├── CmdCounts.java │ │ ├── CmdCreate.java │ │ ├── CmdDelWarp.java │ │ ├── CmdDemote.java │ │ ├── CmdDisband.java │ │ ├── CmdExpel.java │ │ ├── CmdFly.java │ │ ├── CmdHelp.java │ │ ├── CmdInvite.java │ │ ├── CmdKick.java │ │ ├── CmdLang.java │ │ ├── CmdLeave.java │ │ ├── CmdMembers.java │ │ ├── CmdName.java │ │ ├── CmdOpen.java │ │ ├── CmdPanel.java │ │ ├── CmdPardon.java │ │ ├── CmdPermissions.java │ │ ├── CmdPromote.java │ │ ├── CmdRate.java │ │ ├── CmdRatings.java │ │ ├── CmdRecalc.java │ │ ├── CmdSetDiscord.java │ │ ├── CmdSetPaypal.java │ │ ├── CmdSetRole.java │ │ ├── CmdSetTeleport.java │ │ ├── CmdSetWarp.java │ │ ├── CmdSettings.java │ │ ├── CmdShow.java │ │ ├── CmdTeam.java │ │ ├── CmdTeamChat.java │ │ ├── CmdTeleport.java │ │ ├── CmdToggle.java │ │ ├── CmdTop.java │ │ ├── CmdTransfer.java │ │ ├── CmdUncoop.java │ │ ├── CmdValue.java │ │ ├── CmdValues.java │ │ ├── CmdVisit.java │ │ ├── CmdVisitors.java │ │ ├── CmdWarp.java │ │ ├── CmdWarps.java │ │ └── PlayerCommandsMap.java │ ├── config/ │ │ ├── SettingsContainer.java │ │ ├── SettingsContainerHolder.java │ │ ├── SettingsManagerImpl.java │ │ └── section/ │ │ ├── AFKIntegrationsSection.java │ │ ├── DatabaseSection.java │ │ ├── DefaultContainersSection.java │ │ ├── DefaultValuesSection.java │ │ ├── EntityCategoriesSection.java │ │ ├── GlobalSection.java │ │ ├── InteractablesSection.java │ │ ├── IslandChestsSection.java │ │ ├── IslandNamesSection.java │ │ ├── IslandPreviewsSection.java │ │ ├── IslandRolesSection.java │ │ ├── SpawnSection.java │ │ ├── StackedBlocksSection.java │ │ ├── VisitorsSignSection.java │ │ ├── VoidTeleportSection.java │ │ └── WorldsSection.java │ ├── core/ │ │ ├── BaseCacheImpl.java │ │ ├── BigBitSet.java │ │ ├── ByteBigArray.java │ │ ├── CalculatedChunk.java │ │ ├── ChunkPosition.java │ │ ├── Counter.java │ │ ├── DirtyChunk.java │ │ ├── DynamicArray.java │ │ ├── Either.java │ │ ├── EnumHelper.java │ │ ├── GameSoundImpl.java │ │ ├── IslandArea.java │ │ ├── IslandPosition.java │ │ ├── IslandWorlds.java │ │ ├── IslandWorldsPlayersStrategy.java │ │ ├── JavaVersion.java │ │ ├── LazyReference.java │ │ ├── LazyWorldLocation.java │ │ ├── Manager.java │ │ ├── Materials.java │ │ ├── MutableChunkPosition.java │ │ ├── ObjectsPool.java │ │ ├── ObjectsPools.java │ │ ├── PlayerHand.java │ │ ├── PluginLoadingStage.java │ │ ├── PluginReloadReason.java │ │ ├── Precision.java │ │ ├── SBlockOffset.java │ │ ├── SBlockPosition.java │ │ ├── SWorldPosition.java │ │ ├── SequentialListBuilder.java │ │ ├── ServerVersion.java │ │ ├── Text.java │ │ ├── VarintArray.java │ │ ├── WorldInfoImpl.java │ │ ├── collections/ │ │ │ ├── ArrayMap.java │ │ │ ├── AutoRemovalCollection.java │ │ │ ├── AutoRemovalMap.java │ │ │ ├── Chunk2ObjectMap.java │ │ │ ├── CollectionsFactory.java │ │ │ ├── CompletableFutureList.java │ │ │ ├── EnumerateMap.java │ │ │ ├── EnumerateSet.java │ │ │ ├── IslandPosition2ObjectMap.java │ │ │ ├── Location2ObjectMap.java │ │ │ ├── creator/ │ │ │ │ ├── CollectionsCreator.java │ │ │ │ ├── FastUtilCollectionsCreator.java │ │ │ │ └── JavaCollectionsCreator.java │ │ │ └── view/ │ │ │ ├── Char2ObjectMapView.java │ │ │ ├── CharIterator.java │ │ │ ├── EmptyInt2IntMapView.java │ │ │ ├── EmptyIntIterator.java │ │ │ ├── Int2IntMapView.java │ │ │ ├── Int2ObjectMapView.java │ │ │ ├── IntIterator.java │ │ │ ├── Long2ObjectMapView.java │ │ │ └── LongIterator.java │ │ ├── config/ │ │ │ └── PvPWorldsCache.java │ │ ├── database/ │ │ │ ├── DBColumn.java │ │ │ ├── DataManager.java │ │ │ ├── DatabaseResult.java │ │ │ ├── bridge/ │ │ │ │ ├── EmptyDatabaseBridge.java │ │ │ │ ├── GridDatabaseBridge.java │ │ │ │ ├── IslandsDatabaseBridge.java │ │ │ │ ├── PlayersDatabaseBridge.java │ │ │ │ └── StackedBlocksDatabaseBridge.java │ │ │ ├── cache/ │ │ │ │ └── DatabaseCache.java │ │ │ ├── loader/ │ │ │ │ ├── DatabaseLoader.java │ │ │ │ ├── MachineStateDatabaseLoader.java │ │ │ │ ├── backup/ │ │ │ │ │ └── BackupDatabase.java │ │ │ │ └── sql/ │ │ │ │ ├── SQLDatabase.java │ │ │ │ ├── SQLDatabaseLoader.java │ │ │ │ └── upgrade/ │ │ │ │ ├── v0/ │ │ │ │ │ ├── DatabaseConverter.java │ │ │ │ │ ├── DatabaseUpgrade_V0.java │ │ │ │ │ ├── attributes/ │ │ │ │ │ │ ├── AttributesRegistry.java │ │ │ │ │ │ ├── BankTransactionsAttributes.java │ │ │ │ │ │ ├── GridAttributes.java │ │ │ │ │ │ ├── IslandAttributes.java │ │ │ │ │ │ ├── IslandChestAttributes.java │ │ │ │ │ │ ├── IslandWarpAttributes.java │ │ │ │ │ │ ├── PlayerAttributes.java │ │ │ │ │ │ ├── StackedBlockAttributes.java │ │ │ │ │ │ └── WarpCategoryAttributes.java │ │ │ │ │ └── deserializer/ │ │ │ │ │ ├── EmptyParameterGuardDeserializer.java │ │ │ │ │ ├── IDeserializer.java │ │ │ │ │ ├── JsonDeserializer.java │ │ │ │ │ ├── MultipleDeserializer.java │ │ │ │ │ └── RawDeserializer.java │ │ │ │ ├── v1/ │ │ │ │ │ └── DatabaseUpgrade_V1.java │ │ │ │ ├── v2/ │ │ │ │ │ └── DatabaseUpgrade_V2.java │ │ │ │ └── v3/ │ │ │ │ └── DatabaseUpgrade_V3.java │ │ │ ├── serialization/ │ │ │ │ ├── IslandsDeserializer.java │ │ │ │ ├── IslandsSerializer.java │ │ │ │ └── PlayersDeserializer.java │ │ │ └── sql/ │ │ │ ├── DBSession.java │ │ │ ├── ResultSetMapBridge.java │ │ │ └── SQLDatabaseBridge.java │ │ ├── engine/ │ │ │ ├── EnginesFactory.java │ │ │ ├── NashornEngine.java │ │ │ └── NashornEngineDownloader.java │ │ ├── errors/ │ │ │ └── ManagerLoadException.java │ │ ├── events/ │ │ │ ├── EventCallback.java │ │ │ ├── EventType.java │ │ │ ├── EventsDispatcher.java │ │ │ ├── IEvent.java │ │ │ ├── args/ │ │ │ │ ├── IEventArgs.java │ │ │ │ └── PluginEventArgs.java │ │ │ └── plugin/ │ │ │ ├── PluginEvent.java │ │ │ ├── PluginEventPriority.java │ │ │ ├── PluginEventType.java │ │ │ ├── PluginEventsDispatcher.java │ │ │ └── PluginEventsFactory.java │ │ ├── factory/ │ │ │ ├── DefaultBanksFactory.java │ │ │ ├── DefaultDatabaseBridgeFactory.java │ │ │ ├── DefaultIslandsFactory.java │ │ │ ├── DefaultPlayersFactory.java │ │ │ └── FactoriesManagerImpl.java │ │ ├── formatting/ │ │ │ ├── Formatters.java │ │ │ ├── IBiFormatter.java │ │ │ ├── IFormatter.java │ │ │ └── impl/ │ │ │ ├── BlockPositionFormatter.java │ │ │ ├── BooleanFormatter.java │ │ │ ├── BorderColorFormatter.java │ │ │ ├── CapitalizedFormatter.java │ │ │ ├── ChatFormatter.java │ │ │ ├── ColorFormatter.java │ │ │ ├── CommaFormatter.java │ │ │ ├── DateFormatter.java │ │ │ ├── FancyNumberFormatter.java │ │ │ ├── LocaleFormatter.java │ │ │ ├── LocationFormatter.java │ │ │ ├── NumberFormatter.java │ │ │ ├── RatingFormatter.java │ │ │ ├── StripColorFormatter.java │ │ │ └── TimeFormatter.java │ │ ├── io/ │ │ │ ├── ClassProcessor.java │ │ │ ├── FileClassLoader.java │ │ │ ├── Files.java │ │ │ ├── IOUtils.java │ │ │ ├── JarFiles.java │ │ │ ├── MenuParserImpl.java │ │ │ ├── Resources.java │ │ │ ├── ZipFiles.java │ │ │ └── loader/ │ │ │ ├── DefaultFilesLookupProvider.java │ │ │ ├── FilesLookup.java │ │ │ ├── FilesLookupFactory.java │ │ │ └── FilesLookupProvider.java │ │ ├── itemstack/ │ │ │ ├── ItemBuilder.java │ │ │ ├── ItemSkulls.java │ │ │ ├── MinecraftNamesMapper.java │ │ │ └── heads/ │ │ │ └── MinecraftHeadsClient.java │ │ ├── key/ │ │ │ ├── BaseKey.java │ │ │ ├── ConstantKeys.java │ │ │ ├── KeyIndicator.java │ │ │ ├── Keys.java │ │ │ ├── KeysManagerImpl.java │ │ │ ├── MaterialKeySource.java │ │ │ ├── map/ │ │ │ │ ├── AbstractKeyMap.java │ │ │ │ ├── CustomKeyMap.java │ │ │ │ ├── EntityTypeKeyMap.java │ │ │ │ ├── KeyMapStrategy.java │ │ │ │ ├── KeyMaps.java │ │ │ │ ├── LazyLoadedKeyMap.java │ │ │ │ └── MaterialKeyMap.java │ │ │ ├── set/ │ │ │ │ ├── AbstractKeySet.java │ │ │ │ ├── CustomKeySet.java │ │ │ │ ├── EntityTypeKeySet.java │ │ │ │ ├── KeySetStrategy.java │ │ │ │ ├── KeySets.java │ │ │ │ ├── LazyLoadedKeySet.java │ │ │ │ └── MaterialKeySet.java │ │ │ └── types/ │ │ │ ├── CustomKey.java │ │ │ ├── EntityTypeKey.java │ │ │ ├── LazyKey.java │ │ │ ├── MaterialKey.java │ │ │ └── SpawnerKey.java │ │ ├── logging/ │ │ │ ├── Debug.java │ │ │ ├── Log.java │ │ │ └── StackTrace.java │ │ ├── menu/ │ │ │ ├── AbstractMenu.java │ │ │ ├── AbstractPagedMenu.java │ │ │ ├── MenuActions.java │ │ │ ├── MenuCommandsImpl.java │ │ │ ├── MenuConfig.java │ │ │ ├── MenuIdentifiers.java │ │ │ ├── MenuParseResult.java │ │ │ ├── MenuPatternSlots.java │ │ │ ├── Menus.java │ │ │ ├── MenusManagerImpl.java │ │ │ ├── TemplateItem.java │ │ │ ├── button/ │ │ │ │ ├── AbstractMenuTemplateButton.java │ │ │ │ ├── AbstractMenuViewButton.java │ │ │ │ ├── AbstractPagedMenuButton.java │ │ │ │ ├── MenuTemplateButtonImpl.java │ │ │ │ ├── PagedMenuTemplateButtonImpl.java │ │ │ │ └── impl/ │ │ │ │ ├── BackButton.java │ │ │ │ ├── BanButton.java │ │ │ │ ├── BankBalanceButton.java │ │ │ │ ├── BankCustomDepositButton.java │ │ │ │ ├── BankCustomWithdrawButton.java │ │ │ │ ├── BankDepositButton.java │ │ │ │ ├── BankLogsPagedObjectButton.java │ │ │ │ ├── BankLogsSortButton.java │ │ │ │ ├── BankWithdrawButton.java │ │ │ │ ├── BannedPlayersPagedObjectButton.java │ │ │ │ ├── BiomeButton.java │ │ │ │ ├── BorderColorButton.java │ │ │ │ ├── BorderColorToggleButton.java │ │ │ │ ├── ChangeSortingTypeButton.java │ │ │ │ ├── ConfigEditorPagedObjectButton.java │ │ │ │ ├── ConfigEditorSaveButton.java │ │ │ │ ├── ControlPanelButton.java │ │ │ │ ├── CoopsPagedObjectButton.java │ │ │ │ ├── CountsPagedObjectButton.java │ │ │ │ ├── CurrentPageButton.java │ │ │ │ ├── DisbandButton.java │ │ │ │ ├── DummyButton.java │ │ │ │ ├── GlobalWarpsPagedObjectButton.java │ │ │ │ ├── IconDisplayButton.java │ │ │ │ ├── IconEditLoreButton.java │ │ │ │ ├── IconEditTypeButton.java │ │ │ │ ├── IconRenameButton.java │ │ │ │ ├── IslandChestPagedObjectButton.java │ │ │ │ ├── IslandCreationButton.java │ │ │ │ ├── IslandFlagPagedObjectButton.java │ │ │ │ ├── IslandPrivilegePagedObjectButton.java │ │ │ │ ├── KickButton.java │ │ │ │ ├── LanguageButton.java │ │ │ │ ├── LeaveButton.java │ │ │ │ ├── MemberManageButton.java │ │ │ │ ├── MemberRoleButton.java │ │ │ │ ├── MembersPagedObjectButton.java │ │ │ │ ├── MissionsPagedObjectButton.java │ │ │ │ ├── NextPageButton.java │ │ │ │ ├── OpenBankLogsButton.java │ │ │ │ ├── OpenMissionCategoryButton.java │ │ │ │ ├── OpenUniqueVisitorsButton.java │ │ │ │ ├── PreviousPageButton.java │ │ │ │ ├── RateIslandButton.java │ │ │ │ ├── RatingsPagedObjectButton.java │ │ │ │ ├── TopIslandsPagedObjectButton.java │ │ │ │ ├── TopIslandsSelfIslandButton.java │ │ │ │ ├── TransferButton.java │ │ │ │ ├── UniqueVisitorPagedObjectButton.java │ │ │ │ ├── UpgradeButton.java │ │ │ │ ├── ValuesButton.java │ │ │ │ ├── VisitorPagedObjectButton.java │ │ │ │ ├── WarpCategoryIconEditConfirmButton.java │ │ │ │ ├── WarpCategoryManageIconButton.java │ │ │ │ ├── WarpCategoryManageRenameButton.java │ │ │ │ ├── WarpCategoryManageWarpsButton.java │ │ │ │ ├── WarpCategoryPagedObjectButton.java │ │ │ │ ├── WarpIconEditConfirmButton.java │ │ │ │ ├── WarpManageIconButton.java │ │ │ │ ├── WarpManageLocationButton.java │ │ │ │ ├── WarpManagePrivateButton.java │ │ │ │ ├── WarpManageRenameButton.java │ │ │ │ └── WarpPagedObjectButton.java │ │ │ ├── converter/ │ │ │ │ └── MenuConverter.java │ │ │ ├── impl/ │ │ │ │ ├── MenuBankLogs.java │ │ │ │ ├── MenuBiomes.java │ │ │ │ ├── MenuBorderColor.java │ │ │ │ ├── MenuConfirmBan.java │ │ │ │ ├── MenuConfirmDisband.java │ │ │ │ ├── MenuConfirmKick.java │ │ │ │ ├── MenuConfirmLeave.java │ │ │ │ ├── MenuConfirmTransfer.java │ │ │ │ ├── MenuControlPanel.java │ │ │ │ ├── MenuCoops.java │ │ │ │ ├── MenuCounts.java │ │ │ │ ├── MenuGlobalWarps.java │ │ │ │ ├── MenuIslandBank.java │ │ │ │ ├── MenuIslandBannedPlayers.java │ │ │ │ ├── MenuIslandChest.java │ │ │ │ ├── MenuIslandCreation.java │ │ │ │ ├── MenuIslandFlags.java │ │ │ │ ├── MenuIslandMembers.java │ │ │ │ ├── MenuIslandPrivileges.java │ │ │ │ ├── MenuIslandRate.java │ │ │ │ ├── MenuIslandRatings.java │ │ │ │ ├── MenuIslandUniqueVisitors.java │ │ │ │ ├── MenuIslandUpgrades.java │ │ │ │ ├── MenuIslandValues.java │ │ │ │ ├── MenuIslandVisitors.java │ │ │ │ ├── MenuMemberManage.java │ │ │ │ ├── MenuMemberRole.java │ │ │ │ ├── MenuMissions.java │ │ │ │ ├── MenuMissionsCategory.java │ │ │ │ ├── MenuPlayerLanguage.java │ │ │ │ ├── MenuTopIslands.java │ │ │ │ ├── MenuWarpCategories.java │ │ │ │ ├── MenuWarpCategoryIconEdit.java │ │ │ │ ├── MenuWarpCategoryManage.java │ │ │ │ ├── MenuWarpIconEdit.java │ │ │ │ ├── MenuWarpManage.java │ │ │ │ ├── MenuWarps.java │ │ │ │ └── internal/ │ │ │ │ ├── MenuBlank.java │ │ │ │ ├── MenuConfigEditor.java │ │ │ │ ├── MenuCustom.java │ │ │ │ └── StackedBlocksDepositMenu.java │ │ │ ├── layout/ │ │ │ │ ├── AbstractMenuLayout.java │ │ │ │ ├── PagedMenuLayoutImpl.java │ │ │ │ ├── RegularMenuLayoutImpl.java │ │ │ │ └── order/ │ │ │ │ ├── CustomPagedLayoutOrder.java │ │ │ │ └── PagedLayoutOrder.java │ │ │ └── view/ │ │ │ ├── AbstractIconProviderMenu.java │ │ │ ├── AbstractMenuView.java │ │ │ ├── AbstractPagedMenuView.java │ │ │ ├── BaseMenuView.java │ │ │ ├── IIslandMenuView.java │ │ │ ├── IPlayerMenuView.java │ │ │ ├── MenuViewWrapper.java │ │ │ ├── args/ │ │ │ │ ├── EmptyViewArgs.java │ │ │ │ ├── IslandViewArgs.java │ │ │ │ └── PlayerViewArgs.java │ │ │ └── impl/ │ │ │ ├── IslandMenuView.java │ │ │ └── PlayerMenuView.java │ │ ├── messages/ │ │ │ ├── Message.java │ │ │ ├── MessageContent.java │ │ │ └── component/ │ │ │ ├── EmptyMessageComponent.java │ │ │ ├── MultipleComponents.java │ │ │ └── impl/ │ │ │ ├── ActionBarComponent.java │ │ │ ├── BossBarComponent.java │ │ │ ├── ComplexMessageComponent.java │ │ │ ├── RawMessageComponent.java │ │ │ ├── SoundComponent.java │ │ │ └── TitleComponent.java │ │ ├── mutable/ │ │ │ ├── MutableBoolean.java │ │ │ ├── MutableInt.java │ │ │ ├── MutableLong.java │ │ │ └── MutableObject.java │ │ ├── persistence/ │ │ │ ├── EmptyPersistentDataContainer.java │ │ │ ├── PersistenceDataTypeSerializer.java │ │ │ └── PersistentDataContainerImpl.java │ │ ├── profiler/ │ │ │ ├── ProfileType.java │ │ │ ├── Profiler.java │ │ │ └── ProfilerSession.java │ │ ├── schematic/ │ │ │ ├── SchematicBlock.java │ │ │ ├── SchematicBlockData.java │ │ │ ├── SchematicEntity.java │ │ │ └── SchematicEntityFilter.java │ │ ├── serialization/ │ │ │ ├── ISerializer.java │ │ │ ├── Serializers.java │ │ │ └── impl/ │ │ │ ├── BlockPositionSerializer.java │ │ │ ├── InventorySerializer.java │ │ │ ├── ItemStack2TagSerializer.java │ │ │ ├── ItemStackSerializer.java │ │ │ ├── LocationSerializer.java │ │ │ ├── OffsetSerializer.java │ │ │ ├── PersistentDataSerializer.java │ │ │ └── WorldPositionSerializer.java │ │ ├── stackedblocks/ │ │ │ ├── StackedBlock.java │ │ │ ├── StackedBlocksManagerImpl.java │ │ │ └── container/ │ │ │ ├── DefaultStackedBlocksContainer.java │ │ │ └── StackedBlocksContainer.java │ │ ├── stats/ │ │ │ ├── IStatsCollector.java │ │ │ ├── StatsClient.java │ │ │ ├── StatsIslandsCounter.java │ │ │ ├── StatsPlayersCounter.java │ │ │ ├── StatsProfilers.java │ │ │ └── StatsSchematicsSizes.java │ │ ├── task/ │ │ │ ├── CalcTask.java │ │ │ └── ShutdownTask.java │ │ ├── threads/ │ │ │ ├── BukkitExecutor.java │ │ │ ├── Synchronized.java │ │ │ └── SynchronizedTasks.java │ │ ├── value/ │ │ │ ├── DoubleValue.java │ │ │ ├── DoubleValueFixed.java │ │ │ ├── DoubleValueFixedSynced.java │ │ │ ├── DoubleValueSuppliedSynced.java │ │ │ ├── IntValue.java │ │ │ ├── IntValueFixed.java │ │ │ ├── IntValueFixedSynced.java │ │ │ ├── IntValueSuppliedSynced.java │ │ │ ├── Value.java │ │ │ ├── ValueFixed.java │ │ │ ├── ValueFixedSynced.java │ │ │ ├── ValueSuppliedSynced.java │ │ │ └── ValuesCache.java │ │ └── values/ │ │ ├── BlockValue.java │ │ ├── BlockValuesManagerImpl.java │ │ └── container/ │ │ └── BlockValuesContainer.java │ ├── external/ │ │ ├── ProvidersManagerImpl.java │ │ ├── async/ │ │ │ ├── AsyncProvider.java │ │ │ └── AsyncProvider_Default.java │ │ ├── blocks/ │ │ │ └── ICustomBlocksProvider.java │ │ ├── chunks/ │ │ │ └── ChunksProvider_Default.java │ │ ├── economy/ │ │ │ └── EconomyProvider_Default.java │ │ ├── menus/ │ │ │ └── MenusProvider_Default.java │ │ ├── permissions/ │ │ │ └── PermissionsProvider_Default.java │ │ ├── placeholders/ │ │ │ └── PlaceholdersProvider.java │ │ ├── prices/ │ │ │ ├── PricesProvider_Default.java │ │ │ └── PricesProvider_ShopsBridgeWrapper.java │ │ ├── spawners/ │ │ │ ├── SpawnersProviderItemMetaSpawnerType.java │ │ │ ├── SpawnersProvider_AutoDetect.java │ │ │ └── SpawnersProvider_Default.java │ │ ├── stackedblocks/ │ │ │ ├── StackedBlocksProvider_AutoDetect.java │ │ │ └── StackedBlocksProvider_Default.java │ │ ├── text/ │ │ │ └── ITextFormatter.java │ │ ├── vanish/ │ │ │ └── VanishProvider_Default.java │ │ └── worlds/ │ │ ├── DefaultWorldLoadListener.java │ │ └── WorldsProvider_Default.java │ ├── island/ │ │ ├── GridManagerImpl.java │ │ ├── IslandNames.java │ │ ├── IslandUtils.java │ │ ├── SIsland.java │ │ ├── SIslandChest.java │ │ ├── SpawnIsland.java │ │ ├── algorithm/ │ │ │ ├── DefaultIslandBlocksTrackerAlgorithm.java │ │ │ ├── DefaultIslandCalculationAlgorithm.java │ │ │ ├── DefaultIslandCreationAlgorithm.java │ │ │ ├── DefaultIslandEntitiesTrackerAlgorithm.java │ │ │ ├── SpawnIslandBlocksTrackerAlgorithm.java │ │ │ ├── SpawnIslandCalculationAlgorithm.java │ │ │ └── SpawnIslandEntitiesTrackerAlgorithm.java │ │ ├── bank/ │ │ │ ├── SBankTransaction.java │ │ │ ├── SIslandBank.java │ │ │ └── logs/ │ │ │ ├── CacheBankLogs.java │ │ │ ├── DatabaseBankLogs.java │ │ │ └── IBankLogs.java │ │ ├── builder/ │ │ │ ├── IslandBuilderImpl.java │ │ │ ├── WarpCategoryRecord.java │ │ │ └── WarpRecord.java │ │ ├── cache/ │ │ │ ├── IslandCacheImpl.java │ │ │ └── IslandCacheKeys.java │ │ ├── chunk/ │ │ │ └── DirtyChunksContainer.java │ │ ├── container/ │ │ │ ├── DefaultIslandsContainer.java │ │ │ └── grid/ │ │ │ ├── IslandsGrid.java │ │ │ ├── MultiWorldIslandsGrid.java │ │ │ └── SingleWorldIslandsGrid.java │ │ ├── flag/ │ │ │ └── IslandFlags.java │ │ ├── notifications/ │ │ │ └── IslandNotifications.java │ │ ├── preview/ │ │ │ ├── DefaultIslandPreviews.java │ │ │ ├── IslandPreviews.java │ │ │ └── SIslandPreview.java │ │ ├── privilege/ │ │ │ ├── IslandPrivileges.java │ │ │ ├── PlayerPrivilegeNode.java │ │ │ ├── PrivilegeNodeAbstract.java │ │ │ └── RolePrivilegeNode.java │ │ ├── purge/ │ │ │ ├── DefaultIslandsPurger.java │ │ │ └── IslandsPurger.java │ │ ├── role/ │ │ │ ├── RolesManagerImpl.java │ │ │ ├── SPlayerRole.java │ │ │ └── container/ │ │ │ ├── DefaultRolesContainer.java │ │ │ └── RolesContainer.java │ │ ├── signs/ │ │ │ └── IslandSigns.java │ │ ├── top/ │ │ │ ├── SortingComparators.java │ │ │ ├── SortingTypes.java │ │ │ └── metadata/ │ │ │ ├── IslandSortMetadata.java │ │ │ ├── IslandSortPlayerMetadata.java │ │ │ ├── IslandSortRatingMetadata.java │ │ │ └── IslandSortValueMetadata.java │ │ ├── upgrade/ │ │ │ ├── DefaultUpgrade.java │ │ │ ├── DefaultUpgradeLevel.java │ │ │ ├── IslandUpgradeConstants.java │ │ │ ├── SUpgrade.java │ │ │ ├── SUpgradeLevel.java │ │ │ ├── UpgradeRequirement.java │ │ │ ├── UpgradesManagerImpl.java │ │ │ ├── container/ │ │ │ │ ├── DefaultUpgradesContainer.java │ │ │ │ ├── IslandUpgrades.java │ │ │ │ └── UpgradesContainer.java │ │ │ ├── cost/ │ │ │ │ ├── EmptyUpgradeCost.java │ │ │ │ ├── PlaceholdersUpgradeCost.java │ │ │ │ ├── UpgradeCostAbstract.java │ │ │ │ └── VaultUpgradeCost.java │ │ │ └── loaders/ │ │ │ ├── PlaceholdersUpgradeCostLoader.java │ │ │ └── VaultUpgradeCostLoader.java │ │ └── warp/ │ │ ├── SIslandWarp.java │ │ ├── SWarpCategory.java │ │ ├── SignWarp.java │ │ └── WarpIcons.java │ ├── listener/ │ │ ├── AbstractGameEventListener.java │ │ ├── AdminPlayersListener.java │ │ ├── BlockChangesListener.java │ │ ├── BukkitEventsListener.java │ │ ├── BukkitListeners.java │ │ ├── ChunksListener.java │ │ ├── EntityTrackingListener.java │ │ ├── FeaturesListener.java │ │ ├── IslandFlagsListener.java │ │ ├── IslandOutsideListener.java │ │ ├── IslandPreviewListener.java │ │ ├── IslandWorldEventsListener.java │ │ ├── MenusListener.java │ │ ├── PlayersListener.java │ │ ├── PortalsListener.java │ │ ├── ProtectionListener.java │ │ ├── SignsListener.java │ │ ├── StackedBlocksListener.java │ │ └── WorldDestructionListener.java │ ├── mission/ │ │ ├── MissionData.java │ │ ├── MissionReference.java │ │ ├── MissionsManagerImpl.java │ │ ├── SMissionCategory.java │ │ └── container/ │ │ ├── DefaultMissionsContainer.java │ │ └── MissionsContainer.java │ ├── module/ │ │ ├── BuiltinModule.java │ │ ├── BuiltinModules.java │ │ ├── IModuleConfiguration.java │ │ ├── ModuleData.java │ │ ├── ModulesManagerImpl.java │ │ ├── bank/ │ │ │ ├── BankModule.java │ │ │ └── commands/ │ │ │ ├── CmdAdminAddBankLimit.java │ │ │ ├── CmdAdminDeposit.java │ │ │ ├── CmdAdminSetBankLimit.java │ │ │ ├── CmdAdminWithdraw.java │ │ │ ├── CmdBalance.java │ │ │ ├── CmdBank.java │ │ │ ├── CmdDeposit.java │ │ │ └── CmdWithdraw.java │ │ ├── container/ │ │ │ ├── DefaultModulesContainer.java │ │ │ └── ModulesContainer.java │ │ ├── generators/ │ │ │ ├── GeneratorsModule.java │ │ │ ├── commands/ │ │ │ │ ├── CmdAdminAddGenerator.java │ │ │ │ ├── CmdAdminClearGenerator.java │ │ │ │ └── CmdAdminSetGenerator.java │ │ │ └── listeners/ │ │ │ └── GeneratorsListener.java │ │ ├── logging/ │ │ │ └── ModuleLoggerFileHandler.java │ │ ├── missions/ │ │ │ ├── MissionsModule.java │ │ │ └── commands/ │ │ │ ├── CmdAdminMission.java │ │ │ ├── CmdMission.java │ │ │ └── CmdMissions.java │ │ └── upgrades/ │ │ ├── UpgradesModule.java │ │ ├── commands/ │ │ │ ├── CmdAdminAddBlockLimit.java │ │ │ ├── CmdAdminAddCropGrowth.java │ │ │ ├── CmdAdminAddEffect.java │ │ │ ├── CmdAdminAddEntityLimit.java │ │ │ ├── CmdAdminAddMobDrops.java │ │ │ ├── CmdAdminAddSpawnerRates.java │ │ │ ├── CmdAdminRankup.java │ │ │ ├── CmdAdminRemoveBlockLimit.java │ │ │ ├── CmdAdminRemoveEntityLimit.java │ │ │ ├── CmdAdminSetBlockLimit.java │ │ │ ├── CmdAdminSetCropGrowth.java │ │ │ ├── CmdAdminSetEffect.java │ │ │ ├── CmdAdminSetEntityLimit.java │ │ │ ├── CmdAdminSetMobDrops.java │ │ │ ├── CmdAdminSetSpawnerRates.java │ │ │ ├── CmdAdminSetUpgrade.java │ │ │ ├── CmdAdminSyncUpgrades.java │ │ │ ├── CmdRankup.java │ │ │ └── CmdUpgrade.java │ │ └── type/ │ │ ├── IUpgradeType.java │ │ ├── UpgradeTypeBlockLimits.java │ │ ├── UpgradeTypeCropGrowth.java │ │ ├── UpgradeTypeEntityLimits.java │ │ ├── UpgradeTypeIslandEffects.java │ │ ├── UpgradeTypeMobDrops.java │ │ └── UpgradeTypeSpawnerRates.java │ ├── nms/ │ │ ├── ICachedBlock.java │ │ ├── NMSAlgorithms.java │ │ ├── NMSChunks.java │ │ ├── NMSDragonFight.java │ │ ├── NMSDragonFightChooser.java │ │ ├── NMSDragonFightImpl.java │ │ ├── NMSEntities.java │ │ ├── NMSHolograms.java │ │ ├── NMSPlayers.java │ │ ├── NMSTags.java │ │ ├── NMSWorld.java │ │ ├── bridge/ │ │ │ └── PistonPushReaction.java │ │ ├── player/ │ │ │ └── OfflinePlayerData.java │ │ └── world/ │ │ ├── ChunkReader.java │ │ └── WorldEditSession.java │ ├── platform/ │ │ ├── IPlatform.java │ │ └── event/ │ │ ├── GameEvent.java │ │ ├── GameEventCallback.java │ │ ├── GameEventFlags.java │ │ ├── GameEventPriority.java │ │ ├── GameEventType.java │ │ ├── GameEventsDispatcher.java │ │ └── args/ │ │ ├── GameEventArgs.java │ │ └── IEventArgs.java │ ├── player/ │ │ ├── PlayerLocales.java │ │ ├── PlayersManagerImpl.java │ │ ├── SSuperiorPlayer.java │ │ ├── SuperiorNPCPlayer.java │ │ ├── algorithm/ │ │ │ └── DefaultPlayerTeleportAlgorithm.java │ │ ├── builder/ │ │ │ └── SuperiorPlayerBuilderImpl.java │ │ ├── cache/ │ │ │ └── PlayerCacheImpl.java │ │ ├── chat/ │ │ │ └── PlayerChat.java │ │ ├── container/ │ │ │ └── DefaultPlayersContainer.java │ │ ├── inventory/ │ │ │ └── ClearActions.java │ │ ├── permissions/ │ │ │ └── PlayerPermissionsStore.java │ │ └── respawn/ │ │ └── RespawnActions.java │ ├── service/ │ │ ├── IService.java │ │ ├── ServicesHandler.java │ │ ├── bossbar/ │ │ │ ├── BossBarTask.java │ │ │ ├── BossBarsServiceImpl.java │ │ │ └── EmptyBossBar.java │ │ ├── dragon/ │ │ │ └── DragonBattleServiceImpl.java │ │ ├── hologram/ │ │ │ └── HologramsServiceImpl.java │ │ ├── message/ │ │ │ └── MessagesServiceImpl.java │ │ ├── placeholders/ │ │ │ └── PlaceholdersServiceImpl.java │ │ ├── portals/ │ │ │ └── PortalsManagerServiceImpl.java │ │ ├── region/ │ │ │ ├── ProtectionHelper.java │ │ │ └── RegionManagerServiceImpl.java │ │ ├── stackedblocks/ │ │ │ ├── StackedBlocksInteractionServiceImpl.java │ │ │ └── StackedBlocksServiceHelper.java │ │ └── world/ │ │ └── WorldRecordServiceImpl.java │ ├── tag/ │ │ ├── BigDecimalTag.java │ │ ├── ByteArrayTag.java │ │ ├── ByteTag.java │ │ ├── CompoundTag.java │ │ ├── DoubleTag.java │ │ ├── EndTag.java │ │ ├── FloatTag.java │ │ ├── IntArrayTag.java │ │ ├── IntTag.java │ │ ├── ListTag.java │ │ ├── LongTag.java │ │ ├── NBTTags.java │ │ ├── NBTUtils.java │ │ ├── NMSTagConverter.java │ │ ├── NumberTag.java │ │ ├── PersistentDataTag.java │ │ ├── PersistentDataTagSerialized.java │ │ ├── ShortTag.java │ │ ├── StringTag.java │ │ ├── Tag.java │ │ └── UUIDTag.java │ └── world/ │ ├── BukkitEntities.java │ ├── BukkitItems.java │ ├── Dimensions.java │ ├── EntityTeleports.java │ ├── GeneratorType.java │ ├── SignType.java │ ├── WorldBlocks.java │ ├── WorldGenerator.java │ ├── WorldReader.java │ ├── chunk/ │ │ ├── ChunkLoadReason.java │ │ └── ChunksProvider.java │ ├── entity/ │ │ ├── BuiltinEntityCategory.java │ │ └── EntityCategoryImpl.java │ ├── generator/ │ │ └── IslandsGenerator.java │ └── schematic/ │ ├── BaseSchematic.java │ ├── SchematicBuilder.java │ ├── SchematicsManagerImpl.java │ ├── container/ │ │ ├── DefaultSchematicsContainer.java │ │ └── SchematicsContainer.java │ ├── impl/ │ │ ├── CachedSuperiorSchematic.java │ │ ├── SuperiorSchematic.java │ │ └── SuperiorSchematicDeserializer.java │ ├── options/ │ │ ├── SchematicOptionsBuilderImpl.java │ │ └── SchematicOptionsImpl.java │ └── parser/ │ └── DefaultSchematicParser.java └── resources/ ├── block-values/ │ ├── levels.yml │ └── worth.yml ├── config.yml ├── entity-categories.yml ├── heads.yml ├── interactables.yml ├── lang/ │ ├── de-DE.yml │ ├── en-US.yml │ ├── es-ES.yml │ ├── fr-FR.yml │ ├── it-IT.yml │ ├── iw-IL.yml │ ├── pl-PL.yml │ ├── pt-BR.yml │ ├── ru-RU.yml │ ├── tr-TR.yml │ ├── vi-VN.yml │ └── zh-CN.yml ├── menus/ │ ├── bank-logs.yml │ ├── bank-logs1_12.yml │ ├── bank-logs1_13.yml │ ├── banned-players.yml │ ├── banned-players1_12.yml │ ├── banned-players1_13.yml │ ├── biomes.yml │ ├── biomes1_12.yml │ ├── biomes1_13.yml │ ├── border-color.yml │ ├── border-color1_12.yml │ ├── border-color1_13.yml │ ├── confirm-ban.yml │ ├── confirm-ban1_12.yml │ ├── confirm-ban1_13.yml │ ├── confirm-disband.yml │ ├── confirm-disband1_12.yml │ ├── confirm-disband1_13.yml │ ├── confirm-kick.yml │ ├── confirm-kick1_12.yml │ ├── confirm-kick1_13.yml │ ├── confirm-leave.yml │ ├── confirm-leave1_12.yml │ ├── confirm-leave1_13.yml │ ├── confirm-transfer.yml │ ├── confirm-transfer1_12.yml │ ├── confirm-transfer1_13.yml │ ├── control-panel.yml │ ├── control-panel1_12.yml │ ├── control-panel1_13.yml │ ├── coops.yml │ ├── coops1_12.yml │ ├── coops1_13.yml │ ├── counts.yml │ ├── counts1_12.yml │ ├── counts1_13.yml │ ├── counts1_20.yml │ ├── global-warps.yml │ ├── global-warps1_12.yml │ ├── global-warps1_13.yml │ ├── island-bank.yml │ ├── island-bank1_12.yml │ ├── island-bank1_13.yml │ ├── island-chest.yml │ ├── island-chest1_12.yml │ ├── island-chest1_13.yml │ ├── island-creation.yml │ ├── island-creation1_12.yml │ ├── island-creation1_13.yml │ ├── island-rate.yml │ ├── island-rate1_12.yml │ ├── island-rate1_13.yml │ ├── island-ratings.yml │ ├── island-ratings1_13.yml │ ├── member-manage.yml │ ├── member-manage1_12.yml │ ├── member-manage1_13.yml │ ├── member-role.yml │ ├── member-role1_12.yml │ ├── member-role1_13.yml │ ├── members.yml │ ├── members1_12.yml │ ├── members1_13.yml │ ├── missions-category.yml │ ├── missions-category1_12.yml │ ├── missions-category1_13.yml │ ├── missions.yml │ ├── missions1_12.yml │ ├── missions1_13.yml │ ├── permissions.yml │ ├── permissions1_12.yml │ ├── permissions1_16.yml │ ├── permissions1_17.yml │ ├── permissions1_19.yml │ ├── permissions1_20.yml │ ├── permissions1_21.yml │ ├── player-language.yml │ ├── player-language1_12.yml │ ├── player-language1_13.yml │ ├── settings.yml │ ├── settings1_12.yml │ ├── settings1_13.yml │ ├── settings1_20.yml │ ├── top-islands.yml │ ├── top-islands1_12.yml │ ├── top-islands1_13.yml │ ├── unique-visitors.yml │ ├── unique-visitors1_12.yml │ ├── unique-visitors1_13.yml │ ├── upgrades.yml │ ├── upgrades1_12.yml │ ├── upgrades1_13.yml │ ├── upgrades1_20.yml │ ├── values.yml │ ├── values1_13.yml │ ├── values1_20.yml │ ├── visitors.yml │ ├── visitors1_12.yml │ ├── visitors1_13.yml │ ├── warp-categories.yml │ ├── warp-categories1_13.yml │ ├── warp-category-icon-edit.yml │ ├── warp-category-icon-edit1_12.yml │ ├── warp-category-manage.yml │ ├── warp-category-manage1_12.yml │ ├── warp-icon-edit.yml │ ├── warp-icon-edit1_12.yml │ ├── warp-manage.yml │ ├── warp-manage1_12.yml │ ├── warps.yml │ ├── warps1_12.yml │ └── warps1_13.yml ├── modules/ │ ├── bank/ │ │ └── config.yml │ ├── generators/ │ │ └── config.yml │ ├── missions/ │ │ ├── categories/ │ │ │ ├── explorer/ │ │ │ │ ├── explorer_1.yml │ │ │ │ └── explorer_2.yml │ │ │ ├── farmer/ │ │ │ │ ├── farmer_1.yml │ │ │ │ ├── farmer_11_12.yml │ │ │ │ ├── farmer_2.yml │ │ │ │ ├── farmer_21_12.yml │ │ │ │ ├── farmer_3.yml │ │ │ │ ├── farmer_31_12.yml │ │ │ │ ├── farmer_4.yml │ │ │ │ ├── farmer_41_12.yml │ │ │ │ ├── farmer_5.yml │ │ │ │ └── farmer_51_12.yml │ │ │ ├── fisherman/ │ │ │ │ ├── fisherman_1.yml │ │ │ │ ├── fisherman_11_13.yml │ │ │ │ ├── fisherman_2.yml │ │ │ │ ├── fisherman_21_13.yml │ │ │ │ ├── fisherman_3.yml │ │ │ │ └── fisherman_31_13.yml │ │ │ ├── miner/ │ │ │ │ ├── miner_1.yml │ │ │ │ ├── miner_2.yml │ │ │ │ ├── miner_3.yml │ │ │ │ ├── miner_4.yml │ │ │ │ └── miner_5.yml │ │ │ └── slayer/ │ │ │ ├── slayer_1.yml │ │ │ ├── slayer_2.yml │ │ │ ├── slayer_3.yml │ │ │ └── slayer_4.yml │ │ └── config.yml │ └── upgrades/ │ └── config.yml ├── plugin.yml ├── safe_blocks.yml └── schematics/ ├── desert.schematic ├── desert1_16.schematic ├── mycel.schematic ├── mycel1_16.schematic ├── normal.schematic ├── normal1_16.schematic ├── normal_nether.schematic ├── normal_nether1_16.schematic ├── normal_the_end.schematic ├── normal_the_end1_12.schematic └── normal_the_end1_16.schematic ================================================ FILE CONTENTS ================================================ ================================================ FILE: .claudeignore ================================================ gradle/ .git/ .github/ *.jar *.class ================================================ FILE: .gitattributes ================================================ # # https://help.github.com/articles/dealing-with-line-endings/ # # These are explicitly windows files and should use crlf *.bat text eol=crlf ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms custom: https://bg-software.com/patreon ================================================ FILE: .github/ISSUE_TEMPLATE/bug-report.yaml ================================================ name: Bug Report description: Report a Bug or an Issue in the plugin. labels: [ 'Bug Report', 'Pending' ] assignees: OmerBenGera body: - type: markdown attributes: value: | ## SuperiorSkyblock2 Issues Tracker 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/). Be sure to check for existing [Issues](https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues).
- id: minecraft type: textarea validations: required: true attributes: label: 'Minecraft''s Version' description: | The minecraft version your server run on. Use /version to find which version you use. Make sure you give the exact output of the command. placeholder: | [Insert minecraft version and server jar.] - id: plugin type: textarea validations: required: true attributes: label: 'Plugin''s Version' description: | The version of the plugin. Use /version SuperiorSkyblock2 and find which version you use. Make sure you give the exact output of the command. placeholder: | [Insert plugin version and if it is a dev build.] - id: description type: textarea validations: required: true attributes: label: 'Describe the bug' description: | A clear and concise description of what the bug is. placeholder: | [Insert what exactly the problem is.] - id: reproduction type: textarea validations: required: true attributes: label: 'To Reproduce' description: | Steps to reproduce the bug. placeholder: | [Insert what exactly happened and the steps to reproduce the issue.] - id: extra type: textarea attributes: label: 'Additional Information' description: | Additional information that can help understanding the issue. Config file, clips, etc are more than welcome. placeholder: | Drag and drop an image or video onto this field to upload it. Otherwise please use pastebin for configs. - type: markdown attributes: value: | ## Thank you for helping improve SuperiorSkyblock2! Please remember to check back for any questions being asked and reply back as soon as you can! ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Feature Requests url: https://github.com/OmerBenGera/SuperiorSkyblock2/discussions about: Create feature requests, any posted in issue tracker will be removed. ================================================ FILE: .github/workflows/gemini.yml ================================================ name: Gemini Issue Fixer on: issues: types: [opened, edited] issue_comment: types: [created] jobs: gemini-fix: if: contains(github.event.issue.labels.*.name, 'bug') || contains(github.event.comment.body, '@gemini') runs-on: ubuntu-latest permissions: contents: write pull-requests: write issues: write id-token: write steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.10' - name: Install Aider (The Agent Engine) run: | python -m pip install --upgrade pip pip install aider-chat - name: Run Gemini Fix env: GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git config --global user.name "Gemini AI" git config --global user.email "gemini-ai@github.com" BRANCH_NAME="bugfix/issue-${{ github.event.issue.number }}" git checkout -b "$BRANCH_NAME" aider --model gemini/gemini-3-flash-preview \ --yes \ --commit \ --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 }}" git push origin "$BRANCH_NAME" gh pr create \ --title "Fix: ${{ github.event.issue.title }}" \ --body "Automated fix for #${{ github.event.issue.number }} generated by Gemini." \ --base dev \ --head "$BRANCH_NAME" ================================================ FILE: .gitignore ================================================ # Ignore Gradle project-specific cache directory .gradle gradle.properties # Ignore Gradle build output directory build # Ignore intellij files .idea *.iml # Ignore output generated files target out ================================================ FILE: API/build.gradle ================================================ plugins { id 'maven-publish' } java { withSourcesJar() } group 'API' dependencies { compileOnly "org.spigotmc:v1_8_R1:latest" } publishing { publications { maven(MavenPublication) { groupId = 'com.bgsoftware' artifactId = 'SuperiorSkyblockAPI' version = parent.version from components.java } } repositories { String mavenUsername = System.getenv('mavenUsername'); String mavenPassword = System.getenv('mavenPassword'); if (mavenUsername != null && mavenPassword != null) { maven { url 'https://repo.bg-software.com/repository/api/' credentials { username mavenUsername password mavenPassword } } } } } task generateAPIDocs(type: Javadoc) { source = sourceSets.main.allJava } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblock.java ================================================ package com.bgsoftware.superiorskyblock.api; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.handlers.CommandsManager; import com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.handlers.KeysManager; import com.bgsoftware.superiorskyblock.api.handlers.MenusManager; import com.bgsoftware.superiorskyblock.api.handlers.MissionsManager; import com.bgsoftware.superiorskyblock.api.handlers.ModulesManager; import com.bgsoftware.superiorskyblock.api.handlers.PlayersManager; import com.bgsoftware.superiorskyblock.api.handlers.ProvidersManager; import com.bgsoftware.superiorskyblock.api.handlers.RolesManager; import com.bgsoftware.superiorskyblock.api.handlers.SchematicManager; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.api.handlers.UpgradesManager; import com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher; import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; import org.bukkit.plugin.Plugin; public interface SuperiorSkyblock extends Plugin { /** * Get the grid of the core. */ GridManager getGrid(); /** * Get the stacked-blocks manager of the core. */ StackedBlocksManager getStackedBlocks(); /** * Get the blocks manager of the core. */ BlockValuesManager getBlockValues(); /** * Get the schematics manager of the core. */ SchematicManager getSchematics(); /** * Get the players manager of the core. */ PlayersManager getPlayers(); /** * Get the roles manager of the core. */ RolesManager getRoles(); /** * Get the missions manager of the core. */ MissionsManager getMissions(); /** * Get the menus manager of the core. */ MenusManager getMenus(); /** * Get the keys manager of the core. */ KeysManager getKeys(); /** * Get the providers manager of the core. */ ProvidersManager getProviders(); /** * Get the upgrades manager of the core. */ UpgradesManager getUpgrades(); /** * Get the commands manager of the core. */ CommandsManager getCommands(); /** * Get the settings of the plugin. */ SettingsManager getSettings(); /** * Get the objects factory of the plugin. */ FactoriesManager getFactory(); /** * Get the modules manager of the plugin. */ ModulesManager getModules(); /** * Get the script engine of the plugin. */ IScriptEngine getScriptEngine(); /** * Set the script engine of the plugin. * * @param scriptEngine The script engine to set. * When null, the default java script engine will be set instead. */ void setScriptEngine(@Nullable IScriptEngine scriptEngine); /** * Get the events dispatcher of the plugin. * * @return The events dispatcher, or null if the default events dispatcher is used. */ @Nullable IEventsDispatcher getEventsDispatcher(); /** * Sets a custom events dispatcher for the plugin. * * @param eventsDispatcher The new events dispatcher to set. * When null, the default events dispatcher will be used instead. */ void setEventsDispatcher(@Nullable IEventsDispatcher eventsDispatcher); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java ================================================ package com.bgsoftware.superiorskyblock.api; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.handlers.CommandsManager; import com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.handlers.KeysManager; import com.bgsoftware.superiorskyblock.api.handlers.MenusManager; import com.bgsoftware.superiorskyblock.api.handlers.MissionsManager; import com.bgsoftware.superiorskyblock.api.handlers.ModulesManager; import com.bgsoftware.superiorskyblock.api.handlers.PlayersManager; import com.bgsoftware.superiorskyblock.api.handlers.ProvidersManager; import com.bgsoftware.superiorskyblock.api.handlers.RolesManager; import com.bgsoftware.superiorskyblock.api.handlers.SchematicManager; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.api.handlers.UpgradesManager; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.entity.Player; import java.math.BigDecimal; import java.util.UUID; public class SuperiorSkyblockAPI { private static SuperiorSkyblock plugin; /** * Private constructor to prevent people from creating an instance of this class. */ private SuperiorSkyblockAPI() { } /* * General Methods */ /** * Get the plugin instance. */ public static SuperiorSkyblock getSuperiorSkyblock() { return plugin; } /** * Set the plugin's instance for the API. * Do not use this method on your own, as it may cause an undefined behavior when using the API. * * @param plugin The instance of the plugin to set to the API. */ public static void setPluginInstance(SuperiorSkyblock plugin) { if (SuperiorSkyblockAPI.plugin != null) { throw new UnsupportedOperationException("You cannot initialize the plugin instance after it was initialized."); } SuperiorSkyblockAPI.plugin = plugin; } /** * Get the version of the API. * Everytime a change is made to the API, the version of it changes. */ public static int getAPIVersion() { return 16; } /* * Player Methods */ /** * Get the superior player object from a player instance. */ public static SuperiorPlayer getPlayer(Player player) { return plugin.getPlayers().getSuperiorPlayer(player.getUniqueId()); } /** * Get the superior player object by a player's name. */ @Nullable public static SuperiorPlayer getPlayer(String name) { return plugin.getPlayers().getSuperiorPlayer(name); } /** * Get the superior player object from a player's uuid. * * @param uuid player uuid * @return The superior player object. null if doesn't exist. */ public static SuperiorPlayer getPlayer(UUID uuid) { return plugin.getPlayers().getSuperiorPlayer(uuid); } /* * Island Methods */ /** * Create a new island. * * @param superiorPlayer owner of the island * @param schemName the schematic of the island to be pasted * @param bonus The default island bonus level * @param biome The default island biome * @param islandName The island name */ public static void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName) { plugin.getGrid().createIsland(superiorPlayer, schemName, bonus, biome, islandName); } /** * Create a new island. * * @param superiorPlayer The new owner for the island. * @param schemName The schematic that should be used. * @param bonus A starting worth for the island. * @param biome A starting biome for the island. * @param islandName The name of the new island. * @param offset Should the island have an offset for it's values? If disabled, the bonus will be given. */ public static void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName, boolean offset) { plugin.getGrid().createIsland(superiorPlayer, schemName, bonus, biome, islandName, offset); } /** * Create a new island. * * @param superiorPlayer The new owner for the island. * @param schemName The schematic that should be used. * @param bonusWorth A starting worth for the island. * @param bonusLevel A starting level for the island. * @param biome A starting biome for the island. * @param islandName The name of the new island. * @param offset Should the island have an offset for it's values? If disabled, the bonus will be given. */ public static void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonusWorth, BigDecimal bonusLevel, Biome biome, String islandName, boolean offset) { plugin.getGrid().createIsland(superiorPlayer, schemName, bonusWorth, bonusLevel, biome, islandName, offset); } /** * Delete an island */ public static void deleteIsland(Island island) { plugin.getGrid().deleteIsland(island); } /** * Get an island by it's name. */ @Nullable public static Island getIsland(String islandName) { return plugin.getGrid().getIsland(islandName); } /** * Get an island by it's uuid. */ @Nullable public static Island getIslandByUUID(UUID uuid) { return plugin.getGrid().getIslandByUUID(uuid); } /** * Get the spawn island. */ public static Island getSpawnIsland() { return plugin.getGrid().getSpawnIsland(); } /** * Get the world of an island by the world's dimension. */ @Nullable public static World getIslandsWorld(Island island, Dimension dimension) { return plugin.getGrid().getIslandsWorld(island, dimension); } /** * Get an island at a location. */ @Nullable public static Island getIslandAt(Location location) { return plugin.getGrid().getIslandAt(location); } /** * Calculate all island worths on the server */ public static void calcAllIslands() { plugin.getGrid().calcAllIslands(); } /* * Schematic Methods */ /** * Get a schematic object by its name */ @Nullable public static Schematic getSchematic(String name) { return plugin.getSchematics().getSchematic(name); } /* * Providers Methods */ /** * Set custom spawners provider for the plugin. * * @param spawnersProvider The spawner provider to set. */ public static void setSpawnersProvider(SpawnersProvider spawnersProvider) { plugin.getProviders().setSpawnersProvider(spawnersProvider); } /* * Commands Methods */ /** * Register a sub-command. * * @param superiorCommand The sub command to register. */ public static void registerCommand(SuperiorCommand superiorCommand) { plugin.getCommands().registerCommand(superiorCommand); } /* * Main Method */ /** * Get the grid of the core. */ public static GridManager getGrid() { return plugin.getGrid(); } /** * Get the stacked-blocks manager of the core. */ public static StackedBlocksManager getStackedBlocks() { return plugin.getStackedBlocks(); } /** * Get the blocks manager of the core. */ public static BlockValuesManager getBlockValues() { return plugin.getBlockValues(); } /** * Get the schematics manager of the core. */ public static SchematicManager getSchematics() { return plugin.getSchematics(); } /** * Get the players manager of the core. */ public static PlayersManager getPlayers() { return plugin.getPlayers(); } /** * Get the roles manager of the core. */ public static RolesManager getRoles() { return plugin.getRoles(); } /** * Get the missions manager of the core. */ public static MissionsManager getMissions() { return plugin.getMissions(); } /** * Get the menus manager of the core. */ public static MenusManager getMenus() { return plugin.getMenus(); } /** * Get the keys manager of the core. */ public static KeysManager getKeys() { return plugin.getKeys(); } /** * Get the providers manager of the core. */ public static ProvidersManager getProviders() { return plugin.getProviders(); } /** * Get the upgrades manager of the core. */ public static UpgradesManager getUpgrades() { return plugin.getUpgrades(); } /** * Get the commands manager of the core. */ public static CommandsManager getCommands() { return plugin.getCommands(); } /** * Get the settings of the plugin. */ public static SettingsManager getSettings() { return plugin.getSettings(); } /** * Get the objects factory of the plugin. */ public static FactoriesManager getFactory() { return plugin.getFactory(); } /** * Get the modules manager of the plugin. */ public static ModulesManager getModules() { return plugin.getModules(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/commands/SuperiorCommand.java ================================================ package com.bgsoftware.superiorskyblock.api.commands; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import org.bukkit.command.CommandSender; import java.util.List; import java.util.Locale; public interface SuperiorCommand { /** * Get the aliases of the sub command. */ List getAliases(); /** * Get the required permission to use the sub command. * If no permission is required, can be empty. */ String getPermission(); /** * Get the usage of the sub command. * * @param locale The locale of the player. */ String getUsage(Locale locale); /** * Get the description of the sub command. * * @param locale The locale of the player. */ String getDescription(Locale locale); /** * Get the minimum arguments required for the command. * For example, the command /is example PLAYER_NAME has 2 arguments. */ int getMinArgs(); /** * Get the maximum arguments required for the command. * For example, the command /is example PLAYER_NAME has 2 arguments. */ int getMaxArgs(); /** * Can the command be executed from console? * If true, sender cannot be casted directly into a player. Otherwise, it can be. */ boolean canBeExecutedByConsole(); /** * Should the command be displayed in /is help (or /is admin for admin commands)? */ boolean displayCommand(); /** * The method to be executed when the command is running. * * @param plugin The instance of the plugin. * @param sender The sender who ran the command. * @param args The arguments of the command. */ void execute(SuperiorSkyblock plugin, CommandSender sender, String[] args); /** * Get the tab-complete arguments of the command. * * @param plugin The instance of the plugin. * @param sender The sender who ran the command. * @param args The arguments of the command. */ List tabComplete(SuperiorSkyblock plugin, CommandSender sender, String[] args); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java ================================================ package com.bgsoftware.superiorskyblock.api.config; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; public interface SettingsManager { /** * The amount of time between auto-calculations that the plugin runs. * If set to 0, it means the task is disabled. * Config path: calc-interval */ long getCalcInterval(); /** * All settings related to the database of the plugin. * Config path: database */ Database getDatabase(); /** * The main command of the plugin. * Aliases can be added by adding "," after the command name, and split them using ",". * Config path: island-command */ String getIslandCommand(); /** * The maximum island size. * Config path: max-island-size */ int getMaxIslandSize(); /** * All the default values for new islands that are created. * Config path: default-values */ DefaultValues getDefaultValues(); /** * The default height islands will generate. * Config path: islands-height */ int getIslandHeight(); /** * Whether world borders are enabled for islands or not. * Config path: world-borders */ boolean isWorldBorders(); /** * All settings related to the stacked-blocks system of the plugin. * Config path: stacked-blocks */ StackedBlocks getStackedBlocks(); /** * The formula used to calculate a block's level when it has a worth defined but no level specified. * The formula can contain a placeholder: `{}`, which is replaced with the block worth. * Config path: block-level-formula */ String getIslandLevelFormula(); /** * Whether island levels should be rounded or not. * Config path: rounded-island-level */ boolean isRoundedIslandLevels(); /** * The rounding mode used for the island level when rounded-island-level feature is enabled. * Config path: island-level-rounding-mode */ RoundingMode getIslandLevelRoundingMode(); /** * Whether to automatic track block counts when players place and break blocks. * Config path: auto-blocks-tracking */ boolean isAutoBlocksTracking(); /** * The default island-top sorting type. * Config path: island-top-order */ String getIslandTopOrder(); /** * The default global-warps sorting type. * Config path: global-warps-order */ String getGlobalWarpsOrder(); /** * Whether coop members are enabled. * Config path: coop-members */ boolean isCoopMembers(); /** * Should players be able to edit island privileges for other players? * Config path: edit-player-permissions */ boolean isEditPlayerPermissions(); /** * All settings related to the island-roles. * Config path: island-roles */ IslandRoles getIslandRoles(); /** * The line that determines if a sign is created as an island warp. * Config path: sign-warp-line */ String getSignWarpLine(); /** * The lines to be set for warp signs. * Config path: sign-warp */ List getSignWarp(); /** * All settings related to the visitors-sign. * Config path: visitors-sign */ VisitorsSign getVisitorsSign(); /** * All settings related to the worlds of the plugin. * Config path: worlds */ Worlds getWorlds(); /** * All settings related to the spawn island. * Config path: spawn */ Spawn getSpawn(); /** * A list of permissions players will have in the islands world, outside of islands. * Config path: world-permissions */ Collection getWorldPermissions(); /** * All settings related to the void teleportation. * Config path: void-teleport */ VoidTeleport getVoidTeleport(); /** * Get all the interactable blocks. * * @deprecated See {@link #getInteractablesMap} */ @Deprecated List getInteractables(); /** * Get all the interactable blocks and their interact privilege. */ Interactables getInteractablesMap(); /** * Get all the safe blocks. */ Collection getSafeBlocks(); /** * Whether visitors should take damage on islands or not. * Config path: visitors-damage */ boolean isVisitorsDamage(); /** * Whether coop players should take damage on islands or not. * Config-path: coop-damage */ boolean isCoopDamage(); /** * The default number of disbands players receive when they first join the server. * If -1, then the disbands limit is disabled. * Config-path: default-disband-count */ int getDisbandCount(); /** * Whether the members list shown in island top should include the leader or not. * Config-path: island-top-include-leader */ boolean isIslandTopIncludeLeader(); /** * Default placeholders to be returned when no island exists. * Config-path: default-placeholders */ Map getDefaultPlaceholders(); /** * Whether confirmation menu should be opened before banning a player from an island or not. * Config-path: ban-confirm */ boolean isBanConfirm(); /** * Whether confirmation menu should be opened before disbanding an island or not. * Config-path: disband-confirm */ boolean isDisbandConfirm(); /** * Whether confirmation menu should be opened before kicking an island member from an island or not. * Config-path: kick-confirm */ boolean isKickConfirm(); /** * Whether confirmation menu should be opened before leaving an island or not. * Config-path: leave-confirm */ boolean isLeaveConfirm(); /** * Whether confirmation menu should be opened before transfering an island or not. * Config-path: transfer-confirm */ boolean isTransferConfirm(); /** * The spawners-provider to use. * If set to AUTO, the plugin will automatically detect an available spawners provider and use it. * Config-path: spawners-provider */ String getSpawnersProvider(); /** * The stacked-blocks provider to use. * If set to AUTO, the plugin will automatically detect an available stacked-blocks provider and use it. * Config-path: stacked-blocks-provider */ String getStackedBlocksProvider(); /** * Whether inventory of island members should be cleared when their island is disbanded or not. * Return true if clear-on-disband contains both ENDER_CHEST and INVENTORY. * This method will be deleted in the future! * * @deprecated See {@link #getClearActionsOnDisband()} */ @Deprecated boolean isDisbandInventoryClear(); /** * All settings related to island-names. * Config path: island-names */ IslandNames getIslandNames(); /** * Whether to teleport players to their island when they create it or not. * Config path: teleport-on-create */ boolean isTeleportOnCreate(); /** * Whether to teleport players to their island when they join it or not. * Config-path: teleport-on-join */ boolean isTeleportOnJoin(); /** * Whether to teleport players to the spawn when they are kicked from their island or not. * Config-path: teleport-on-kick */ boolean isTeleportOnKick(); /** * Whether to teleport players to the spawn when they leave an island or not. * Config-path: teleport-on-leave */ boolean isTeleportOnLeave(); /** * Whether to clear players' inventories when they join a new island or not. * Return true if clear-on-join contains both ENDER_CHEST and INVENTORY. * This method will be deleted in the future! * * @deprecated See {@link #getClearActionsOnJoin()} */ @Deprecated boolean isClearOnJoin(); /** * Get the list of clear actions to perform on island members when their island is disbanded. * Config-path: clear-on-disband */ List getClearActionsOnDisband(); /** * Get the list of clear actions to perform on players when they accept an invite. * Config-path: clear-on-join */ List getClearActionsOnJoin(); /** * Get the list of clear actions to perform on players when they are kicked from their island. * Config-path: clear-on-kick */ List getClearActionsOnKick(); /** * Get the list of clear actions to perform on players when they leave an island. * Config-path: clear-on-leave */ List getClearActionsOnLeave(); /** * Whether players can rate their own island or not. * Config-path: rate-own-island */ boolean isRateOwnIsland(); /** * Whether players can change island rating or not. * Config-path: change-island-rating */ boolean isChangeIslandRating(); /** * All the default island-flags that will be enabled for new islands. * Config-path: default-settings */ List getDefaultSettings(); /** * Whether redstone should be disabled on islands when all of the members of the island are offline or not. * Config-path: disable-redstone-offline */ boolean isDisableRedstoneOffline(); /** * All settings related to afk-integrations. * Config path: afk-integrations */ AFKIntegrations getAFKIntegrations(); /** * Cooldowns of commands for players. * Represented by a map with keys as the command labels, and values as pairs * containing the cooldown and a bypass permission. * Config-path: commands-cooldown */ Map> getCommandsCooldown(); /** * Cooldown between upgrades. * If -1, then there is no cooldown. * Config-path: upgrade-cooldown */ long getUpgradeCooldown(); /** * The numbers-formatting of the plugin. * Config-path: number-format */ String getNumbersFormat(); /** * The date-formatting of the plugin. * Config-path: date-format */ String getDateFormat(); /** * Whether menus with only one item inside them should be skipped or not. * Config-path: skip-one-item-menus */ boolean isSkipOneItemMenus(); /** * Whether visitors on islands should get teleported to spawn when pvp is enabled on the island they were on or not. * Config-path: teleport-on-pvp-enable */ boolean isTeleportOnPvPEnable(); /** * Whether visitors should be immuned to PvP for a few seconds when they visit an island that has pvp enabled or not. * Config-path: immune-to-pvp-when-teleport */ boolean isImmuneToPvPWhenTeleport(); /** * List of blocked commands that visitors cannot run on islands. * Config-path: blocked-visitors-commands */ List getBlockedVisitorsCommands(); /** * All settings related to default-containers in schematics. * Currently, getting contents of containers is not available using the API. * Config path: island-names */ DefaultContainers getDefaultContainers(); /** * Lines that should be set for signs of schematics. * If empty, no signs will be changed. * Config-path: default-signs */ List getDefaultSign(); /** * List of commands to be executed for events. * Represented by a map with keys as event names and values as a list of commands. * Config-path: event-commands */ Map> getEventCommands(); /** * Delay before teleporting to an island warp, in milliseconds. * If 0, no delay will be. * Config-path: warps-warmup */ long getWarpsWarmup(); /** * Delay before teleporting to island home, in milliseconds. * If 0, no delay will be. * Config-path: home-warmup */ long getHomeWarmup(); /** * Delay before teleporting to another island, in milliseconds. * If 0, no delay will be. * Config-path: visit-warmup */ long getVisitWarmup(); /** * Whether liquids should receive a physics update when placed in schematics or not. * Config-path: liquid-update */ boolean isLiquidUpdate(); /** * Whether lights should be set when placing schematics or not. * Config-path: lights-update */ boolean isLightsUpdate(); /** * List of worlds that pvp is allowed between island-members. * Config-path: pvp-worlds */ List getPvPWorlds(); /** * Whether the plugin should force players to stay in islands in the islands worlds or not. * Config-path: stop-leaving */ boolean isStopLeaving(); /** * Whether players can open the values-menu by right-clicking on islands in the islands top menu or not. * Config-path: values-menu */ boolean isValuesMenu(); /** * List of crops that can get affected by the crops-growth multiplier. * Config-path: crops-to-grow */ List getCropsToGrow(); /** * Time between each iteration of the crops task. * Config-path: crops-interval */ int getCropsInterval(); /** * Whether players can only go back to the previous menu by clicking the back-button or not. * Config-path: only-back-button */ boolean isOnlyBackButton(); /** * Whether players can build outside their islands or not. * When enabled, island-sizes to be {@link #getMaxIslandSize()} * 1.5, * and islands will be connected to each other. * Config-path: build-outside-island */ boolean isBuildOutsideIsland(); /** * The default language to be set for new players. * Config-path: default-language */ String getDefaultLanguage(); /** * Whether new players should have world-borders enabled by default or not. * Config-path: default-world-border */ boolean isDefaultWorldBorder(); /** * Whether new players should be able to stack blocks by default or not. * Config-path: default-blocks-stacker */ boolean isDefaultStackedBlocks(); /** * Whether new players should have /is open their island panel by default or not. * Config-path: default-toggled-panel */ boolean isDefaultToggledPanel(); /** * Whether new players should have island fly enabled by default or not. * Config-path: default-island-fly */ boolean isDefaultIslandFly(); /** * The default border-color for new players. * Config-path: default-border-color */ String getDefaultBorderColor(); /** * Whether obsidian should turn into a lava-bucket when clicking on it with an empty bucket in hand or not. * Config-path: obsidian-to-lava */ boolean isObsidianToLava(); /** * The sync-worth status of the plugin. * Config-path: sync-worth */ BlockValuesManager.SyncWorthStatus getSyncWorth(); /** * Whether island-worth can be negative or not. * Config-path: negative-worth */ boolean isNegativeWorth(); /** * Whether island-level can be negative or not. * Config-path: negative-level */ boolean isNegativeLevel(); /** * List of plugin-events that should not be fired. * Config-path: disabled-events */ List getDisabledEvents(); /** * List of commands that should be disabled within the plugin. * Config-path: disabled-commands */ List getDisabledCommands(); /** * List of plugins that their hooks should not be enabled. * Config-path: disabled-hooks */ List getDisabledHooks(); /** * Whether the schematic-name argument should be when executing /is create or not. * Config-path: schematic-name-argument */ boolean isSchematicNameArgument(); /** * All settings related to island-chests. * Config path: island-chests */ IslandChests getIslandChests(); /** * Custom aliases for commands of the plugin. * Represented by a map with keys as commands, and values as aliases. * Config-path: command-aliases */ Map> getCommandAliases(); /** * List of valuable-blocks. * Config-path: valuable-blocks */ Set getValuableBlocks(); /** * List of preview-island locations. * Represented by a map with keys as schematic names, and values as locations for the preview islands. * Config-path: preview-islands * * @deprecated See {@link #getIslandPreviews()} */ @Deprecated Map getPreviewIslands(); /** * All settings related to the island previews. * Config path: island-previews */ IslandPreviews getIslandPreviews(); /** * Whether vanished players should be hidden from command tab completes or not. * Config-path: tab-complete-hide-vanished */ boolean isTabCompleteHideVanished(); /** * Whether drops multiplier should only affect entities that are killed by players or not. * Config-path: drops-upgrade-players-multiply */ boolean isDropsUpgradePlayersMultiply(); /** * The delay set for the ISLAND_PROTECTED message. * * @deprecated See {@link #getMessageDelays()} */ @Deprecated long getProtectedMessageDelay(); /** * A list of messages that should have a delay, in milliseconds. * Represented by a map with string as the message name, and values as the delays. * Config-path: message-delays */ Map getMessageDelays(); /** * Whether the warp categories system is enabled or not. * Config-path: warp-categories */ boolean isWarpCategories(); /** * Whether the plugin should listen for the physics event or not. * Config-path: physics-listener */ boolean isPhysicsListener(); /** * Amount of money to be charged from players when they use an island warp. * If set to 0, no money will be charged. * Config-path: charge-on-warp */ double getChargeOnWarp(); /** * Whether island warps should be public by default or not. * Config-path: public-warps */ boolean isPublicWarps(); /** * Whether islands should be locked by default or not. * Config-path: locked-islands */ boolean isLockedIslands(); /** * Cooldown between recalculations of an island, in seconds. * If set to 0, no cooldown is set. * Config-path: recalc-task-timeout */ long getRecalcTaskTimeout(); /** * Whether to detect the player's language automatically when he first joins the server. * Config-path: auto-language-detection */ boolean isAutoLanguageDetection(); /** * Automatically uncoop players when there are no island members left online that can remove uncoop players. * Config-path: auto-uncoop-when-alone */ boolean isAutoUncoopWhenAlone(); /** * Get the way to sort members in the top islands menu. * Config-path: island-top-members-sorting */ TopIslandMembersSorting getTopIslandMembersSorting(); /** * Limit of the amount of bossbar tasks each player can have at the same time. * Config-path: bossbar-limit */ int getBossbarLimit(); /** * Whether to delete unsafe warps when players try to teleport to them automatically. * Config-path: delete-unsafe-warps */ boolean getDeleteUnsafeWarps(); /** * Get the list of actions to perform when a player respawns. * Config-path: player-respawn */ List getPlayerRespawn(); /** * Get the threshold between saves for block counts. * Config-path: block-counts-save-threshold */ BigInteger getBlockCountsSaveThreshold(); /** * Support for chat-signing in 1.19+. * Config-path: chat-signing-support */ boolean getChatSigningSupport(); /** * Amount of commands to be listed in the `/is help` and `/is admin` commands. * Config-path: commands-per-page */ int getCommandsPerPage(); /** * Whether players should receive a help instead of a `INVALID_COMMAND` message * when using a command that doesn't exist or not. * Config-path: help-on-invalid-command */ boolean isHelpOnInvalidCommand(); /** * Whether players should receive a help instead of a `NO_COMMAND_PERMISSION` message * when using a command they don't have permission for or not. * Config-path: help-on-no-permission */ boolean isHelpOnNoPermission(); /** * Whether the plugin should cache schematics for faster placement of schematics. * Config-path: cache-schematics */ boolean isCacheSchematics(); /** * Custom entity categories to be used by the plugin. * Config-path: entity-categories */ @Deprecated Map getEntityCategories(); /** * Custom entity categories to be used by the plugin. */ EntityCategories getEntityCategoriesMap(); interface Database { /** * Get the database-type to use (SQLite or MySQL). * Config-path: database.type */ String getType(); /** * Whether the datastore folder should be back-up on startup. * Config-path: database.backup */ boolean isBackup(); /** * The address used to connect to the database. * Used for MySQL only. * Config-path: database.address */ String getAddress(); /** * The port used to connect to the database. * Used for MySQL only. * Config-path: database.port */ int getPort(); /** * Get the name of the database. * Used for MySQL only. * Config-path: database.db-name */ String getDBName(); /** * The username used to connect to the database. * Used for MySQL only. * Config-path: database.user-name */ String getUsername(); /** * The password used to connect to the database. * Used for MySQL only. * Config-path: database.password */ String getPassword(); /** * The prefix used for tables in the database. * Used for MySQL only. * Config-path: database.prefix */ String getPrefix(); /** * Whether the database uses SSL or not. * Used for MySQL only. * Config-path: database.useSSL */ boolean hasSSL(); /** * Whether public-key-retrieval is allowed in the database or not. * Used for MySQL only. * Config-path: database.allowPublicKeyRetrieval */ boolean hasPublicKeyRetrieval(); /** * The wait-timeout of the database, in milliseconds. * Used for MySQL only. * Config-path: database.waitTimeout */ long getWaitTimeout(); /** * The max-lifetime of the database, in milliseconds. * Used for MySQL only. * Config-path: database.maxLifetime */ long getMaxLifetime(); } interface DefaultValues { /** * The default island size for new islands. * Config-path: default-values.island-size */ int getIslandSize(); /** * The default block limits for new islands. * Represented by a map with keys as the block types, and values as the limits. * Config-path: default-values.block-limits */ Map getBlockLimits(); /** * The default entity limits for new islands. * Represented by a map with keys as the entity types, and values as the limits. * Config-path: default-values.entity-limits */ Map getEntityLimits(); /** * The default warps limit for new islands. * Config-path: default-values.warps-limit */ int getWarpsLimit(); /** * The default team limit for new islands. * Config-path: default-values.team-limit */ int getTeamLimit(); /** * The default coops limit for new islands. * Config-path: default-values.coop-limit */ int getCoopLimit(); /** * The default crop-growth multiplier for new islands. * Config-path: default-values.crop-growth */ double getCropGrowth(); /** * The default spawner-rates multiplier for new islands. * Config-path: default-values.spawner-rates */ double getSpawnerRates(); /** * The default mob-drops multiplier for new islands. * Config-path: default-values.mob-drops */ double getMobDrops(); /** * The default bank-limit for new islands. * Config-path: default-values.bank-limit */ BigDecimal getBankLimit(); /** * The default generator-rates for new islands. * Represented by an array of maps with keys as the blocks, and values as the rates. * The maps are sorted by the {@link Dimension} they belong to. * Config-path: default-values.generator * * @deprecated See {@link #getGeneratorsMap()} */ @Deprecated Map[] getGenerators(); /** * The default generator-rates for new islands. * Represented by maps with keys as the blocks, and values as the rates. * Config-path: default-values.generator */ Map> getGeneratorsMap(); /** * The default role-limits for new islands. * Represented by a map with keys as the role ids, and values as the limit. * Config-path: default-values.role-limits */ Map getRoleLimits(); /** * The default island effects for new islands. * Represented by a map with keys as the effect types, and values as the effect levels. * Config-path: default-values.island-effects */ Map getIslandEffects(); } interface StackedBlocks { /** * Whether stacked blocks are enabled on the server or not. * Config-path: stacked-blocks.enabled */ boolean isEnabled(); /** * The custom hologram names for stacked blocks. * Config-path: stacked-blocks.custom-name */ String getCustomName(); /** * List of worlds that blocks cannot be stacked in. * Config-path: stacked-blocks.disabled-worlds */ List getDisabledWorlds(); /** * List of whitelisted block types that can be stacked together. * Config-path: stacked-blocks.whitelisted */ Set getWhitelisted(); /** * Limits for stacked-blocks * Represented by a map with keys as block types, and values as limits. * Config-path: stacked-blocks.limits */ Map getLimits(); /** * Whether stacked blocks should be auto-collected to players' inventories or not. * Config-path: stacked-blocks.auto-collect */ boolean isAutoCollect(); /** * All the settings related to the deposit-menu of stacked blocks. * Config path: default-values.deposit-menu */ DepositMenu getDepositMenu(); interface DepositMenu { /** * Whether the deposit-menu is enabled or not. * Config path: default-values.deposit-menu.enabled */ boolean isEnabled(); /** * The title of the deposit menu. * Config path: default-values.deposit-menu.title */ String getTitle(); } } interface IslandRoles { /** * The configuration section of the island-roles. * Config path: island-roles */ ConfigurationSection getSection(); } interface VisitorsSign { /** * Whether a visitors sign is required for others to visit islands. * Config-path: visitors-sign.required-for-visit */ boolean isRequiredForVisit(); /** * The line that determines if the sign is used as a visitors home location. * Config-path: visitors-sign.line */ String getLine(); /** * The line that is displayed when the visitors sign is active. * Config-path: visitors-sign.active */ String getActive(); /** * The line that is displayed when the visitors sign is inactive. * Config-path: visitors-sign.inactive */ String getInactive(); /** * The format in which the island description lines will be saved. * Config-path: visitors-sign.description-line-format */ String getDescriptionLineFormat(); } interface Worlds { /** * The default world dimension. * Config-path: worlds.default-world */ Dimension getDefaultWorldDimension(); /** * The default world environment. * Config-path: worlds.default-world * * @deprecated See {@link #getDefaultWorldDimension()} */ @Deprecated World.Environment getDefaultWorld(); /** * The name of the overworld world. * Config-path: worlds.world-name */ String getWorldName(); /** * The name of the default world. */ String getDefaultWorldName(); /** * All settings related to the overworld world. * Config-path: worlds.normal * * @deprecated See {@link #getDimensionConfig(Dimension)} */ @Deprecated Normal getNormal(); /** * All settings related to the nether world. * Config-path: worlds.nether * * @deprecated See {@link #getDimensionConfig(Dimension)} */ @Deprecated Nether getNether(); /** * All settings related to the end world. * Config-path: worlds.end * * @deprecated See {@link #getDimensionConfig(Dimension)} */ @Deprecated End getEnd(); /** * All settings related to a dimension. * Config-path: worlds. */ @Nullable DimensionConfig getDimensionConfig(Dimension dimension); /** * The difficulty of the islands worlds. * Config-path: worlds.difficulty */ String getDifficulty(); /** * The sea level of island worlds. * Config path: worlds.sea-level-height */ int getSeaLevelHeight(); interface DimensionConfig { /** * Whether this dimension is enabled or not. * Config-path: worlds.dimensions..enabled */ boolean isEnabled(); /** * Whether this dimension is unlocked by default or not. * Config-path: worlds.dimensions..unlock */ boolean isUnlocked(); /** * Whether the schematic for this dimension should be offset or not. * Config-path: worlds.dimensions..schematic-offset */ boolean isSchematicOffset(); /** * Get the default biome for this dimension. * Config-path: worlds.dimensions..biome */ String getBiome(); /** * Get the world's name for this dimension. * Config-path: worlds.dimensions..name */ String getName(); /** * Get the destination of a specific portal type {@link PortalType} * Config-path: worlds.dimensions..portals * * @param portalType The portal type to get * @return The destination of that portal type, or null if doesn't exist. */ @Nullable Dimension getPortalDestination(PortalType portalType); } interface Normal extends DimensionConfig { } interface Nether extends DimensionConfig { } interface End extends DimensionConfig { /** * Whether ender-dragon fights should be enabled for islands or not. * Config-path: worlds.end.dragon-fight.enabled */ boolean isDragonFight(); /** * Get the offset of the portal from the center of the island. * Config-path: worlds.end.dragon-fight.portal-offset */ BlockOffset getPortalOffset(); } } interface Spawn { /** * The location of the spawn island. * Config-path: spawn.location */ String getLocation(); /** * Whether the spawn island has a protection or not. * Config-path: spawn.protection */ boolean isProtected(); /** * List of island-flags that will be enabled for the spawn island. * Config-path: spawn.settings */ List getSettings(); /** * List of permissions that will be given to players for the spawn island. * Config-path: spawn.permissions */ List getPermissions(); /** * Whether the spawn island has a world border or not. * Config-path: spawn.world-border */ boolean isWorldBorder(); /** * The size of the spawn island. * Config-path: spawn.size */ int getSize(); /** * Whether players should take damage in the spawn island or not. * Config-path: spawn.players-damage */ boolean isPlayersDamage(); } interface VoidTeleport { /** * Whether island members should be teleported when they fall into void on their island or not. * Config-path: void-teleport.members */ boolean isMembers(); /** * Whether visitors should be teleported when they fall into void on other islands or not. * Config-path: void-teleport.visitors */ boolean isVisitors(); } interface IslandNames { /** * Whether an island name is required for creating a new island or not. * Config-path: island-names.required-for-creation */ boolean isRequiredForCreation(); /** * The maximum length for island-names. * Config-path: island-names.max-length */ int getMaxLength(); /** * The minimum length for island-names. * Config-path: island-names.min-length */ int getMinLength(); /** * List of names that cannot be used. * Config-path: island-names.filtered-names */ List getFilteredNames(); /** * Whether island-names should support colors or not. * Config-path: island-names.color-support */ boolean isColorSupport(); /** * Whether island names should be displayed in the island-top menu or not. * Config-path: island-names.island-top */ boolean isIslandTop(); /** * Whether the plugin should prevent from choosing player names as island names or not. * Config-path: island-names.prevent-player-names */ boolean isPreventPlayerNames(); /** * Whether the name change announcement should be sent to all players or not. * Config-path: island-names.announce-change-to-all */ boolean isAnnounceChangeToAll(); } interface AFKIntegrations { /** * Whether redstone should be disabled when all island members are afk or not. * Config-path: afk-integrations.disable-redstone */ boolean isDisableRedstone(); /** * Whether mob spawning should be disabled when all island members are afk or not. * Config-path: afk-integrations.disable-spawning */ boolean isDisableSpawning(); } interface DefaultContainers { /** * Whether the default-containers system is enabled or not. * Config-path: default-containers.enabled */ boolean isEnabled(); } interface IslandChests { /** * The title to be shown for island chests. * Config-path: island-chests.chest-title */ String getChestTitle(); /** * The default pages new islands will have. * Config-path: island-chests.default-pages */ int getDefaultPages(); /** * The default size for chests. * Config-path: island-chests.default-size */ int getDefaultSize(); } interface IslandPreviews { /** * The game mode that will be set for the player when they enter preview mode. * Config-path: island-previews.game-mode */ GameMode getGameMode(); /** * The maximum distance a player can move before the preview mode is canceled. * Config-path: island-previews.max-distance */ int getMaxDistance(); /** * A list of commands that cannot be executed by players in preview mode. * Config-path: island-previews.blocked-commands */ List getBlockedCommands(); /** * List of island preview locations. * Represented by a map with keys as schematic names, and values as locations for the preview islands. * Config-path: island-previews.locations */ Map getLocations(); } interface Interactables { /** * Get all the interactables from the interactables file. */ Set getInteractables(); /** * Get all the interactables for a specific {@link IslandPrivilege} */ @Nullable Set getInteractables(IslandPrivilege islandPrivilege); /** * Get the required {@link IslandPrivilege} for a specific key. */ @Nullable IslandPrivilege getRequiredPrivilege(Key key); } interface EntityCategories { /** * Get all the categories from the entity-categories file. */ List getCategories(); /** * Get the entity categories for a specific entity key. * * @param key The entity's key */ List getCategories(Key key); /** * Get an entity category by its name * * @param name The name of the category. */ @Nullable EntityCategory getCategoryByName(String name); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/data/DatabaseBridge.java ================================================ package com.bgsoftware.superiorskyblock.api.data; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.objects.Pair; import java.util.Map; import java.util.function.Consumer; public interface DatabaseBridge { /** * Load all the objects from the database. * * @param table: The table to load the objects from. * @param resultConsumer Consumer that receives each object from the database. */ void loadAllObjects(String table, Consumer> resultConsumer); /** * Start saving data for the object. * If this method is not called, data should not be saved when saveRow is called. * * @deprecated See {@link #setDatabaseBridgeMode(DatabaseBridgeMode)} */ @Deprecated default void startSavingData() { setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } /** * Set whether to execute operations in batches or not. */ void batchOperations(boolean batchOperations); /** * Update the object in the database. * * @param table The name of the table in the database. * @param filter The filter of the column. * @param columns All columns to be saved with their values. */ void updateObject(String table, @Nullable DatabaseFilter filter, Pair... columns); /** * Insert the object in the database. * * @param table The name of the table in the database. * @param columns All columns to be saved with their values. */ void insertObject(String table, Pair... columns); /** * Delete the object from the database. * * @param table The name of the table in the database. * @param filter The filter of the column. */ void deleteObject(String table, @Nullable DatabaseFilter filter); /** * Load data from the database for this object. * * @param table The table to get the data from. * @param filter The filter of the column. * @param resultConsumer Consumer that receives data for each row. */ void loadObject(String table, @Nullable DatabaseFilter filter, Consumer> resultConsumer); /** * Set the mode for the database bridge. * * @param databaseBridgeMode The {@link DatabaseBridgeMode} mode to set. */ void setDatabaseBridgeMode(DatabaseBridgeMode databaseBridgeMode); /** * Get the current mode of the database bridge. */ DatabaseBridgeMode getDatabaseBridgeMode(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/data/DatabaseBridgeMode.java ================================================ package com.bgsoftware.superiorskyblock.api.data; /** * Represents the mode the database-bridge object is in. */ public enum DatabaseBridgeMode { /** * When this mode is selected, the database-bridge should run queries to the database. */ SAVE_DATA, /** * When this mode is selected, the database-bridge should not execute updates to the database. * Reading from the database should still work. */ IDLE } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/data/DatabaseFilter.java ================================================ package com.bgsoftware.superiorskyblock.api.data; import com.bgsoftware.superiorskyblock.api.objects.Pair; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; public abstract class DatabaseFilter { private static DatabaseFilterEmpty EMPTY_FILTER; public static DatabaseFilter fromFilter(String filterKey, Object filterValue) { return new DatabaseFilterSingle(filterKey, filterValue); } public static DatabaseFilter fromFilters(List> filters) { if (filters.isEmpty()) { if (EMPTY_FILTER == null) EMPTY_FILTER = new DatabaseFilterEmpty(); return EMPTY_FILTER; } else if (filters.size() == 1) { Pair filter = filters.get(0); return fromFilter(filter.getKey(), filter.getValue()); } else { return new DatabaseFilterList(filters); } } protected DatabaseFilter() { } public abstract void forEach(BiConsumer consumer); public abstract Collection> getFilters(); private static class DatabaseFilterList extends DatabaseFilter { private final Collection> filters; DatabaseFilterList(Collection> filters) { this.filters = filters; } @Override public void forEach(BiConsumer consumer) { filters.forEach(pair -> consumer.accept(pair.getKey(), pair.getValue())); } @Override public Collection> getFilters() { return Collections.unmodifiableCollection(filters); } } private static class DatabaseFilterEmpty extends DatabaseFilter { @Override public void forEach(BiConsumer consumer) { // Do nothing. } @Override public Collection> getFilters() { return Collections.emptyList(); } } private static class DatabaseFilterSingle extends DatabaseFilter { private final String filterKey; private final Object filterValue; DatabaseFilterSingle(String filterKey, Object filterValue) { this.filterKey = filterKey; this.filterValue = filterValue; } @Override public void forEach(BiConsumer consumer) { consumer.accept(filterKey, filterValue); } @Override public Collection> getFilters() { return Collections.singleton(new Pair<>(filterKey, filterValue)); } } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/data/IDatabaseBridgeHolder.java ================================================ package com.bgsoftware.superiorskyblock.api.data; public interface IDatabaseBridgeHolder { /** * Get the current database bridge of the object. */ DatabaseBridge getDatabaseBridge(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java ================================================ package com.bgsoftware.superiorskyblock.api.entity; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.KeySet; public interface EntityCategory { /** * Get the name of the entity category. */ String getName(); /** * Get the entities this category contains. */ KeySet getEntities(); /** * Get the required {@link IslandPrivilege} to spawn entities from this category on an island. */ @Nullable IslandPrivilege getSpawnPrivilege(); /** * Get the required {@link IslandPrivilege} to damage entities from this category on an island. */ @Nullable IslandPrivilege getDamagePrivilege(); /** * Get the required {@link IslandPrivilege} to interact with entities from this category on an island. */ @Nullable IslandPrivilege getInteractPrivilege(); /** * Get the required {@link IslandFlag} for entities from this category to spawn on an island from a spawner. */ @Nullable IslandFlag getSpawnerSpawningIslandFlag(); /** * Get the required {@link IslandFlag} for entities from this category to spawn on an island naturally. */ @Nullable IslandFlag getNaturalSpawningIslandFlag(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/BankAction.java ================================================ package com.bgsoftware.superiorskyblock.api.enums; public enum BankAction { WITHDRAW_COMPLETED, WITHDRAW_FAILED, DEPOSIT_COMPLETED, DEPOSIT_FAILED } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/BorderColor.java ================================================ package com.bgsoftware.superiorskyblock.api.enums; /** * Used to determine what's the color of the border of players. */ public enum BorderColor { RED, GREEN, BLUE; public static BorderColor safeValue(String name, BorderColor def) { try { return BorderColor.valueOf(name); } catch (IllegalArgumentException ex) { return def; } } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/HitActionResult.java ================================================ package com.bgsoftware.superiorskyblock.api.enums; public enum HitActionResult { NOT_ONLINE, PVP_WARMUP, ISLAND_PVP_DISABLE, VISITOR_DAMAGE, COOP_DAMAGE, TARGET_NOT_ONLINE, TARGET_PVP_WARMUP, TARGET_ISLAND_PVP_DISABLE, TARGET_VISITOR_DAMAGE, TARGET_COOP_DAMAGE, ISLAND_TEAM_PVP, SUCCESS } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/MemberRemoveReason.java ================================================ package com.bgsoftware.superiorskyblock.api.enums; /** * Used to determine the reason why a member was removed from an island. */ public enum MemberRemoveReason { /** * The member was removed because the island was disbanded. */ DISBAND, /** * The member was removed because another player kicked them from the island. */ KICK, /** * The member was removed because they left the island. */ LEAVE } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/Rating.java ================================================ package com.bgsoftware.superiorskyblock.api.enums; import java.util.Locale; /** * Used to determine what rating has a player given to an island. */ public enum Rating { UNKNOWN, ZERO_STARS, ONE_STAR, TWO_STARS, THREE_STARS, FOUR_STARS, FIVE_STARS; private static String ALL_RATING_NAMES; /** * Get a string of all the rating names. */ public static String getValuesString() { if (ALL_RATING_NAMES == null) { StringBuilder namesBuilder = new StringBuilder(); for (Rating rating : Rating.values()) namesBuilder.append(", ").append(rating.toString().toLowerCase(Locale.ENGLISH)); ALL_RATING_NAMES = namesBuilder.length() == 0 ? "" : namesBuilder.substring(2); } return ALL_RATING_NAMES; } /** * Get a rating by it's value. */ public static Rating valueOf(int value) { return values()[value + 1]; } /** * Get the integer value of the rating. */ public int getValue() { return ordinal() - 1; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/SyncStatus.java ================================================ package com.bgsoftware.superiorskyblock.api.enums; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; /** * Sync status for {@link IslandFlag} and {@link IslandPrivilege} in islands. */ public enum SyncStatus { /** * The target is enabled and is not synced. */ ENABLED, /** * The target is disabled and is not synced. */ DISABLED, /** * The target is synced with upgrades and default config values. */ SYNCED } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/TopIslandMembersSorting.java ================================================ package com.bgsoftware.superiorskyblock.api.enums; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.Comparator; public enum TopIslandMembersSorting { /** * Sort members in the top-islands menu by their names. */ NAMES, /** * Sort members in the top-islands menu by their roles. */ ROLES; private Comparator comparator = null; TopIslandMembersSorting() { } public void setComparator(Comparator comparator) { if (this.comparator != null) throw new IllegalArgumentException("You cannot set a comparator after it was already been set."); this.comparator = comparator; } public Comparator getComparator() { if (this.comparator == null) throw new RuntimeException(this + " was not initialized."); return comparator; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/AttemptPlayerSendMessageEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * AttemptPlayerSendMessageEvent is called when a message is attempted to be sent to {@link SuperiorPlayer} * The event is called before it checks if {@link SuperiorPlayer} can get the message. * In this time there is no {@link IMessageComponent} yet, as it is created only once the message can be sent * to the receiver. */ public class AttemptPlayerSendMessageEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer receiver; private final String messageType; private final Object[] args; private boolean cancelled = false; /** * The constructor for the event. * * @param receiver The receiver of the message. * @param messageType The name of the message, similar to the one from lang file. */ public AttemptPlayerSendMessageEvent(SuperiorPlayer receiver, String messageType, Object[] args) { super(!Bukkit.isPrimaryThread()); this.receiver = receiver; this.messageType = messageType; this.args = args; } /** * Get the receiver of the message. */ public SuperiorPlayer getReceiver() { return receiver; } /** * Get the name of the message, similar to the one from lang file. */ public String getMessageType() { return messageType; } /** * Get an argument of the message. * * @param index The index of the argument. * @throws ArrayIndexOutOfBoundsException If {@param index} is out of bounds. */ public Object getArgument(int index) { return args[index]; } /** * Set an argument for the message. * * @param index The index of the argument. * @param value The value to be set. * @throws ArrayIndexOutOfBoundsException If {@param index} is out of bounds. */ public void setArgument(int index, Object value) { Preconditions.checkNotNull(value, "Argument's value cannot be null."); args[index] = value; } /** * Get the length of the arguments array. */ public int getArgumentsLength() { return args.length; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/BlockStackEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.HandlerList; import org.bukkit.event.block.BlockEvent; public class BlockStackEvent extends BlockEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final Player player; private final int originalCount; private final int newCount; private boolean cancelled = false; public BlockStackEvent(Block block, Player player, int originalCount, int newCount) { super(block); this.player = player; this.originalCount = originalCount; this.newCount = newCount; } public static HandlerList getHandlerList() { return handlers; } public Player getPlayer() { return player; } public int getOriginalCount() { return originalCount; } public int getNewCount() { return newCount; } public int getIncreaseAmount() { return newCount - originalCount; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/BlockUnstackEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.HandlerList; import org.bukkit.event.block.BlockEvent; public class BlockUnstackEvent extends BlockEvent implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final Player player; private final int originalCount; private final int newCount; private boolean cancelled = false; public BlockUnstackEvent(Block block, Player player, int originalCount, int newCount) { super(block); this.player = player; this.originalCount = originalCount; this.newCount = newCount; } public static HandlerList getHandlerList() { return handlers; } @Nullable public Player getPlayer() { return player; } public int getOriginalCount() { return originalCount; } public int getNewCount() { return newCount; } public int getDecreaseAmount() { return originalCount - newCount; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandBanEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandBanEvent is called when a player is banned from his island. */ public class IslandBanEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final SuperiorPlayer targetPlayer; private boolean cancelled; /** * The constructor of the event. * * @param superiorPlayer The player who banned the other player. * @param targetPlayer The player that was banned. * @param island The island that the player was banned from. */ public IslandBanEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; this.targetPlayer = targetPlayer; } /** * Get the player who banned the other player. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the player that was banned. */ public SuperiorPlayer getTarget() { return targetPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandBankDepositEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; import java.math.BigDecimal; /** * IslandBankDepositEvent is called when money is deposited to the bank. */ public class IslandBankDepositEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final BigDecimal amount; private String failureReason = null; /** * The constructor of the event. * * @param superiorPlayer The player who deposited the money. * @param island The island that the money was deposited to. * @param amount The amount that was deposited. */ public IslandBankDepositEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, BigDecimal amount) { super(island); this.superiorPlayer = superiorPlayer; this.amount = amount; } /** * Get the player who deposited the money. * When null, then the console deposited the money using the admin command. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the amount that was deposited. */ public BigDecimal getAmount() { return amount; } /** * Get the failure reason of the transaction. */ @Nullable public String getFailureReason() { return failureReason; } /** * Set a failure reason for the transaction. * * @param failureReason The new failure reason to set. */ public void setFailureReason(@Nullable String failureReason) { this.failureReason = failureReason != null && failureReason.isEmpty() ? null : failureReason; } @Override public boolean isCancelled() { return this.failureReason != null; } @Override public void setCancelled(boolean cancelled) { setFailureReason(cancelled ? "Generic event cancel." : null); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandBankWithdrawEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; import java.math.BigDecimal; /** * IslandBankDepositEvent is called when money is deposited to the bank. */ public class IslandBankWithdrawEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final BigDecimal amount; private String failureReason = null; /** * The constructor of the event. * * @param superiorPlayer The player who withdrawn the money. * @param island The island that the money was withdrawn from. * @param amount The amount that was withdrawn. */ public IslandBankWithdrawEvent(SuperiorPlayer superiorPlayer, Island island, BigDecimal amount) { super(island); this.superiorPlayer = superiorPlayer; this.amount = amount; } /** * Get the player who withdrawn the money. * When null, then the console deposited the money using the admin command. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the amount that was deposited. */ public BigDecimal getAmount() { return amount; } /** * Get the failure reason of the transaction. */ @Nullable public String getFailureReason() { return failureReason; } /** * Set a failure reason for the transaction. * * @param failureReason The new failure reason to set. */ public void setFailureReason(@Nullable String failureReason) { this.failureReason = failureReason != null && failureReason.isEmpty() ? null : failureReason; } @Override public boolean isCancelled() { return this.failureReason != null; } @Override public void setCancelled(boolean cancelled) { setFailureReason(cancelled ? "Generic event cancel." : null); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandBiomeChangeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.block.Biome; import org.bukkit.event.Cancellable; /** * IslandCreateEvent is called when a new island is created. */ public class IslandBiomeChangeEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private Biome biome; private boolean cancelled = false; /** * The constructor for the event. * * @param superiorPlayer The player who changed the biome of the island. * @param island The island object that was changed. * @param biome The name of the new biome. */ public IslandBiomeChangeEvent(SuperiorPlayer superiorPlayer, Island island, Biome biome) { super(island); this.superiorPlayer = superiorPlayer; this.biome = biome; } /** * Get the player who upgraded the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new biome. */ public Biome getBiome() { return biome; } /** * Set the new biome. */ public void setBiome(Biome biome) { this.biome = biome; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeBankLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; import java.math.BigDecimal; /** * IslandChangeBankLimitEvent is called when the bank-limit of the island is changed. */ public class IslandChangeBankLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private BigDecimal bankLimit; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the bank limit of the island. * If set to null, it means the limit was changed by console. * @param island The island that the bank limit was changed for. * @param bankLimit The new bank limit of the island */ public IslandChangeBankLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, BigDecimal bankLimit) { super(island); this.superiorPlayer = superiorPlayer; this.bankLimit = bankLimit; } /** * Get the player that changed the bank limit of the island. * If null, it means the limit was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new bank limit of the island. */ public BigDecimal getBankLimit() { return bankLimit; } /** * Set the new bank limit for the island. * * @param bankLimit The new bank limit to set. */ public void setBankLimit(BigDecimal bankLimit) { Preconditions.checkNotNull(bankLimit, "Cannot set the bank limit to null."); Preconditions.checkArgument(bankLimit.compareTo(BigDecimal.ZERO) >= 0, "Cannot set the bank limit to a negative limit."); this.bankLimit = bankLimit; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeBlockLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeBlockLimitEvent is called when a block-limit of an island is changed. */ public class IslandChangeBlockLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Key block; private int blockLimit; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the block limit of an island. * If set to null, it means the limit was changed via the console. * @param island The island that the block limit was changed for. * @param block The block that the limit was changed for. * @param blockLimit The new block limit of the block */ public IslandChangeBlockLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block, int blockLimit) { super(island); this.superiorPlayer = superiorPlayer; this.block = block; this.blockLimit = blockLimit; } /** * Get the player that changed the block limit. * If null, it means the limit was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the block that the limit was changed for. */ public Key getBlock() { return block; } /** * Get the new block limit of the block. */ public int getBlockLimit() { return blockLimit; } /** * Set the new block limit of the block. * * @param blockLimit The new block limit to set. */ public void setBlockLimit(int blockLimit) { Preconditions.checkArgument(blockLimit >= 0, "Cannot set the block limit to a negative limit."); this.blockLimit = blockLimit; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeBorderSizeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeBorderSizeEvent is called when the border-size of the island is changed. */ public class IslandChangeBorderSizeEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private int borderSize; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the border size of the island. * If set to null, it means the limit was changed by console. * @param island The island that the border size was changed for. * @param borderSize The new border size of the island */ public IslandChangeBorderSizeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, int borderSize) { super(island); this.superiorPlayer = superiorPlayer; this.borderSize = borderSize; } /** * Get the player that changed the border-size of the island. * If null, it means the size was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new border size of the island. */ public int getBorderSize() { return borderSize; } /** * Set the new border size for the island. * * @param borderSize The new border size to set. */ public void setBorderSize(int borderSize) { Preconditions.checkArgument(borderSize >= 1, "Cannot set the border size to values lower than 1."); this.borderSize = borderSize; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeCoopLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeCoopLimitEvent is called when the coop-limit of the island is changed. */ public class IslandChangeCoopLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private int coopLimit; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the coop limit of the island. * If set to null, it means the limit was changed via the console. * @param island The island that the coop limit was changed for. * @param coopLimit The new coop limit of the island */ public IslandChangeCoopLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, int coopLimit) { super(island); this.superiorPlayer = superiorPlayer; this.coopLimit = coopLimit; } /** * Get the player that changed the coop limit. * If null, it means the limit was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new coop limit of the island. */ public int getCoopLimit() { return coopLimit; } /** * Set the new coop limit for the island. * * @param coopLimit The new coop limit to set. */ public void setCoopLimit(int coopLimit) { Preconditions.checkArgument(coopLimit >= 0, "Cannot set the coop limit to a negative limit."); this.coopLimit = coopLimit; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeCropGrowthEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeCropGrowthEvent is called when the crop-growth multiplier of the island is changed. */ public class IslandChangeCropGrowthEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private double cropGrowth; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the crop-growth multiplier of the island. * If set to null, it means the crop-growth multiplier was changed via the console. * @param island The island that the crop-growth multiplier was changed for. * @param cropGrowth The new crop-growth multiplier of the island */ public IslandChangeCropGrowthEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, double cropGrowth) { super(island); this.superiorPlayer = superiorPlayer; this.cropGrowth = cropGrowth; } /** * Get the player that changed the crop-growth multiplier. * If null, it means the crop-growth multiplier was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new crop-growth multiplier of the island. */ public double getCropGrowth() { return cropGrowth; } /** * Set the new crop-growth multiplier for the island. * * @param cropGrowth The crop-growth multiplier to set. */ public void setCropGrowth(double cropGrowth) { Preconditions.checkArgument(cropGrowth >= 0, "Cannot set the crop growth to a negative multiplier."); this.cropGrowth = cropGrowth; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeDescriptionEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeDescriptionEvent is called when an island changes its description. */ public class IslandChangeDescriptionEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private String description; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that its description was changed. * @param superiorPlayer The player that changed the description of the island. * @param description The new description of the island. */ public IslandChangeDescriptionEvent(Island island, SuperiorPlayer superiorPlayer, String description) { super(island); this.superiorPlayer = superiorPlayer; this.description = description; } /** * Get the player that changed the description of the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new description of the island. */ public String getDescription() { return description; } /** * Set the new description of the island. * * @param description The new description to set. */ public void setIslandName(String description) { Preconditions.checkNotNull(description, "Island descriptions cannot be null."); this.description = description; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeDiscordEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeDiscordEvent is called when the discord of the island is changed. */ public class IslandChangeDiscordEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private String discord; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the discord of the island. * @param island The island that the discord was changed for. * @param discord The new discord of the island */ public IslandChangeDiscordEvent(SuperiorPlayer superiorPlayer, Island island, String discord) { super(island); this.superiorPlayer = superiorPlayer; this.discord = discord; } /** * Get the player that changed the discord of the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new discord of the island. */ public String getDiscord() { return discord; } /** * Set the new discord for the island. * * @param discord The new discord to set. */ public void setDiscord(String discord) { Preconditions.checkNotNull(discord, "Cannot set the discord of the island to null."); this.discord = discord; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeEffectLevelEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; import org.bukkit.potion.PotionEffectType; /** * IslandChangeEffectLevelEvent is called when an effect of an island is changed. */ public class IslandChangeEffectLevelEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final PotionEffectType effectType; private int effectLevel; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the effect level of an island. * If set to null, it means the level was changed via the console. * @param island The island that the effect level was changed for. * @param effectType The effect that the level was changed for. * @param effectLevel The new level of the effect. */ public IslandChangeEffectLevelEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, PotionEffectType effectType, int effectLevel) { super(island); this.superiorPlayer = superiorPlayer; this.effectType = effectType; this.effectLevel = effectLevel; } /** * Get the player that changed the effect level. * If null, it means the level was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the effect that the level was changed for. */ public PotionEffectType getEffectType() { return effectType; } /** * Get the new level of the effect. */ public int getEffectLevel() { return effectLevel; } /** * Set the new level of the effect. * * @param effectLevel The new effect level to set. */ public void setEffectLevel(int effectLevel) { Preconditions.checkArgument(effectLevel >= 0, "Cannot set the effect level to a negative level."); this.effectLevel = effectLevel; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeEntityLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeEntityLimitEvent is called when an entity-limit of an island is changed. */ public class IslandChangeEntityLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Key entity; private int entityLimit; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the entity limit of an island. * If set to null, it means the limit was changed via the console. * @param island The island that the entity limit was changed for. * @param entity The entity that the limit was changed for. * @param entityLimit The new entity limit of the entity. */ public IslandChangeEntityLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key entity, int entityLimit) { super(island); this.superiorPlayer = superiorPlayer; this.entity = entity; this.entityLimit = entityLimit; } /** * Get the player that changed the entity limit. * If null, it means the limit was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the entity that the limit was changed for. */ public Key getEntity() { return entity; } /** * Get the new entity limit of the entity. */ public int getEntityLimit() { return entityLimit; } /** * Set the new entity limit of the entity.. * * @param entityLimit The new entity limit to set. */ public void setEntityLimit(int entityLimit) { Preconditions.checkArgument(entityLimit >= 0, "Cannot set the entity limit to a negative limit."); this.entityLimit = entityLimit; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeGeneratorRateEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.World; import org.bukkit.event.Cancellable; /** * IslandChangeGeneratorRateEvent is called when a generator-rate of an island is changed. */ public class IslandChangeGeneratorRateEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Key block; private final Dimension dimension; private int generatorRate; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the generator-rate of an island. * If set to null, it means the rate was changed via the console. * @param island The island that the generator-rate was changed for. * @param block The block that the rate was changed for. * @param environment The environment of the world that the rate was changed for. * @param generatorRate The new generator-rate of the block. */ @Deprecated public IslandChangeGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block, World.Environment environment, int generatorRate) { this(superiorPlayer, island, block, Dimension.getByName(environment.name()), generatorRate); } /** * The constructor of the event. * * @param superiorPlayer The player that changed the generator-rate of an island. * If set to null, it means the rate was changed via the console. * @param island The island that the generator-rate was changed for. * @param block The block that the rate was changed for. * @param dimension The dimension of the world that the rate was changed for. * @param generatorRate The new generator-rate of the block. */ public IslandChangeGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block, Dimension dimension, int generatorRate) { super(island); this.superiorPlayer = superiorPlayer; this.block = block; this.dimension = dimension; this.generatorRate = generatorRate; } /** * Get the player that changed the generator-rate. * If null, it means the level was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the block that the generator-rate was changed for. */ public Key getBlock() { return block; } /** * Get the environment of the world that the rate was changed for. */ @Deprecated public World.Environment getEnvironment() { return this.dimension.getEnvironment(); } /** * Get the environment of the world that the rate was changed for. */ public Dimension getDimension() { return this.dimension; } /** * Get the new generator-rate of the block. */ public int getGeneratorRate() { return generatorRate; } /** * Set the new generator-rate of the block. * * @param generatorRate The new generator-rate to set. */ public void setGeneratorRate(int generatorRate) { Preconditions.checkArgument(generatorRate >= 0, "Cannot set the generator-rate to a negative rate."); this.generatorRate = generatorRate; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeLevelBonusEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; import java.math.BigDecimal; /** * IslandChangeLevelBonusEvent is called when the level-bonus of the island is changed. */ public class IslandChangeLevelBonusEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Reason reason; private BigDecimal levelBonus; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the level bonus of the island. * If set to null, it means the bonus was changed by console. * @param island The island that the level bonus was changed for. * @param reason The reason for changing the level bonus. * @param levelBonus The new level bonus of the island */ public IslandChangeLevelBonusEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Reason reason, BigDecimal levelBonus) { super(island); this.superiorPlayer = superiorPlayer; this.reason = reason; this.levelBonus = levelBonus; } /** * Get the player that changed the level bonus. * If null, it means the bonus was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the reason for changing the level bonus. */ public Reason getReason() { return reason; } /** * Get the new level bonus of the island. */ public BigDecimal getLevelBonus() { return levelBonus; } /** * Set the new level bonus for the island. * * @param levelBonus The new level bonus to set. */ public void setLevelBonus(BigDecimal levelBonus) { Preconditions.checkNotNull(levelBonus, "Cannot set the level bonus to null."); this.levelBonus = levelBonus; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } /** * The reason for changing the level bonus. */ public enum Reason { /** * The level bonus was changed due to a command by a player or console. */ COMMAND, /** * The level bonus was changed due to schematic that was placed in the world for the island. */ SCHEMATIC } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeMembersLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeMembersLimitEvent is called when the members limit of an island is changed. */ public class IslandChangeMembersLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private int membersLimit; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the members limit of an island. * If set to null, it means the limit was changed via the console. * @param island The island that the members limit was changed for. * @param membersLimit The new members limit of an island. */ public IslandChangeMembersLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, int membersLimit) { super(island); this.superiorPlayer = superiorPlayer; this.membersLimit = membersLimit; } /** * Get the player that changed the members limit. * If null, it means the limit was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new members limit of the island. */ public int getMembersLimit() { return membersLimit; } /** * Set the new members limit of the island. * * @param membersLimit The new members limit to set. */ public void setMembersLimit(int membersLimit) { Preconditions.checkArgument(membersLimit >= 0, "Cannot set the members limit to a negative limit."); this.membersLimit = membersLimit; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeMobDropsEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeMobDropsEvent is called when the mob-drops multiplier of the island is changed. */ public class IslandChangeMobDropsEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private double mobDrops; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the mob-drops multiplier of the island. * If set to null, it means the mob-drops multiplier was changed via the console. * @param island The island that the mob-drops multiplier was changed for. * @param mobDrops The new mob drops of the island */ public IslandChangeMobDropsEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, double mobDrops) { super(island); this.superiorPlayer = superiorPlayer; this.mobDrops = mobDrops; } /** * Get the player that changed the mob-drops multiplier. * If null, it means the mob-drops multiplier was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new mob-drops multiplier of the island. */ public double getMobDrops() { return mobDrops; } /** * Set the new mob-drops multiplier for the island. * * @param mobDrops The mob-drops multiplier to set. */ public void setMobDrops(double mobDrops) { Preconditions.checkArgument(mobDrops >= 0, "Cannot set the mob-drops to a negative multiplier."); this.mobDrops = mobDrops; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangePaypalEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangePaypalEvent is called when the paypal of the island is changed. */ public class IslandChangePaypalEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private String paypal; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the paypal of the island. * @param island The island that the paypal was changed for. * @param paypal The new paypal of the island */ public IslandChangePaypalEvent(SuperiorPlayer superiorPlayer, Island island, String paypal) { super(island); this.superiorPlayer = superiorPlayer; this.paypal = paypal; } /** * Get the player that changed the paypal of the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new paypal of the island. */ public String getPaypal() { return paypal; } /** * Set the new paypal for the island. * * @param paypal The new paypal to set. */ public void setPaypal(String paypal) { Preconditions.checkNotNull(paypal, "Cannot set the discord of the island to null."); this.paypal = paypal; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangePlayerPrivilegeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandChangePlayerPrivilegeEvent is called when a privilege is changed for a player on an island. */ public class IslandChangePlayerPrivilegeEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final SuperiorPlayer privilegedPlayer; private final boolean privilegeEnabled; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the privilege was changed in. * @param superiorPlayer The player that changed the privilege to the other player. * @param privilegedPlayer The player that the privilege was changed for. * @param privilegeEnabled Whether the privilege was enabled or disabled for the player. */ public IslandChangePlayerPrivilegeEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer privilegedPlayer, boolean privilegeEnabled) { super(island); this.superiorPlayer = superiorPlayer; this.privilegedPlayer = privilegedPlayer; this.privilegeEnabled = privilegeEnabled; } /** * Get the player that changed the privilege to the other player. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the player that the privilege was changed for. */ public SuperiorPlayer getPrivilegedPlayer() { return privilegedPlayer; } /** * Check whether the privilege was enabled to {@link #getPrivilegedPlayer()} */ public boolean isPrivilegeEnabled() { return privilegeEnabled; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeRoleLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeRoleLimitEvent is called when a role-limit of an island is changed. */ public class IslandChangeRoleLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final PlayerRole playerRole; private int roleLimit; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the role limit of an island. * If set to null, it means the limit was changed via the console. * @param island The island that the role limit was changed for. * @param playerRole The role that the limit was changed for. * @param roleLimit The new role limit of the role. */ public IslandChangeRoleLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, PlayerRole playerRole, int roleLimit) { super(island); this.superiorPlayer = superiorPlayer; this.playerRole = playerRole; this.roleLimit = roleLimit; } /** * Get the player that changed the role limit. * If null, it means the limit was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the role that the limit was changed for. */ public PlayerRole getPlayerRole() { return playerRole; } /** * Get the new role limit of the role. */ public int getRoleLimit() { return roleLimit; } /** * Set the new role limit for the role. * * @param roleLimit The new role limit to set. */ public void setRoleLimit(int roleLimit) { Preconditions.checkArgument(roleLimit >= 0, "Cannot set the role limit to a negative limit."); this.roleLimit = roleLimit; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeRolePrivilegeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandChangeRolePrivilegeEvent is called when a privilege is changed for a role on an island. */ public class IslandChangeRolePrivilegeEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final PlayerRole playerRole; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the privilege was changed in. * @param superiorPlayer The player that changed the privilege to the other role. * If null, the privilege was changed by the console. * @param playerRole The role that the privilege was changed for. */ public IslandChangeRolePrivilegeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) { super(island); this.superiorPlayer = superiorPlayer; this.playerRole = playerRole; } /** * Get the player that changed the privilege to the other player. * If null, the privilege was changed by the console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the role that the privilege was changed for. */ public PlayerRole getPlayerRole() { return playerRole; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeSpawnerRatesEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeSpawnerRatesEvent is called when the spawner-rates multiplier of the island is changed. */ public class IslandChangeSpawnerRatesEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private double spawnerRates; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the spawner-rates multiplier of the island. * If set to null, it means the spawner-rates multiplier was changed via the console. * @param island The island that the spawner-rates multiplier was changed for. * @param spawnerRates The new spawner-rates multiplier of the island */ public IslandChangeSpawnerRatesEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, double spawnerRates) { super(island); this.superiorPlayer = superiorPlayer; this.spawnerRates = spawnerRates; } /** * Get the player that changed the spawner-rates multiplier. * If null, it means the spawner-rates multiplier was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new spawner-rates multiplier of the island. */ public double getSpawnerRates() { return spawnerRates; } /** * Set the new spawner-rates multiplier for the island. * * @param spawnerRates The spawner-rates multiplier to set. */ public void setSpawnerRates(double spawnerRates) { Preconditions.checkArgument(spawnerRates >= 0, "Cannot set the spawner rate to a negative multiplier."); this.spawnerRates = spawnerRates; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpCategoryIconEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; import org.bukkit.inventory.ItemStack; /** * IslandChangeWarpCategoryIconEvent is called when the icon of a warp-category was changed. */ public class IslandChangeWarpCategoryIconEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final WarpCategory warpCategory; @Nullable private ItemStack icon; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the icon of the warp-category. * @param island The island of the warp-category. * @param warpCategory The warp-category that its icon was changed. * @param icon The new icon of the warp-category. * If null, default icon will be set. */ public IslandChangeWarpCategoryIconEvent(SuperiorPlayer superiorPlayer, Island island, WarpCategory warpCategory, @Nullable ItemStack icon) { super(island); this.superiorPlayer = superiorPlayer; this.warpCategory = warpCategory; this.icon = icon == null ? null : icon.clone(); } /** * Get the player that changed the icon of the warp-category. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp-category that its icon was changed. */ public WarpCategory getWarpCategory() { return warpCategory; } /** * Get the new icon of the warp-category. */ @Nullable public ItemStack getIcon() { return icon == null ? null : icon.clone(); } /** * Set the new icon for the warp-category. * If set to null, default icon will be set. * * @param icon The new icon to set. */ public void setIcon(@Nullable ItemStack icon) { this.icon = icon == null ? null : icon.clone(); } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpCategorySlotEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeWarpCategorySlotEvent is called when the slot of a warp-category was changed. */ public class IslandChangeWarpCategorySlotEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final WarpCategory warpCategory; private final int maxSlot; private int slot; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the slot of the warp-category. * @param island The island of the warp-category. * @param warpCategory The warp-category that its slot was changed. * @param slot The new slot of the warp-category. * @param maxSlot The maximum slot that the warp category can occupy. */ public IslandChangeWarpCategorySlotEvent(SuperiorPlayer superiorPlayer, Island island, WarpCategory warpCategory, int slot, int maxSlot) { super(island); this.superiorPlayer = superiorPlayer; this.warpCategory = warpCategory; this.slot = slot; this.maxSlot = maxSlot; } /** * Get the player that changed the slot of the warp-category. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp-category that its slot was changed. */ public WarpCategory getWarpCategory() { return warpCategory; } /** * Get the new slot of the warp-category. */ public int getSlot() { return slot; } /** * Set the new slot for the warp-category. * * @param slot The new slot to set. */ public void setSlot(int slot) { Preconditions.checkArgument(slot < maxSlot, "Cannot set the slot to outside of the inventory space."); Preconditions.checkState(island.getWarpCategory(slot) == null, "Cannot change the slot of" + " the category to an already existing another category's slot"); this.slot = slot; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpIconEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; import org.bukkit.inventory.ItemStack; /** * IslandChangeWarpIconEvent is called when the icon of a warp was changed. */ public class IslandChangeWarpIconEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final IslandWarp islandWarp; @Nullable private ItemStack icon; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the icon of the warp. * @param island The island of the warp. * @param islandWarp The warp that its icon was changed. * @param icon The new icon of the warp. * If null, default icon will be set. */ public IslandChangeWarpIconEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp, @Nullable ItemStack icon) { super(island); this.superiorPlayer = superiorPlayer; this.islandWarp = islandWarp; this.icon = icon == null ? null : icon.clone(); } /** * Get the player that changed the icon of the warp. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp that its icon was changed. */ public IslandWarp getIslandWarp() { return islandWarp; } /** * Get the new icon of the warp. */ @Nullable public ItemStack getIcon() { return icon == null ? null : icon.clone(); } /** * Set the new icon for the warp. * If set to null, default icon will be set. * * @param icon The new icon to set. */ public void setIcon(@Nullable ItemStack icon) { this.icon = icon == null ? null : icon.clone(); } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpLocationEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.event.Cancellable; /** * IslandChangeWarpLocationEvent is called when the location of a warp was changed. */ public class IslandChangeWarpLocationEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final IslandWarp islandWarp; private Location location; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the location of the warp. * @param island The island of the warp. * @param islandWarp The warp that its location was changed. * @param location The new location of the warp. */ public IslandChangeWarpLocationEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp, Location location) { super(island); this.superiorPlayer = superiorPlayer; this.islandWarp = islandWarp; this.location = location.clone(); } /** * Get the player that changed the location of the warp. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp that its location was changed. */ public IslandWarp getIslandWarp() { return islandWarp; } /** * Get the new location of the warp. */ public Location getLocation() { return location.clone(); } /** * Set the new location for the warp. * * @param location The new location to set. */ public void setLocation(Location location) { Preconditions.checkNotNull(location, "Cannot set warp location to null."); Preconditions.checkNotNull(location.getWorld(), "location's world cannot be null."); Preconditions.checkState(island.isInsideRange(location), "Warp locations must be inside the island's area."); this.location = location.clone(); } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWarpsLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChangeWarpsLimitEvent is called when the warps limit of an island is changed. */ public class IslandChangeWarpsLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private int warpsLimit; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the warps limit of an island. * If set to null, it means the limit was changed via the console. * @param island The island that the warps limit was changed for. * @param warpsLimit The new warps limit of an island. */ public IslandChangeWarpsLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, int warpsLimit) { super(island); this.superiorPlayer = superiorPlayer; this.warpsLimit = warpsLimit; } /** * Get the player that changed the warps limit. * If null, it means the limit was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new warps limit of the island. */ public int getWarpsLimit() { return warpsLimit; } /** * Set the new warps limit of the island. * * @param warpsLimit The new warps limit to set. */ public void setWarpsLimit(int warpsLimit) { Preconditions.checkArgument(warpsLimit >= 0, "Cannot set the warps limit to a negative limit."); this.warpsLimit = warpsLimit; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChangeWorthBonusEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; import java.math.BigDecimal; /** * IslandChangeWorthBonusEvent is called when the worth-bonus of the island is changed. */ public class IslandChangeWorthBonusEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Reason reason; private BigDecimal worthBonus; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the worth bonus of the island. * If set to null, it means the bonus was changed by console. * @param island The island that the worth bonus was changed for. * @param reason The reason for changing the worth bonus. * @param worthBonus The new worth bonus of the island */ public IslandChangeWorthBonusEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Reason reason, BigDecimal worthBonus) { super(island); this.superiorPlayer = superiorPlayer; this.reason = reason; this.worthBonus = worthBonus; } /** * Get the player that changed the worth bonus. * If null, it means the bonus was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the reason for changing the worth bonus. */ public Reason getReason() { return reason; } /** * Get the new worth bonus of the island. */ public BigDecimal getWorthBonus() { return worthBonus; } /** * Set the new worth bonus for the island. * * @param worthBonus The new worth bonus to set. */ public void setWorthBonus(BigDecimal worthBonus) { Preconditions.checkNotNull(worthBonus, "Cannot set the worth bonus to null."); this.worthBonus = worthBonus; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } /** * The reason for changing the worth bonus. */ public enum Reason { /** * The worth bonus was changed due to a command by a player or console. */ COMMAND, /** * The worth bonus was changed due to schematic that was placed in the world for the island. */ SCHEMATIC } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChatEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandChatEvent is called when a player talks in islands chat. */ public class IslandChatEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private String message; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the player talks in. * @param superiorPlayer The player who sent the message. * @param message The message that was sent. */ public IslandChatEvent(Island island, SuperiorPlayer superiorPlayer, String message) { super(island); this.superiorPlayer = superiorPlayer; this.message = message; } /** * Get the player who banned the other player. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the message that the player sent. */ public String getMessage() { return message; } /** * Set a new message that will be sent. * * @param message The new message to send. */ public void setMessage(String message) { Preconditions.checkNotNull(message, "message parameter cannot be null."); Preconditions.checkArgument(!message.isEmpty(), "message cannot be empty."); this.message = message; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandChunkResetEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import org.bukkit.World; /** * IslandChunkResetEvent is called when a chunk is reset inside an island. */ public class IslandChunkResetEvent extends IslandEvent { private final World world; private final int chunkX; private final int chunkZ; /** * The constructor of the event. * * @param island The island that the chunk was reset in. * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ public IslandChunkResetEvent(Island island, World world, int chunkX, int chunkZ) { super(island); this.world = world; this.chunkX = chunkX; this.chunkZ = chunkZ; } /** * Get the world of the chunk. */ public World getWorld() { return world; } /** * Get the x-coords of the chunk. */ public int getChunkX() { return chunkX; } /** * Get the z-coords of the chunk. */ public int getChunkZ() { return chunkZ; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandClearFlagsEvent is called when flags are cleared on an island. */ public class IslandClearFlagsEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the flags were cleared in. * @param superiorPlayer The player that cleared the flags, or null if it was done by console. */ public IslandClearFlagsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player that cleared the flags to the island, or null if it was done by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearGeneratorRatesEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.World; import org.bukkit.event.Cancellable; /** * IslandClearGeneratorRatesEvent is called when clearing generator-rates of an island. */ public class IslandClearGeneratorRatesEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Dimension dimension; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that cleared the generator-rates of an island. * If set to null, it means the rates were cleared via the console. * @param island The island that the generator-rates were cleared for. * @param environment The environment of the world that the rates were cleared for. */ @Deprecated public IslandClearGeneratorRatesEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, World.Environment environment) { this(superiorPlayer, island, Dimension.getByName(environment.name())); } /** * The constructor of the event. * * @param superiorPlayer The player that cleared the generator-rates of an island. * If set to null, it means the rates were cleared via the console. * @param island The island that the generator-rates were cleared for. * @param dimension The dimension of the world that the rates were cleared for. */ public IslandClearGeneratorRatesEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Dimension dimension) { super(island); this.superiorPlayer = superiorPlayer; this.dimension = dimension; } /** * Get the player that cleared the generator-rates. * If null, it means the rates were cleared by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the environment of the world that the rates were cleared for. */ @Deprecated public World.Environment getEnvironment() { return this.dimension.getEnvironment(); } /** * Get the environment of the world that the rates were cleared for. */ public Dimension getDimension() { return this.dimension; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearPlayerPrivilegesEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandClearPlayerPrivilegesEvent is called when privileges of a player is cleared on an island. */ public class IslandClearPlayerPrivilegesEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final SuperiorPlayer privilegedPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the privileges were cleared in. * @param superiorPlayer The player that cleared the privileges to the other player. * @param privilegedPlayer The player that the privileges were cleared for. */ public IslandClearPlayerPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer privilegedPlayer) { super(island); this.superiorPlayer = superiorPlayer; this.privilegedPlayer = privilegedPlayer; } /** * Get the player that cleared the privileges to the other player. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the player that the privileges were cleared for. */ public SuperiorPlayer getPrivilegedPlayer() { return privilegedPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearRatingsEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandClearRatingsEvent is called when all ratings of an island are cleared. */ public class IslandClearRatingsEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that cleared the ratings of the island. * If null, the ratings were cleared by console. * @param island The island that was cleared from ratings. */ public IslandClearRatingsEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player that cleared the ratings of the island. * If null, the ratings were cleared by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearRolesPrivilegesEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandClearRolesPrivilegesEvent is called when privileges of roles are cleared on an island. */ public class IslandClearRolesPrivilegesEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the privileges were cleared in. * @param superiorPlayer The player that cleared the privileges, or null if it was done by console. */ public IslandClearRolesPrivilegesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player that cleared the privileges to the island, or null if it was done by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCloseEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandCloseEvent is called when the island is closed for visitors. */ public class IslandCloseEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that closed the island. * If null, then the island was opened by console. * @param island The island that was closed. */ public IslandCloseEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player that closed the island. * If null, then the island was opened by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCloseWarpEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandCloseWarpEvent is called when closing the warp to the public. */ public class IslandCloseWarpEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final IslandWarp islandWarp; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that closed the warp to the public. * @param island The island of the warp. * @param islandWarp The warp that was closed. */ public IslandCloseWarpEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) { super(island); this.superiorPlayer = superiorPlayer; this.islandWarp = islandWarp; } /** * Get the player that closed the warp to the public. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp that was closed. */ public IslandWarp getIslandWarp() { return islandWarp; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCoopPlayerEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandCoopPlayerEvent is called when a player is making another player coop on their island. */ public class IslandCoopPlayerEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer player; private final SuperiorPlayer target; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the leadership of it is transferred. * @param player The player who cooped the target. * @param target The player that will be cooped. */ public IslandCoopPlayerEvent(Island island, SuperiorPlayer player, SuperiorPlayer target) { super(island); this.player = player; this.target = target; } /** * Get the player who cooped the target. */ public SuperiorPlayer getPlayer() { return player; } /** * Get the player that will be cooped. */ public SuperiorPlayer getTarget() { return target; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandCreateEvent is called when a new island is created. */ public class IslandCreateEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final String schematic; private boolean teleport; private boolean cancelled = false; /** * The constructor for the event. * * @param superiorPlayer The player who created the island. * @param island The island object that was created. * @deprecated See IslandCreateEvent(SuperiorPlayer, Island, String) */ @Deprecated public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island) { this(superiorPlayer, island, ""); } /** * The constructor for the event. * * @param superiorPlayer The player who created the island. * @param island The island object that was created. * @param schematic The schematic that was used. */ public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island, String schematic) { this(superiorPlayer, island, schematic, true); } /** * The constructor for the event. * * @param superiorPlayer The player who created the island. * @param island The island object that was created. * @param schematic The schematic that was used. * @param teleport Whether the player should be teleported after creation. */ public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island, String schematic, boolean teleport) { super(island); this.superiorPlayer = superiorPlayer; this.schematic = schematic; this.teleport = teleport; } /** * Get the player who created the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the schematic that was used. */ public String getSchematic() { return schematic; } /** * Check if the player should get teleported when the process finishes. */ public boolean canTeleport() { return teleport; } /** * Set whether or not the player should be teleported to the island when the process finishes. */ public void setTeleport(boolean teleport) { this.teleport = teleport; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateWarpCategoryEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandCreateWarpCategoryEvent is called when a new warp-category is created on an island. */ public class IslandCreateWarpCategoryEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final String categoryName; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that created the warp-category. * @param island The island that the warp-category was created on. * @param categoryName The name of the new warp-category. */ public IslandCreateWarpCategoryEvent(SuperiorPlayer superiorPlayer, Island island, String categoryName) { super(island); this.superiorPlayer = superiorPlayer; this.categoryName = categoryName; } /** * Get the player that created the warp-category. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the name of the new warp-category. */ public String getCategoryName() { return categoryName; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateWarpEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import org.bukkit.event.Cancellable; /** * IslandCreateWarpEvent is called when a new warp is created on an island. */ public class IslandCreateWarpEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final String warpName; private final Location location; private final boolean openToPublic; @Nullable private final WarpCategory warpCategory; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that created the warp. * @param island The island that the warp was created on. * @param warpName The name of the new warp. * @param location The location of the new warp. * @param openToPublic Whether the island is open to the public. * @param warpCategory The category of the new warp. * If null, it means the warp will be added to the first found category; * if no category exists, new one will be created for the warp. */ public IslandCreateWarpEvent(SuperiorPlayer superiorPlayer, Island island, String warpName, Location location, boolean openToPublic, @Nullable WarpCategory warpCategory) { super(island); this.superiorPlayer = superiorPlayer; this.warpName = warpName; this.location = location.clone(); this.openToPublic = openToPublic; this.warpCategory = warpCategory; } /** * Get the player that created the warp. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the name of the new warp. */ public String getWarpName() { return warpName; } /** * Get the location of the new warp. */ public Location getLocation() { return location.clone(); } /** * Get whether the warp is opened to the public. */ public boolean isOpenToPublic() { return openToPublic; } /** * Get the category of the new warp. * If null, it means the warp will be added to the first found category; * if no category exists, new one will be created for the warp. */ @Nullable public WarpCategory getWarpCategory() { return warpCategory; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandDeleteWarpEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandDeleteWarpEvent is called when a warp is deleted from an island. */ public class IslandDeleteWarpEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final IslandWarp islandWarp; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that deleted the warp. * If null, then the warp was deleted by the console. * @param island The island that the warp was deleted from. * @param islandWarp The warp that was deleted. */ public IslandDeleteWarpEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) { super(island); this.superiorPlayer = superiorPlayer; this.islandWarp = islandWarp; } /** * Get the player that deleted the warp. * If null, then the warp was deleted by the console or not by a command. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp that was deleted. */ public IslandWarp getIslandWarp() { return islandWarp; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandDisableFlagEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandDisableFlagEvent is called when a flag is disabling for an island. */ public class IslandDisableFlagEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final IslandFlag islandFlag; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that disabled the island flag for the island. * If null, the flag was disabled by console. * @param island The island that the flag was disabled for. * @param islandFlag The flag that was disabled. */ public IslandDisableFlagEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandFlag islandFlag) { super(island); this.superiorPlayer = superiorPlayer; this.islandFlag = islandFlag; } /** * Get the player that disabled the island flag for the island. * If null, the flag was disabled by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the flag that was disabled. */ public IslandFlag getIslandFlag() { return islandFlag; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandDisbandEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandDisbandEvent is called when an island is disbanded. */ public class IslandDisbandEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor for the event. * * @param superiorPlayer The player who proceed the operation. * @param island The island that is being disbanded. */ public IslandDisbandEvent(SuperiorPlayer superiorPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player who proceed the operation. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEnableFlagEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandEnableFlagEvent is called when a flag is enabled for an island. */ public class IslandEnableFlagEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final IslandFlag islandFlag; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that enabled the island flag for the island. * If null, the flag was enabled by console. * @param island The island that the flag was enabled for. * @param islandFlag The flag that was enabled. */ public IslandEnableFlagEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandFlag islandFlag) { super(island); this.superiorPlayer = superiorPlayer; this.islandFlag = islandFlag; } /** * Get the player that enabled the island flag for the island. * If null, the flag was enabled by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the flag that was enabled. */ public IslandFlag getIslandFlag() { return islandFlag; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEnterEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import org.bukkit.event.Cancellable; /** * IslandEnterEvent is called when a player is walking into an island's area. */ public class IslandEnterEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final EnterCause enterCause; private boolean cancelled = false; private Location cancelTeleport = null; /** * The constructor of the event. * * @param superiorPlayer The player who entered to the island's area. * @param island The island that the player entered into. * @param enterCause The cause of entering into the island. */ public IslandEnterEvent(SuperiorPlayer superiorPlayer, Island island, EnterCause enterCause) { super(island); this.superiorPlayer = superiorPlayer; this.enterCause = enterCause; } /** * Get the player who entered to the island's area. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the cause of entering into the island. */ public EnterCause getCause() { return enterCause; } /** * Get the location the player would be teleported if the event is cancelled. */ public Location getCancelTeleport() { return cancelTeleport == null ? null : cancelTeleport.clone(); } /** * Set the location the player would be teleported if the event is cancelled. */ public void setCancelTeleport(Location cancelTeleport) { this.cancelTeleport = cancelTeleport.clone(); } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } /** * Used to determine the cause of entering. */ public enum EnterCause { PLAYER_MOVE, PLAYER_TELEPORT, PLAYER_JOIN, PORTAL, INVALID } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEnterPortalEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.event.Cancellable; /** * IslandEnterPortalEvent is called when a player enters a portal on an island. */ public class IslandEnterPortalEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final PortalType portalType; private Dimension destination; @Nullable private Schematic schematic; private boolean ignoreInvalidSchematic; private boolean cancelled = false; /** * Constructor of the event * * @param island The island that the player entered the portal at. * @param superiorPlayer The player that entered the portal. * @param portalType The type of the portal used. * @param destination The destination of the portal. * @param schematic The schematic to be placed, if exists. * @param ignoreInvalidSchematic Whether to ignore invalid schematics. */ @Deprecated public IslandEnterPortalEvent(Island island, SuperiorPlayer superiorPlayer, PortalType portalType, World.Environment destination, @Nullable Schematic schematic, boolean ignoreInvalidSchematic) { this(island, superiorPlayer, portalType, Dimension.getByName(destination.name()), schematic, ignoreInvalidSchematic); } /** * Constructor of the event * * @param island The island that the player entered the portal at. * @param superiorPlayer The player that entered the portal. * @param portalType The type of the portal used. * @param destination The destination of the portal. * @param schematic The schematic to be placed, if exists. * @param ignoreInvalidSchematic Whether to ignore invalid schematics. */ public IslandEnterPortalEvent(Island island, SuperiorPlayer superiorPlayer, PortalType portalType, Dimension destination, @Nullable Schematic schematic, boolean ignoreInvalidSchematic) { super(island); this.superiorPlayer = superiorPlayer; this.portalType = portalType; this.destination = destination; this.schematic = schematic; this.ignoreInvalidSchematic = ignoreInvalidSchematic; } /** * Get the player that entered the portal. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the type of the portal. */ public PortalType getPortalType() { return portalType; } /** * Get the destination world of the portal. */ @Deprecated public World.Environment getDestination() { return this.destination.getEnvironment(); } /** * Get the destination world of the portal. */ public Dimension getDestinationDimension() { return destination; } /** * Set the destination of the teleportation. * * @param destination The destination to set. */ @Deprecated public void setDestination(World.Environment destination) { this.setDestination(Dimension.getByName(destination.name())); } /** * Set the destination of the teleportation. * * @param destination The destination to set. */ public void setDestination(Dimension destination) { this.destination = destination; } /** * Get the schematic that will be placed before teleporting. * * @return The schematic that will be placed, or null if no schematic should be placed. */ @Nullable public Schematic getSchematic() { return schematic; } /** * Set the schematic that will be placed. * Warning: If a schematic was already been placed and you set this to non-null, a new schematic will be placed * on top of the already blocks. * * @param schematic The schematic to be placed. * If null, no schematic will be used and {@link #isIgnoreInvalidSchematic()} will be set to true. */ public void setSchematic(@Nullable Schematic schematic) { this.schematic = schematic; if (schematic == null) setIgnoreInvalidSchematic(true); } /** * Check whether the plugin should not send a warning if {@link #getSchematic()} is null. */ public boolean isIgnoreInvalidSchematic() { return ignoreInvalidSchematic; } /** * Set whether the plugin should send a warning to the player if {@link #getSchematic()} is null. * * @param ignoreInvalidSchematic Whether to send a warning or not. */ public void setIgnoreInvalidSchematic(boolean ignoreInvalidSchematic) { this.ignoreInvalidSchematic = ignoreInvalidSchematic; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEnterProtectedEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.HandlerList; /** * IslandEnterProtectedEvent is called when a player is walking into an island's protected area. * The protected area is the area that players can build in. */ public class IslandEnterProtectedEvent extends IslandEnterEvent { private static final HandlerList handlers = new HandlerList(); private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player who entered to the island's area. * @param island The island that the player entered into. * @param enterCause The cause of entering into the island. */ public IslandEnterProtectedEvent(SuperiorPlayer superiorPlayer, Island island, EnterCause enterCause) { super(superiorPlayer, island, enterCause); } public static HandlerList getHandlerList() { return handlers; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * All the island events extend IslandEvent. */ public abstract class IslandEvent extends Event { private static final HandlerList handlers = new HandlerList(); protected final Island island; /** * The constructor for the event. * * @param island The island object that was involved in the event. */ public IslandEvent(Island island) { super(!Bukkit.isPrimaryThread()); this.island = island; } public static HandlerList getHandlerList() { return handlers; } /** * Get the island that was involved in the event. */ public Island getIsland() { return island; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandGenerateBlockEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.event.Cancellable; /** * IslandGenerateBlockEvent is called when a cobblestone generator generates a block. */ public class IslandGenerateBlockEvent extends IslandEvent implements Cancellable { private final Location location; private Key block; private boolean placeBlock = true; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the block was generated in. * @param location The location of the generated block. * @param block The block that was generated. */ public IslandGenerateBlockEvent(Island island, Location location, Key block) { super(island); this.block = block; this.location = location.clone(); } /** * Get the location of the block. */ public Location getLocation() { return location.clone(); } /** * Get the block that was generated. */ public Key getBlock() { return block; } /** * Set the block to be generated. * * @param block The new block. */ public void setBlock(Key block) { Preconditions.checkNotNull(block, "Cannot set block to null."); this.block = block; } /** * Check whether the generated block should be set manually in the world. */ public boolean isPlaceBlock() { return placeBlock; } /** * Set whether the generated block should be set manually in the world. */ public void setPlaceBlock(boolean placeBlock) { this.placeBlock = placeBlock; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandHomeTeleportEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandHomeTeleportEvent is called when a player teleports to island home. */ public class IslandHomeTeleportEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final Dimension dimension; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the player teleports to. * @param superiorPlayer The player who teleports to the island home. * @param dimension The dimension that the player teleports to. */ public IslandHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) { super(island); this.superiorPlayer = superiorPlayer; this.dimension = dimension; } /** * Get the player who teleports to the island home. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the dimension that the player teleports to. */ public Dimension getDimension() { return this.dimension; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandInviteEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandInviteEvent is called when a player is invited to an island. */ public class IslandInviteEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final SuperiorPlayer targetPlayer; private boolean cancelled = false; /** * The constructor for the event. * * @param superiorPlayer The player who sent the invite request. * @param targetPlayer The player who received the invite request. * @param island The island that the player was invited into. */ public IslandInviteEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; this.targetPlayer = targetPlayer; } /** * Get the player who sent the invite request. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the player who received the invite request. */ public SuperiorPlayer getTarget() { return targetPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandJoinEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandJoinEvent is called when a player is joining an island as a member of that island. */ public class IslandJoinEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final Cause cause; private boolean cancelled = false; /** * The constructor to the event. * * @param superiorPlayer The player who joined the island as a new member. * @param island The island that the player joined into. * @deprecated See {@link #IslandJoinEvent(SuperiorPlayer, Island, Cause)} */ @Deprecated public IslandJoinEvent(SuperiorPlayer superiorPlayer, Island island) { this(superiorPlayer, island, Cause.INVITE); } /** * The constructor to the event. * * @param superiorPlayer The player who joined the island as a new member. * @param island The island that the player joined into. * @param cause The cause of joining the island. */ public IslandJoinEvent(SuperiorPlayer superiorPlayer, Island island, Cause cause) { super(island); this.superiorPlayer = superiorPlayer; this.cause = cause; } /** * Get the player who joined the island as a new member. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the cause of joining the island. */ public Cause getCause() { return cause; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } /** * The cause of joining an island. */ public enum Cause { /** * The player accepted an invitation to the island. */ INVITE, /** * The player was joined due to an admin, either by `/is admin add` or `/is admin join` */ ADMIN } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandKickEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandKickEvent is called when a player is kicked from his island. */ public class IslandKickEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final SuperiorPlayer targetPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player who kicked the other player. If null, it means console kicked the player. * @param targetPlayer The player that was kicked. * @param island The island that the player was kicked from. */ public IslandKickEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; this.targetPlayer = targetPlayer; } /** * Get the player who kicked the other player. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the player that was kicked. */ public SuperiorPlayer getTarget() { return targetPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandLeaveEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import org.bukkit.event.Cancellable; /** * IslandLeaveEvent is called when a player is walking out from the island's area. */ public class IslandLeaveEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final LeaveCause leaveCause; @Nullable private final Location toLocation; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player who left the island's area. * @param island The island that the player left. * @param leaveCause The cause of leaving the island. * @param toLocation The location the player will be at after leaving. */ public IslandLeaveEvent(SuperiorPlayer superiorPlayer, Island island, LeaveCause leaveCause, @Nullable Location toLocation) { super(island); this.superiorPlayer = superiorPlayer; this.leaveCause = leaveCause; this.toLocation = toLocation; } /** * Get the player who left the island's area. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the cause of leaving the island. */ public LeaveCause getCause() { return leaveCause; } /** * Get the location the player will be after he's leaving. * If the location is null, it means the player left the game. */ @Nullable public Location getTo() { return toLocation; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } /** * Used to determine the cause of leaving. */ public enum LeaveCause { PLAYER_MOVE, PLAYER_TELEPORT, PLAYER_QUIT, INVALID } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandLeaveProtectedEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import org.bukkit.event.HandlerList; /** * IslandLeaveProtectedEvent is called when a player is walking out from the island's protected area. * The protected area is the area that players can build in. */ public class IslandLeaveProtectedEvent extends IslandLeaveEvent { private static final HandlerList handlers = new HandlerList(); private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player who left the island's protected area. * @param island The island that the player left. * @param leaveCause The cause of leaving the island. * @param toLocation The location the player will be at after leaving. */ public IslandLeaveProtectedEvent(SuperiorPlayer superiorPlayer, Island island, LeaveCause leaveCause, Location toLocation) { super(superiorPlayer, island, leaveCause, toLocation); } public static HandlerList getHandlerList() { return handlers; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandLockWorldEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.World; import org.bukkit.event.Cancellable; /** * IslandLockWorldEvent is called when a world is locked to an island. */ public class IslandLockWorldEvent extends IslandEvent implements Cancellable { private final Dimension dimension; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the world was locked for. * @param environment The environment of the world that is locked. */ @Deprecated public IslandLockWorldEvent(Island island, World.Environment environment) { this(island, Dimension.getByName(environment.name())); } /** * The constructor of the event. * * @param island The island that the world was locked for. * @param dimension The dimension of the world that is locked. */ public IslandLockWorldEvent(Island island, Dimension dimension) { super(island); this.dimension = dimension; } /** * Get the environment of the world that is being locked. */ @Deprecated public World.Environment getEnvironment() { return this.dimension.getEnvironment(); } /** * Get the environment of the world that is being locked. */ public Dimension getDimension() { return this.dimension; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandOpenEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandOpenEvent is called when the island is opened for visitors. */ public class IslandOpenEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that opened the island. * If null, then the island was opened by console. * @param island The island that was opened. */ public IslandOpenEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player who locked the island. * If null, then the island was opened by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandOpenWarpEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandOpenWarpEvent is called when opening the warp to the public. */ public class IslandOpenWarpEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final IslandWarp islandWarp; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that opened the warp to the public. * @param island The island of the warp. * @param islandWarp The warp that was opened. */ public IslandOpenWarpEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) { super(island); this.superiorPlayer = superiorPlayer; this.islandWarp = islandWarp; } /** * Get the player that opened the warp to the public. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp that was opened. */ public IslandWarp getIslandWarp() { return islandWarp; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandQuitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandQuitEvent is called when a player is leaving their island. */ public class IslandQuitEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player who left their island. * @param island The island that the player left. */ public IslandQuitEvent(SuperiorPlayer superiorPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player who left their island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRateEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandRateEvent is called when a player rates an island. */ public class IslandRateEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final SuperiorPlayer ratingPlayer; private final Rating rating; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the rating of the other player. * If null, the rating was changed by console. * @param ratingPlayer The player that its rating was changed. * @param island The island that was rated. * @param rating The rating given to the island. */ public IslandRateEvent(@Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Island island, Rating rating) { super(island); this.superiorPlayer = superiorPlayer; this.ratingPlayer = ratingPlayer; this.rating = rating; } /** * Get the player that changed the rating of the other player. * If null, the rating was changed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the player that its rating was changed. */ public SuperiorPlayer getRatingPlayer() { return ratingPlayer; } /** * Get the rating given to the island. */ public Rating getRating() { return rating; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveBlockLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandRemoveBlockLimitEvent is called when a block-limit of an island is removed. */ public class IslandRemoveBlockLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Key block; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that removed the block limit of an island. * If set to null, it means the limit was removed via the console. * @param island The island that the block limit was removed for. * @param block The block that the limit was removed for. */ public IslandRemoveBlockLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block) { super(island); this.superiorPlayer = superiorPlayer; this.block = block; } /** * Get the player that removed the block limit. * If null, it means the limit was removed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the block that the limit was removed for. */ public Key getBlock() { return block; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveEffectEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; import org.bukkit.potion.PotionEffectType; /** * IslandRemoveEffectLevelEvent is called when an effect of an island is removed. */ public class IslandRemoveEffectEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final PotionEffectType effectType; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that removed the effect level of an island. * If set to null, it means the effect was removed via the console. * @param island The island that the effect level was removed for. * @param effectType The effect that was removed from the island. */ public IslandRemoveEffectEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, PotionEffectType effectType) { super(island); this.superiorPlayer = superiorPlayer; this.effectType = effectType; } /** * Get the player that removed the effect level. * If null, it means the effect was removed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the effect that was removed from the island. */ public PotionEffectType getEffectType() { return effectType; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveEntityLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandRemoveEntityLimitEvent is called when an entity-limit of an island is removed. */ public class IslandRemoveEntityLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Key entity; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that removed the entity limit of an island. * If set to null, it means the limit was removed via the console. * @param island The island that the entity limit was removed for. * @param entity The entity that the limit was removed for. */ public IslandRemoveEntityLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key entity) { super(island); this.superiorPlayer = superiorPlayer; this.entity = entity; } /** * Get the player that removed the entity limit. * If null, it means the limit was removed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the entity that the limit was removed for. */ public Key getEntity() { return entity; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveGeneratorRateEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.World; import org.bukkit.event.Cancellable; /** * IslandRemoveGeneratorRateEvent is called when a generator-rate of an island is removed. */ public class IslandRemoveGeneratorRateEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Key block; private final Dimension dimension; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that removed the generator-rate of an island. * If set to null, it means the rate was removed via the console. * @param island The island that the generator-rate was removed for. * @param block The block that the rate was removed for. * @param environment The environment of the world that the rate was removed for. */ @Deprecated public IslandRemoveGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block, World.Environment environment) { this(superiorPlayer, island, block, Dimension.getByName(environment.name())); } /** * The constructor of the event. * * @param superiorPlayer The player that removed the generator-rate of an island. * If set to null, it means the rate was removed via the console. * @param island The island that the generator-rate was removed for. * @param block The block that the rate was removed for. * @param dimension The dimension of the world that the rate was removed for. */ public IslandRemoveGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block, Dimension dimension) { super(island); this.superiorPlayer = superiorPlayer; this.block = block; this.dimension = dimension; } /** * Get the player that removed the generator-rate. * If null, it means the level was removed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the block that the generator-rate was removed for. */ public Key getBlock() { return block; } /** * Get the environment of the world that the rate was removed for. */ @Deprecated public World.Environment getEnvironment() { return this.dimension.getEnvironment(); } /** * Get the environment of the world that the rate was removed for. */ public Dimension getDimension() { return dimension; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveRatingEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandRemoveRatingEvent is called when a rating of a player is removed from an island. */ public class IslandRemoveRatingEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final SuperiorPlayer ratingPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that removed the rating of the other player. * If null, the rating was removed by console. * @param ratingPlayer The player that its rating was removed. * @param island The island that was rated. */ public IslandRemoveRatingEvent(@Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; this.ratingPlayer = ratingPlayer; } /** * Get the player that removed the rating of the other player. * If null, the rating was removed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the player that its rating was removed. */ public SuperiorPlayer getRatingPlayer() { return ratingPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveRoleLimitEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandRemoveRoleLimitEvent is called when a role-limit of an island is removed. */ public class IslandRemoveRoleLimitEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final PlayerRole playerRole; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that removed a role-limit from an island. * If set to null, it means the limit was removed via the console. * @param island The island that the role-limit was removed from. * @param playerRole The role that its limit was removed. */ public IslandRemoveRoleLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, PlayerRole playerRole) { super(island); this.superiorPlayer = superiorPlayer; this.playerRole = playerRole; } /** * Get the player that removed the role-limit. * If null, it means the limit was removed by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the role that its limit was removed. */ public PlayerRole getPlayerRole() { return playerRole; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveVisitorHomeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandRemoveVisitorHomeEvent is called when the visitor home of the island is removed. */ public class IslandRemoveVisitorHomeEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that removed the island visitor home. * If null, then the warp was deleted by the console or another source * @param island The island that the visitor home was removed. */ public IslandRemoveVisitorHomeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player who removed the island visitor home. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRenameEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandRenameEvent is called when an island changes its name. */ public class IslandRenameEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private String islandName; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that was renamed. * @param superiorPlayer The player that renamed the island. * If null, the island was renamed by console. * @param islandName The new name of the island. */ public IslandRenameEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String islandName) { super(island); this.superiorPlayer = superiorPlayer; this.islandName = islandName; } /** * Get the player that changed the privilege to the other player. * If null, the privilege was changed by the console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new name of the island. */ public String getIslandName() { return islandName; } /** * Set the new name of the island. * * @param islandName The new name to set. */ public void setIslandName(String islandName) { Preconditions.checkNotNull(islandName, "Island names cannot be null."); this.islandName = islandName; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRenameWarpCategoryEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandRenameWarpCategoryEvent is called when renaming a warp-category. */ public class IslandRenameWarpCategoryEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final WarpCategory warpCategory; private String categoryName; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that renamed the warp-category. * @param island The island of the warp-category. * @param warpCategory The warp-category that was renamed. * @param categoryName The new name of the warp-category. */ public IslandRenameWarpCategoryEvent(SuperiorPlayer superiorPlayer, Island island, WarpCategory warpCategory, String categoryName) { super(island); this.superiorPlayer = superiorPlayer; this.warpCategory = warpCategory; this.categoryName = categoryName; } /** * Get the player that renamed the warp-category. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp-category that was renamed. */ public WarpCategory getWarpCategory() { return warpCategory; } /** * Get the new name of the warp-category. */ public String getCategoryName() { return categoryName; } /** * Set the new name for the warp-category. * * @param categoryName The new warp-category name to set. */ public void setCategoryName(String categoryName) { Preconditions.checkNotNull(categoryName, "Cannot set warp-category name to null."); Preconditions.checkArgument(categoryName.length() <= 255, "Category names cannot be longer than 255 chars."); Preconditions.checkState(island.getWarpCategory(categoryName) == null, "Cannot rename warp-categories to an already existing categories."); this.categoryName = categoryName; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRenameWarpEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; /** * IslandRenameWarpEvent is called when renaming a warp. */ public class IslandRenameWarpEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final IslandWarp islandWarp; private String warpName; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that renamed the warp. * @param island The island of the warp. * @param islandWarp The warp that was renamed. * @param warpName The new name of the warp. */ public IslandRenameWarpEvent(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp, String warpName) { super(island); this.superiorPlayer = superiorPlayer; this.islandWarp = islandWarp; this.warpName = warpName; } /** * Get the player that renamed the warp. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the warp that was renamed. */ public IslandWarp getIslandWarp() { return islandWarp; } /** * Get the new name of the warp. */ public String getWarpName() { return warpName; } /** * Set the new name for the warp. * * @param warpName The new warp name to set. */ public void setWarpName(String warpName) { Preconditions.checkNotNull(warpName, "Cannot set warp name to null."); Preconditions.checkArgument(warpName.length() <= 255, "Warp names cannot be longer than 255 chars."); Preconditions.checkState(island.getWarp(warpName) == null, "Cannot rename warps to an already existing warps."); this.warpName = warpName; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRestrictMoveEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * IslandRestrictMoveEvent is called when a player is cancelled from moving by the plugin. */ public class IslandRestrictMoveEvent extends Event { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final RestrictReason restrictReason; /** * The constructor for the event. * * @param superiorPlayer The player which was restricted. * @param restrictReason The reason for the restriction. */ public IslandRestrictMoveEvent(SuperiorPlayer superiorPlayer, RestrictReason restrictReason) { this.superiorPlayer = superiorPlayer; this.restrictReason = restrictReason; } public static HandlerList getHandlerList() { return handlers; } /** * Get the player which was restricted. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the reason for the restriction. */ public RestrictReason getRestrictReason() { return restrictReason; } @Override public HandlerList getHandlers() { return handlers; } public enum RestrictReason { LEAVE_ISLAND_TO_OUTSIDE, LEAVE_PROTECTED_EVENT_CANCELLED, LEAVE_EVENT_CANCELLED, BANNED_FROM_ISLAND, LOCKED_ISLAND, ENTER_PROTECTED_EVENT_CANCELLED, ENTER_EVENT_CANCELLED, } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandSchematicPasteEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import org.bukkit.Location; /** * IslandSchematicPasteEvent is called when a schematic is placed. */ public class IslandSchematicPasteEvent extends IslandEvent { private final String schematic; private final Location location; /** * The constructor for the event. * * @param island The island object that was created. * @param schematic The schematic that was used. * @param location The location the schematic was pasted at. */ public IslandSchematicPasteEvent(Island island, String schematic, Location location) { super(island); this.schematic = schematic; this.location = location.clone(); } /** * Get the schematic that was used. */ public String getSchematic() { return schematic; } /** * Get the location that the schematic was pasted at. */ public Location getLocation() { return location; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandSetHomeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.event.Cancellable; /** * IslandSetHomeEvent is called when a new home is set to the island. */ public class IslandSetHomeEvent extends IslandEvent implements Cancellable { private final Reason reason; @Nullable private final SuperiorPlayer superiorPlayer; private Location islandHome; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the home was changed for. * @param islandHome The new island home of the island. * @param reason The reason the home was changed. * @param superiorPlayer The player that changed the island home, if exists */ public IslandSetHomeEvent(Island island, Location islandHome, Reason reason, @Nullable SuperiorPlayer superiorPlayer) { super(island); this.islandHome = islandHome.clone(); this.reason = reason; this.superiorPlayer = superiorPlayer; } /** * Get the new island home location of the island. */ public Location getIslandHome() { return islandHome.clone(); } /** * Set the new home location of the island. * * @param islandHome The home location for the island. */ public void setIslandHome(Location islandHome) { Preconditions.checkNotNull(islandHome.getWorld(), "Cannot set island home with null world"); this.islandHome = islandHome.clone(); } /** * Get the reason the home was changed. */ public Reason getReason() { return reason; } /** * Get the player who changed the island home, if exists. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } /** * The reason the home was changed. */ public enum Reason { /** * The home was changed through a command. */ SET_HOME_COMMAND, /** * The home was changed because the old home was not safe. */ SAFE_HOME } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandSetVisitorHomeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.event.Cancellable; /** * IslandSetVisitorHomeEvent is called when a new visitor home is set to the island. */ public class IslandSetVisitorHomeEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private Location islandVisitorHome; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the island visitor home. * @param island The island that the visitor home was changed for. * @param islandVisitorHome The new island visitor home of the island. */ public IslandSetVisitorHomeEvent(SuperiorPlayer superiorPlayer, Island island, Location islandVisitorHome) { super(island); this.islandVisitorHome = islandVisitorHome.clone(); this.superiorPlayer = superiorPlayer; } /** * Get the player who changed the island home, if exists. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new island visitor home location of the island. */ public Location getIslandVisitorHome() { return islandVisitorHome.clone(); } /** * Set the new visitor home location of the island. * Setting the visitor home location outside the island's area may lead to undefined behaviors. * * @param islandVisitorHome The new home visitor location for the island. */ public void setIslandHome(Location islandVisitorHome) { Preconditions.checkNotNull(islandVisitorHome.getWorld(), "Cannot set island visitor home with null world"); this.islandVisitorHome = islandVisitorHome.clone(); } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandTransferEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandTransferEvent is called when the leadership of an island is transferred. */ public class IslandTransferEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer oldOwner; private final SuperiorPlayer newOwner; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the leadership of it is transferred. * @param oldOwner The old owner of the island. * @param newOwner The new owner of the island. */ public IslandTransferEvent(Island island, SuperiorPlayer oldOwner, SuperiorPlayer newOwner) { super(island); this.oldOwner = oldOwner; this.newOwner = newOwner; } /** * Get the old owner of the island. */ public SuperiorPlayer getOldOwner() { return oldOwner; } /** * Get the new owner of the island. */ public SuperiorPlayer getNewOwner() { return newOwner; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandUnbanEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandUnbanEvent is called when a player is unbanned from his island. */ public class IslandUnbanEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final SuperiorPlayer targetPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player who unbanned the other player. * @param targetPlayer The player that was unbanned. * @param island The island that the player was unbanned from. */ public IslandUnbanEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; this.targetPlayer = targetPlayer; } /** * Get the player who unbanned the other player. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the player that was unbanned. */ public SuperiorPlayer getUnbannedPlayer() { return targetPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandUncoopPlayerEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandUncoopPlayerEvent is called when a player is making another player no longer coop on their island. */ public class IslandUncoopPlayerEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer player; private final SuperiorPlayer target; private final UncoopReason uncoopReason; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the leadership of it is transferred. * @param player The player who cooped the target, if exists. * @param target The player that will no longer be coop. * @param uncoopReason The reason for the action. */ public IslandUncoopPlayerEvent(Island island, @Nullable SuperiorPlayer player, SuperiorPlayer target, UncoopReason uncoopReason) { super(island); this.player = player; this.target = target; this.uncoopReason = uncoopReason; } /** * Get the player who cooped the target, if exists. */ @Nullable public SuperiorPlayer getPlayer() { return player; } /** * Get the player that will no longer be coop. */ public SuperiorPlayer getTarget() { return target; } /** * Get the reason for the action. */ public UncoopReason getUncoopReason() { return uncoopReason; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } public enum UncoopReason { PLAYER, SERVER_LEAVE } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandUnlockWorldEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.World; import org.bukkit.event.Cancellable; /** * IslandUnlockWorldEvent is called when a world is unlocked to an island. */ public class IslandUnlockWorldEvent extends IslandEvent implements Cancellable { private final Dimension dimension; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the world was unlocked for. * @param environment The environment of the world that is unlocked. */ @Deprecated public IslandUnlockWorldEvent(Island island, World.Environment environment) { this(island, Dimension.getByName(environment.name())); } /** * The constructor of the event. * * @param island The island that the world was unlocked for. * @param dimension The dimension of the world that is unlocked. */ public IslandUnlockWorldEvent(Island island, Dimension dimension) { super(island); this.dimension = dimension; } /** * Get the environment of the world that is being unlocked. */ @Deprecated public World.Environment getEnvironment() { return this.dimension.getEnvironment(); } /** * Get the dimension of the world that is being unlocked. */ public Dimension getDimension() { return this.dimension; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandUpgradeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.event.Cancellable; import java.math.BigDecimal; import java.util.LinkedList; import java.util.List; /** * IslandCreateEvent is called when a new island is created. */ public class IslandUpgradeEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Upgrade upgrade; private final UpgradeLevel upgradeLevel; private final List commands; private final Cause cause; @Nullable private UpgradeCost upgradeCost; private boolean cancelled = false; /** * The constructor for the event. * * @param superiorPlayer The player who upgraded the island. Can be null if ran by the console. * @param island The island that was upgraded. * @param upgradeName The name of the upgrade. * @param commands The commands that will be ran upon upgrade. * @param upgradeCost The cost of the upgrade * @deprecated See {@link #IslandUpgradeEvent(SuperiorPlayer, Island, Upgrade, UpgradeLevel, List, Cause, UpgradeCost)} */ @Deprecated public IslandUpgradeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, String upgradeName, List commands, @Nullable UpgradeCost upgradeCost) { super(island); Upgrade upgrade = SuperiorSkyblockAPI.getUpgrades().getUpgrade(upgradeName); this.superiorPlayer = superiorPlayer; this.upgrade = Preconditions.checkNotNull(upgrade, "upgrade cannot be null"); this.upgradeLevel = Preconditions.checkNotNull(island.getUpgradeLevel(upgrade), "upgradeLevel cannot be null"); this.commands = new LinkedList<>(Preconditions.checkNotNull(commands, "commands cannot be null")); this.cause = Cause.UNKONWN; this.upgradeCost = upgradeCost; } /** * The constructor for the event. * * @param superiorPlayer The player who upgraded the island. * Can be null if ran by the console. * @param island The island that was upgraded. * @param upgrade The upgrade. * @param upgradeLevel The level that will be upgraded into. * @param commands The commands that will be running upon upgrade. * @param upgradeCost The cost of the upgrade. * If null, there was no cost for the upgrade (For example, setupgrade command). */ @Deprecated public IslandUpgradeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Upgrade upgrade, UpgradeLevel upgradeLevel, List commands, @Nullable UpgradeCost upgradeCost) { this(superiorPlayer, island, upgrade, upgradeLevel, commands, Cause.UNKONWN, upgradeCost); } /** * The constructor for the event. * * @param superiorPlayer The player who upgraded the island. * Can be null if ran by the console. * @param island The island that was upgraded. * @param upgrade The upgrade. * @param upgradeLevel The level that will be upgraded into. * @param commands The commands that will be running upon upgrade. * @param upgradeCost The cost of the upgrade. * If null, there was no cost for the upgrade (For example, setupgrade command). * @param cause The cause of the upgrade. */ public IslandUpgradeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Upgrade upgrade, UpgradeLevel upgradeLevel, List commands, Cause cause, @Nullable UpgradeCost upgradeCost) { super(island); this.superiorPlayer = superiorPlayer; this.upgrade = Preconditions.checkNotNull(upgrade, "upgrade cannot be null"); this.upgradeLevel = Preconditions.checkNotNull(upgradeLevel, "upgradeLevel cannot be null"); this.commands = new LinkedList<>(Preconditions.checkNotNull(commands, "commands cannot be null")); this.cause = Preconditions.checkNotNull(cause, "cause cannot be null"); this.upgradeCost = upgradeCost; } /** * Get the player who upgraded the island. * Can be null if ran by the console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the name of the upgrade. */ public String getUpgradeName() { return upgrade.getName(); } /** * Get the name of the upgrade. */ public Upgrade getUpgrade() { return upgrade; } /** * Get the level that will be upgraded to. */ public UpgradeLevel getUpgradeLevel() { return upgradeLevel; } /** * Get the commands that will be ran upon upgrade. */ public List getCommands() { return commands; } /** * Get the cause of this event. */ public Cause getCause() { return cause; } /** * Get the upgrade cost that is used. */ @Nullable public UpgradeCost getUpgradeCost() { return upgradeCost; } /** * Set a new upgrade cost to be used. * * @param upgradeCost The new upgrade cost. */ public void setUpgradeCost(@Nullable UpgradeCost upgradeCost) { this.upgradeCost = upgradeCost; } /** * Get the amount that will be withdrawn. * * @deprecated See getCost() */ @Deprecated public double getAmountToWithdraw() { return getCost().doubleValue(); } /** * Set the amount that will be withdrawn. * * @deprecated See setCost(BigDecimal) */ @Deprecated public void setAmountToWithdraw(double amountToWithdraw) { setCost(BigDecimal.valueOf(amountToWithdraw)); } /** * Get the amount that will be withdrawn. */ public BigDecimal getCost() { return upgradeCost == null ? BigDecimal.ZERO : upgradeCost.getCost(); } /** * Set the amount that will be withdrawn. * * @param cost The new amount to be withdrawn. * @throws IllegalStateException If the upgradeCost is null. Use {@link #setUpgradeCost(UpgradeCost)} instead. */ public void setCost(BigDecimal cost) throws IllegalStateException { if (this.upgradeCost == null) throw new IllegalStateException("Cannot set raw cost when upgradeCost is null."); setUpgradeCost(this.upgradeCost.clone(cost)); } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } public enum Cause { /** * Used when player runs '/is rankup'. */ PLAYER_RANKUP, /** * Used when player or console runs '/is admin rankup'. */ ADMIN_RANKUP, /** * Used when an admin or console runs '/is admin setupgrade' */ ADMIN_SET_UPGRADE, /** * Used only for deprecated usage of the old constructors. */ @Deprecated UNKONWN } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandVisitorHomeTeleportEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandVisitorHomeTeleportEvent is called when a player teleports to island visitor home. */ public class IslandVisitorHomeTeleportEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final Dimension dimension; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the player teleports to. * @param superiorPlayer The player who teleports to the island visitor home. * @param dimension The dimension that the player teleports to. */ public IslandVisitorHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) { super(island); this.superiorPlayer = superiorPlayer; this.dimension = dimension; } /** * Get the player who teleports to the island visitor home. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the dimension that the player teleports to. */ public Dimension getDimension() { return this.dimension; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; /** * IslandWarpTeleportEvent is called when a player teleports to island warp. */ public class IslandWarpTeleportEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final IslandWarp islandWarp; private boolean cancelled = false; /** * The constructor of the event. * * @param island The island that the player teleports to. * @param superiorPlayer The player who teleports to the island warp. * @param islandWarp The island warp that the player teleports to. */ public IslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { super(island); this.superiorPlayer = superiorPlayer; this.islandWarp = islandWarp; } /** * Get the player who teleports to the island warp. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the island warp that the player teleports to. */ public IslandWarp getIslandWarp() { return this.islandWarp; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWorldResetEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.World; import org.bukkit.event.Cancellable; /** * IslandWorldResetEvent is called when a world is reset of an island. */ public class IslandWorldResetEvent extends IslandEvent implements Cancellable { @Nullable private final SuperiorPlayer superiorPlayer; private final Dimension dimension; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that reset the world of the island. * If null, the world was reset by console. * @param island The island that the world was reset for. * @param environment The environment of the world that was reset. */ @Deprecated public IslandWorldResetEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, World.Environment environment) { this(superiorPlayer, island, Dimension.getByName(environment.name())); } /** * The constructor of the event. * * @param superiorPlayer The player that reset the world of the island. * If null, the world was reset by console. * @param island The island that the world was reset for. * @param dimension The dimension of the world that was reset. */ public IslandWorldResetEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Dimension dimension) { super(island); this.superiorPlayer = superiorPlayer; this.dimension = dimension; } /** * Get the player that reset the world of the island. * If null, the world was reset by console. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the environment of the world that was reset. */ @Deprecated public World.Environment getEnvironment() { return this.dimension.getEnvironment(); } /** * Get the environment of the world that was reset. */ public Dimension getDimension() { return this.dimension; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWorthCalculatedEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.math.BigDecimal; /** * IslandWorthCalculatedEvent is called when the worth of an island is calculated. */ public class IslandWorthCalculatedEvent extends IslandEvent { private final BigDecimal level; private final BigDecimal worth; @Nullable private final SuperiorPlayer player; /** * The constructor of the event. * * @param island The island that it's worth was calculated. * @param player The player who requested the operation (may be null). * @param level The new level of the island. * @param worth The new worth value of the island. */ public IslandWorthCalculatedEvent(Island island, @Nullable SuperiorPlayer player, BigDecimal level, BigDecimal worth) { super(island); this.player = player; this.level = level; this.worth = worth; } /** * Get the player who requested the operation. * Can be null if the console called the operation. */ @Nullable public SuperiorPlayer getPlayer() { return player; } /** * Get the new level of the island. */ public BigDecimal getLevel() { return level; } /** * Get the new worth value of the island. */ public BigDecimal getWorth() { return worth; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWorthUpdateEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import java.math.BigDecimal; /** * IslandWorthUpdateEvent is called when the worth of the island is updated. */ public class IslandWorthUpdateEvent extends IslandEvent { private final BigDecimal oldWorth; private final BigDecimal oldLevel; private final BigDecimal newWorth; private final BigDecimal newLevel; /** * The constructor of the event. * * @param island The island that the leadership of it is transferred. * @param oldWorth The old worth of the island. * @param oldLevel The old level of the island. * @param newWorth The new worth of the island. * @param newLevel The new level of the island. */ public IslandWorthUpdateEvent(Island island, BigDecimal oldWorth, BigDecimal oldLevel, BigDecimal newWorth, BigDecimal newLevel) { super(island); this.oldWorth = oldWorth; this.oldLevel = oldLevel; this.newWorth = newWorth; this.newLevel = newLevel; } /** * Get the old worth of the island. */ public BigDecimal getOldWorth() { return oldWorth; } /** * Get the old level of the island. */ public BigDecimal getOldLevel() { return oldLevel; } /** * Get the new worth of the island. */ public BigDecimal getNewWorth() { return newWorth; } /** * Get the new level of the island. */ public BigDecimal getNewLevel() { return newLevel; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/MissionCompleteEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; import java.util.List; /** * MissionCompleteEvent is called when a player is completing a mission. */ public class MissionCompleteEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final IMissionsHolder missionsHolder; private final Mission mission; private final List itemRewards; private final List commandRewards; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player who completed the mission. * @param mission The mission that was completed. * @param islandMission Flag that determines whether or not the mission is an island mission. * @param itemRewards The list of items that will be given as a reward. * @param commandRewards The list of commands that will be ran as a reward. */ @Deprecated public MissionCompleteEvent(SuperiorPlayer superiorPlayer, Mission mission, boolean islandMission, List itemRewards, List commandRewards) { this(superiorPlayer, islandMission ? superiorPlayer.getIsland() : superiorPlayer, mission, itemRewards, commandRewards); } public MissionCompleteEvent(SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, Mission mission, List itemRewards, List commandRewards) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; this.missionsHolder = missionsHolder; this.mission = mission; this.itemRewards = itemRewards; this.commandRewards = commandRewards; } /** * Get the player who completed the mission. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the mission holder that the mission was completed for. */ public IMissionsHolder getMissionsHolder() { return missionsHolder; } /** * Get the mission that was completed. */ public Mission getMission() { return mission; } /** * Get the list of items that will be given as a reward. */ public List getItemRewards() { return itemRewards; } /** * Get the list of commands that will be given as a reward. */ public List getCommandRewards() { return commandRewards; } /** * Check whether the mission is an island mission. */ public boolean isIslandMission() { return mission.getIslandMission(); } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/MissionResetEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * MissionResetEvent is called when a mission is reset. * After the event is executed, the holder may still have the mission completed if the times the holder completed * the mission was above 1. */ public class MissionResetEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); @Nullable private final SuperiorPlayer superiorPlayer; private final IMissionsHolder missionsHolder; private final Mission mission; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that reset the mission. * If null, the mission was reset by console. * @param missionsHolder The holder of the mission that the mission was reset for. * @param mission The mission that was reset. */ public MissionResetEvent(@Nullable SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, Mission mission) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; this.missionsHolder = missionsHolder; this.mission = mission; } /** * Get the player who reset the mission for the holder. */ @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the holder of the mission that the mission was reset for. */ public IMissionsHolder getMissionsHolder() { return missionsHolder; } /** * Get the mission that was reset. */ public Mission getMission() { return mission; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerChangeBorderColorEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerChangeBorderColorEvent is called when a player changes the color of the world border. */ public class PlayerChangeBorderColorEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final BorderColor borderColor; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the border color. * @param borderColor The new border color of the player. */ public PlayerChangeBorderColorEvent(SuperiorPlayer superiorPlayer, BorderColor borderColor) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; this.borderColor = borderColor; } /** * Get the player who created the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new border color of the player. */ public BorderColor getBorderColor() { return borderColor; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerChangeLanguageEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import java.util.Locale; /** * PlayerChangeLanguageEvent is called when a player has its language changed. */ public class PlayerChangeLanguageEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final Locale language; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that changed the language. * @param language The new language of the player. */ public PlayerChangeLanguageEvent(SuperiorPlayer superiorPlayer, Locale language) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; this.language = language; } /** * Get the player who created the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new language of the player. */ public Locale getLanguage() { return language; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerChangeNameEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerChangeNameEvent is called when a player has his name changed. */ public class PlayerChangeNameEvent extends Event { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final String newName; /** * The constructor of the event. * * @param superiorPlayer The player that had his name changed. * @param newName The new name of the player. */ public PlayerChangeNameEvent(SuperiorPlayer superiorPlayer, String newName) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; this.newName = newName; } /** * Get the player that had his name changed. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new name of the player. */ public String getNewName() { return newName; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerChangeRoleEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerChangeRoleEvent is called when a player has its role changed. */ public class PlayerChangeRoleEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final PlayerRole newRole; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player. * @param newRole The new role for the player. */ public PlayerChangeRoleEvent(SuperiorPlayer superiorPlayer, PlayerRole newRole) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; this.newRole = newRole; } public static HandlerList getHandlerList() { return handlers; } /** * Get the player who created the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the new role of the player. */ public PlayerRole getNewRole() { return newRole; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerCloseMenuEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerCloseMenuEvent is called when a player closes a menu. */ public class PlayerCloseMenuEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final MenuView openedMenuView; @Nullable private MenuView newMenuView; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that closed the menu. * @param superiorMenu The menu that was closed. * @param newMenu The new menu that will be opened. * If null, no menu will be opened. * @deprecated See {@link #PlayerCloseMenuEvent(SuperiorPlayer, MenuView, MenuView)} */ @Deprecated public PlayerCloseMenuEvent(SuperiorPlayer superiorPlayer, ISuperiorMenu superiorMenu, @Nullable ISuperiorMenu newMenu) { this(superiorPlayer, (MenuView) superiorMenu, newMenu); } /** * The constructor of the event. * * @param superiorPlayer The player that closed the menu. * @param openedMenuView The menu view that is opened for the player. * @param newMenuView The new menu view that will be opened. * If null, no menu will be opened. */ public PlayerCloseMenuEvent(SuperiorPlayer superiorPlayer, MenuView openedMenuView, @Nullable MenuView newMenuView) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; this.openedMenuView = openedMenuView; this.newMenuView = newMenuView; } /** * Get the player that opened the menu. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the menu that was opened by the player. * * @deprecated See {@link #getOpenedMenuView()} */ @Deprecated public ISuperiorMenu getSuperiorMenu() { return ISuperiorMenu.convertFromView(this.getOpenedMenuView()); } /** * Get the menu view that is opened for the player. */ public MenuView getOpenedMenuView() { return this.openedMenuView; } /** * Get the new menu that will be opened. * If null, no menu will be opened. * * @deprecated See {@link #getNewMenuView()} */ @Nullable @Deprecated public ISuperiorMenu getNewMenu() { return ISuperiorMenu.convertFromView(this.getNewMenuView()); } /** * Get the new menu view that will be opened. * If null, no menu will be opened. */ @Nullable public MenuView getNewMenuView() { return this.newMenuView; } /** * Set the new menu that will be opened. * * @param newMenu The new menu that will be opened. * If null, no menu will be opened. * @deprecated See {@link #setNewMenuView(MenuView)} */ @Deprecated public void setNewMenu(@Nullable ISuperiorMenu newMenu) { this.setNewMenuView(newMenu); } /** * Set the new menu view that will be opened. * * @param newMenuView The new menu that will be opened. * If null, no menu will be opened. */ public void setNewMenuView(@Nullable MenuView newMenuView) { this.newMenuView = newMenuView; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerOpenMenuEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerOpenMenuEvent is called when a player opens a menu. */ public class PlayerOpenMenuEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final MenuView menuView; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that opened the menu. * @param superiorMenu The menu that was opened * @deprecated See {@link #PlayerOpenMenuEvent(SuperiorPlayer, MenuView)} */ @Deprecated public PlayerOpenMenuEvent(SuperiorPlayer superiorPlayer, ISuperiorMenu superiorMenu) { this(superiorPlayer, (MenuView) superiorMenu); } /** * The constructor of the event. * * @param superiorPlayer The player that opened the menu. * @param menuView The menu that was opened */ public PlayerOpenMenuEvent(SuperiorPlayer superiorPlayer, MenuView menuView) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; this.menuView = menuView; } /** * Get the player that opened the menu. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the menu that was opened by the player. * * @deprecated See {@link #getMenuView()} */ @Deprecated public ISuperiorMenu getSuperiorMenu() { return ISuperiorMenu.convertFromView(menuView); } /** * Get the menu view that was opened by the player. */ public MenuView getMenuView() { return menuView; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerReplaceEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerReplaceEvent is called when a player changes his uuid and replaced with another one. */ public class PlayerReplaceEvent extends Event { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer oldPlayer; private final SuperiorPlayer newPlayer; /** * The constructor of the event. * * @param oldPlayer The old player that had his UUID changed. * @param newPlayer The new player that has the new UUID. */ public PlayerReplaceEvent(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) { super(!Bukkit.isPrimaryThread()); this.oldPlayer = oldPlayer; this.newPlayer = newPlayer; } /** * Get the old player that had his UUID changed. */ public SuperiorPlayer getOldPlayer() { return oldPlayer; } /** * Get the new player that has the new UUID. */ public SuperiorPlayer getNewPlayer() { return newPlayer; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleBlocksStackerEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerToggleBlocksStackerEvent is called when a player toggles his blocks-stacker. */ public class PlayerToggleBlocksStackerEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that toggled the blocks-stacker. */ public PlayerToggleBlocksStackerEvent(SuperiorPlayer superiorPlayer) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; } /** * Get the player that toggled the blocks-stacker. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleBorderEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerToggleBorderEvent is called when a player toggles his world border. */ public class PlayerToggleBorderEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that toggled the world border. */ public PlayerToggleBorderEvent(SuperiorPlayer superiorPlayer) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; } /** * Get the player that toggled the world border. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleBypassEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerToggleBypassEvent is called when a player toggles his bypass mode. */ public class PlayerToggleBypassEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that toggled the bypass mode. */ public PlayerToggleBypassEvent(SuperiorPlayer superiorPlayer) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; } /** * Get the player that toggled the bypass mode. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleFlyEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerToggleFlyEvent is called when a player toggles his island fly. */ public class PlayerToggleFlyEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that toggled the island fly. */ public PlayerToggleFlyEvent(SuperiorPlayer superiorPlayer) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; } /** * Get the player that toggled the island fly. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerTogglePanelEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerTogglePanelEvent is called when a player toggles his control panel. */ public class PlayerTogglePanelEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that toggled the control panel. */ public PlayerTogglePanelEvent(SuperiorPlayer superiorPlayer) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; } /** * Get the player that toggled the control panel. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleSpyEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerToggleSpyEvent is called when a player toggles his chat-spy. */ public class PlayerToggleSpyEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that toggled the chat-spy. */ public PlayerToggleSpyEvent(SuperiorPlayer superiorPlayer) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; } /** * Get the player that toggled the chat-spy. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PlayerToggleTeamChatEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PlayerToggleTeamChatEvent is called when a player toggles his team chat. */ public class PlayerToggleTeamChatEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player that toggled the team chat. */ public PlayerToggleTeamChatEvent(SuperiorPlayer superiorPlayer) { super(!Bukkit.isPrimaryThread()); this.superiorPlayer = superiorPlayer; } /** * Get the player that toggled the team chat. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PluginInitializeEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; import com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer; import com.google.common.base.Preconditions; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PluginInitializeEvent is called when other plugins needs to register their custom data. */ public class PluginInitializeEvent extends Event { private static final HandlerList handlers = new HandlerList(); private final SuperiorSkyblock plugin; @Nullable private IslandsContainer islandsContainer; @Nullable private PlayersContainer playersContainer; /** * The constructor for the event. * You cannot use handlers in this time, as none of them is set up. * * @param plugin The instance of the plugin. */ public PluginInitializeEvent(SuperiorSkyblock plugin) { this.plugin = plugin; } /** * Get the instance of the plugin. * * @return */ public SuperiorSkyblock getPlugin() { return plugin; } /** * Get the islands container that will be used for storing islands. * If null, default islands container of the plugin will be used. */ @Nullable public IslandsContainer getIslandsContainer() { return islandsContainer; } /** * Set a new islands container to be used for storing islands. * * @param islandsContainer The new container. */ public void setIslandsContainer(IslandsContainer islandsContainer) { Preconditions.checkNotNull(islandsContainer, "IslandsContainer cannot be set to null."); this.islandsContainer = islandsContainer; } /** * Get the players container that will be used for storing players. * If null, default players container of the plugin will be used. */ @Nullable public PlayersContainer getPlayersContainer() { return playersContainer; } /** * Set a new players container to be used for storing players. * * @param playersContainer The new container. */ public void setPlayersContainer(PlayersContainer playersContainer) { Preconditions.checkNotNull(playersContainer, "PlayersContainer cannot be set to null."); this.playersContainer = playersContainer; } public static HandlerList getHandlerList() { return handlers; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PluginInitializedEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PluginInitializedEvent is called when plugin enabled completely. */ public class PluginInitializedEvent extends Event { private static final HandlerList handlers = new HandlerList(); private final SuperiorSkyblock plugin; /** * The constructor for the event. */ public PluginInitializedEvent(SuperiorSkyblock plugin) { this.plugin = plugin; } public static HandlerList getHandlerList() { return handlers; } public SuperiorSkyblock getPlugin() { return plugin; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PluginLoadDataEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PluginLoadDataEvent is called right before the plugin starts to load data. */ public class PluginLoadDataEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorSkyblock plugin; private boolean cancelled = false; /** * The constructor for the event. * * @param plugin The instance of the plugin. */ public PluginLoadDataEvent(SuperiorSkyblock plugin) { this.plugin = plugin; } /** * Get the instance of the plugin. */ public SuperiorSkyblock getPlugin() { return plugin; } @Override public boolean isCancelled() { return this.cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } public static HandlerList getHandlerList() { return handlers; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PostIslandCreateEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; /** * IslandCreateEvent is called after the island is created and the player was teleported to it. */ public class PostIslandCreateEvent extends IslandEvent { private final SuperiorPlayer superiorPlayer; /** * The constructor for the event. * * @param superiorPlayer The player who created the island. * @param island The island object that was created. */ public PostIslandCreateEvent(SuperiorPlayer superiorPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; } /** * Get the player who created the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/PreIslandCreateEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * PreIslandCreateEvent is called when a new island is created. */ public class PreIslandCreateEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final SuperiorPlayer superiorPlayer; private final String islandName; private boolean cancelled = false; /** * The constructor of the event. * * @param superiorPlayer The player who created the island. * @param islandName The name that was given to the island. */ public PreIslandCreateEvent(SuperiorPlayer superiorPlayer, String islandName) { this.superiorPlayer = superiorPlayer; this.islandName = islandName; } /** * The constructor of the event. * * @param superiorPlayer The player who created the island. * @deprecated See PreIslandCreateEvent(SuperiorPlayer, String) */ @Deprecated public PreIslandCreateEvent(SuperiorPlayer superiorPlayer) { this(superiorPlayer, ""); } public static HandlerList getHandlerList() { return handlers; } /** * Get the player who created the island. */ public SuperiorPlayer getPlayer() { return superiorPlayer; } /** * Get the name that was given to the island. */ public String getIslandName() { return islandName; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/events/SendMessageEvent.java ================================================ package com.bgsoftware.superiorskyblock.api.events; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; /** * SendMessageEvent is called when a message is sent to {@link CommandSender} */ public class SendMessageEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private final CommandSender receiver; private final String messageType; private final Object[] args; private IMessageComponent messageComponent; private boolean cancelled = false; /** * The constructor for the event. * * @param receiver The receiver of the message. * @param messageType The name of the message, similar to the one from lang file. * @param messageComponent The message component that is being sent. */ public SendMessageEvent(CommandSender receiver, String messageType, IMessageComponent messageComponent, Object[] args) { super(!Bukkit.isPrimaryThread()); this.receiver = receiver; this.messageType = messageType; this.messageComponent = messageComponent; this.args = args; } /** * Get the receiver of the message. */ public CommandSender getReceiver() { return receiver; } /** * Get the name of the message, similar to the one from lang file. */ public String getMessageType() { return messageType; } /** * Get an argument of the message. * * @param index The index of the argument. * @throws ArrayIndexOutOfBoundsException If {@param index} is out of bounds. */ public Object getArgument(int index) { return args[index]; } /** * Set an argument for the message. * * @param index The index of the argument. * @param value The value to be set. * @throws ArrayIndexOutOfBoundsException If {@param index} is out of bounds. */ public void setArgument(int index, Object value) { Preconditions.checkNotNull(value, "Argument's value cannot be null."); args[index] = value; } /** * Get the length of the arguments array. */ public int getArgumentsLength() { return args.length; } /** * Get the message component that is sent. */ public IMessageComponent getMessageComponent() { return messageComponent; } /** * Set the message component to be sent. * * @param messageComponent The new component to be sent. */ public void setMessageComponent(IMessageComponent messageComponent) { Preconditions.checkNotNull(messageComponent, "Message components cannot be null."); this.messageComponent = messageComponent; } @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } @Override public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/BanksFactory.java ================================================ package com.bgsoftware.superiorskyblock.api.factory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; public interface BanksFactory { /** * Create a new bank for an island. * * @param island The island to create the bank for. * @param original The original island bank that was created. */ IslandBank createIslandBank(Island island, IslandBank original); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DatabaseBridgeFactory.java ================================================ package com.bgsoftware.superiorskyblock.api.factory; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public interface DatabaseBridgeFactory { /** * Create a new database bridge for an island. * * @param island The island to create the database-bridge for. * If island is null, then the database-bridge is used as a loader from the database. * @param original The original database-bridge that was created. */ DatabaseBridge createIslandsDatabaseBridge(@Nullable Island island, DatabaseBridge original); /** * Create a new database bridge for a player. * * @param superiorPlayer The player to create the database-bridge for. * If player is null, then the database-bridge is used as a loader from the database. * @param original The original database-bridge that was created. */ DatabaseBridge createPlayersDatabaseBridge(@Nullable SuperiorPlayer superiorPlayer, DatabaseBridge original); /** * Create a new database bridge for the grid. * * @param gridManager The grid to create the database-bridge for. * If grid is null, then the database-bridge is used as a loader from the database. * @param original The original database-bridge that was created. */ DatabaseBridge createGridDatabaseBridge(@Nullable GridManager gridManager, DatabaseBridge original); /** * Create a new database bridge for the stacked-blocks manager. * * @param stackedBlocksManager The stacked-blocks manager to create the database-bridge for. * If manager is null, then the database-bridge is used as a loader from the database. * @param original The original database-bridge that was created. */ DatabaseBridge createStackedBlocksDatabaseBridge(@Nullable StackedBlocksManager stackedBlocksManager, DatabaseBridge original); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateBanksFactory.java ================================================ package com.bgsoftware.superiorskyblock.api.factory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; public class DelegateBanksFactory implements BanksFactory { protected final BanksFactory handle; protected DelegateBanksFactory(BanksFactory handle) { this.handle = handle; } @Override public IslandBank createIslandBank(Island island, IslandBank original) { return this.handle.createIslandBank(island, original); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateDatabaseBridgeFactory.java ================================================ package com.bgsoftware.superiorskyblock.api.factory; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public class DelegateDatabaseBridgeFactory implements DatabaseBridgeFactory { protected final DatabaseBridgeFactory handle; protected DelegateDatabaseBridgeFactory(DatabaseBridgeFactory handle) { this.handle = handle; } @Override public DatabaseBridge createIslandsDatabaseBridge(@Nullable Island island, DatabaseBridge original) { return this.handle.createIslandsDatabaseBridge(island, original); } @Override public DatabaseBridge createPlayersDatabaseBridge(@Nullable SuperiorPlayer superiorPlayer, DatabaseBridge original) { return this.handle.createPlayersDatabaseBridge(superiorPlayer, original); } @Override public DatabaseBridge createGridDatabaseBridge(@Nullable GridManager gridManager, DatabaseBridge original) { return this.handle.createGridDatabaseBridge(gridManager, original); } @Override public DatabaseBridge createStackedBlocksDatabaseBridge(@Nullable StackedBlocksManager stackedBlocksManager, DatabaseBridge original) { return this.handle.createStackedBlocksDatabaseBridge(stackedBlocksManager, original); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateIslandsFactory.java ================================================ package com.bgsoftware.superiorskyblock.api.factory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; public class DelegateIslandsFactory implements IslandsFactory { protected final IslandsFactory handle; protected DelegateIslandsFactory(IslandsFactory handle) { this.handle = handle; } @Override public Island createIsland(Island original) { return this.handle.createIsland(original); } @Override @Deprecated public IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island) { return this.handle.createIslandCalculationAlgorithm(island); } @Override @Deprecated public IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island) { return this.handle.createIslandBlocksTrackerAlgorithm(island); } @Override @Deprecated public IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island) { return this.handle.createIslandEntitiesTrackerAlgorithm(island); } @Override public IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island, IslandCalculationAlgorithm original) { return this.handle.createIslandCalculationAlgorithm(island, original); } @Override public IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island, IslandBlocksTrackerAlgorithm original) { return this.handle.createIslandBlocksTrackerAlgorithm(island, original); } @Override public IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island, IslandEntitiesTrackerAlgorithm original) { return this.handle.createIslandEntitiesTrackerAlgorithm(island, original); } @Override public PersistentDataContainer createPersistentDataContainer(Island island, PersistentDataContainer original) { return this.handle.createPersistentDataContainer(island, original); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegatePlayersFactory.java ================================================ package com.bgsoftware.superiorskyblock.api.factory; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public class DelegatePlayersFactory implements PlayersFactory { protected final PlayersFactory handle; protected DelegatePlayersFactory(PlayersFactory handle) { this.handle = handle; } @Override public SuperiorPlayer createPlayer(SuperiorPlayer original) { return this.handle.createPlayer(original); } @Override @Deprecated public PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer) { return this.handle.createPlayerTeleportAlgorithm(superiorPlayer); } @Override public PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer, PlayerTeleportAlgorithm original) { return this.handle.createPlayerTeleportAlgorithm(superiorPlayer, original); } @Override public PersistentDataContainer createPersistentDataContainer(SuperiorPlayer superiorPlayer, PersistentDataContainer original) { return this.handle.createPersistentDataContainer(superiorPlayer, original); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/IslandsFactory.java ================================================ package com.bgsoftware.superiorskyblock.api.factory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; public interface IslandsFactory { /** * Create a new island. * * @param original The original island that was created. */ Island createIsland(Island original); /** * Create a calculation algorithm for an island. * * @param island The island to set the algorithm to. * @deprecated Use {@link #createIslandCalculationAlgorithm(Island, IslandCalculationAlgorithm)} */ @Deprecated default IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island) { throw new UnsupportedOperationException("Unsupported operation."); } /** * Create a blocks-tracking algorithm for an island. * * @param island The island to set the algorithm to. * @deprecated Use {@link #createIslandBlocksTrackerAlgorithm(Island, IslandBlocksTrackerAlgorithm)} */ @Deprecated default IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island) { throw new UnsupportedOperationException("Unsupported operation."); } /** * Create an entities-tracking algorithm for an island. * * @param island The island to set the algorithm to. * @deprecated Use {@link #createIslandEntitiesTrackerAlgorithm(Island, IslandEntitiesTrackerAlgorithm)} */ @Deprecated default IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island) { throw new UnsupportedOperationException("Unsupported operation."); } /** * Create a calculation algorithm for an island. * * @param island The island to set the algorithm to. * @param original The original calculation algorithm. */ IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island, IslandCalculationAlgorithm original); /** * Create a blocks-tracking algorithm for an island. * * @param island The island to set the algorithm to. * @param original The original blocks tracking algorithm. */ IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island, IslandBlocksTrackerAlgorithm original); /** * Create an entities-tracking algorithm for an island. * * @param island The island to set the algorithm to. * @param original The original entities tracking algorithm. */ IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island, IslandEntitiesTrackerAlgorithm original); /** * Create a new persistent data container for an island. * * @param island The island to create the container for. * @param original The original persistent data container that was created. */ PersistentDataContainer createPersistentDataContainer(Island island, PersistentDataContainer original); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/PlayersFactory.java ================================================ package com.bgsoftware.superiorskyblock.api.factory; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public interface PlayersFactory { /** * Create a new player wrapper. * * @param original The original player wrapper that was created. */ SuperiorPlayer createPlayer(SuperiorPlayer original); /** * Create a teleport algorithm for a player. * * @param superiorPlayer The player to set the algorithm to. * @deprecated Use {@link #createPlayerTeleportAlgorithm(SuperiorPlayer, PlayerTeleportAlgorithm)} */ @Deprecated default PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer) { throw new UnsupportedOperationException("Unsupported operation."); } /** * Create a teleport algorithm for a player. * * @param superiorPlayer The player to set the algorithm to. * @param original The original teleport algorithm. */ PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer, PlayerTeleportAlgorithm original); /** * Create a new persistent data container for a player. * * @param superiorPlayer The player to create the container for. * @param original The original persistent data container that was created. */ PersistentDataContainer createPersistentDataContainer(SuperiorPlayer superiorPlayer, PersistentDataContainer original); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/BlockValuesManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import java.math.BigDecimal; public interface BlockValuesManager { /** * Get the worth value of a key. * * @param key The key to check. * @return The worth value. */ BigDecimal getBlockWorth(Key key); /** * Get the level value of a key. * * @param key The key to check. * @return The level value. */ BigDecimal getBlockLevel(Key key); /** * Get the exact key that is used in the config. * * @param key The key to check. * @return The key from the config. */ Key getBlockKey(Key key); /** * Register a value for a key. * * @param key The key to set custom value of. * @param worthValue The custom worth value of the key. * @param levelValue The custom level value of the key. */ void registerCustomKey(Key key, @Nullable BigDecimal worthValue, @Nullable BigDecimal levelValue); /** * Register a custom key parser. * * @param customKeyParser The custom key parser. * @param blockTypes All the block types you want to check. */ void registerKeyParser(CustomKeyParser customKeyParser, Key... blockTypes); enum SyncWorthStatus { NONE, BUY, SELL; public static SyncWorthStatus of(String name) { try { return valueOf(name); } catch (Exception ex) { return NONE; } } } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/CommandsManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import org.bukkit.command.CommandSender; import java.util.List; public interface CommandsManager { /** * Register a sub-command. * * @param superiorCommand The sub command to register. */ void registerCommand(SuperiorCommand superiorCommand); /** * Unregister a sub-command. * * @param superiorCommand The sub command to register. */ void unregisterCommand(SuperiorCommand superiorCommand); /** * Register a sub-command to the admin command. * * @param superiorCommand The sub command to unregister. */ void registerAdminCommand(SuperiorCommand superiorCommand); /** * Unregister a sub-command from the admin command. * * @param superiorCommand The sub command to unregister. */ void unregisterAdminCommand(SuperiorCommand superiorCommand); /** * Get all the registered sub-commands. */ List getSubCommands(); /** * Get all the registered sub-commands. * * @param includeDisabled Whether to include disabled commands. */ List getSubCommands(boolean includeDisabled); /** * Get a sub command by its label. * * @param commandLabel The label of the sub command. * @return The sub command if exists or null. */ @Nullable SuperiorCommand getCommand(String commandLabel); /** * Get all the registered admin sub-commands. */ List getAdminSubCommands(); /** * Get an admin sub command by its label. * * @param commandLabel The label of the sub command. * @return The sub command if exists or null. */ @Nullable SuperiorCommand getAdminCommand(String commandLabel); /** * Dispatch a sub command. * If the sub command does not exist, Bukkit#dispatchCommand is executed. * * @param sender The sender to dispatch the command. * @param subCommand The sub-command to dispatch. */ void dispatchSubCommand(CommandSender sender, String subCommand); /** * Dispatch a sub command. * If the sub command does not exist, Bukkit#dispatchCommand is executed. * * @param sender The sender to dispatch the command. * @param subCommand The sub-command to dispatch. * @param args The argument to use for the command. */ void dispatchSubCommand(CommandSender sender, String subCommand, @Nullable String args); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.BankAction; import com.bgsoftware.superiorskyblock.api.factory.BanksFactory; import com.bgsoftware.superiorskyblock.api.factory.DatabaseBridgeFactory; import com.bgsoftware.superiorskyblock.api.factory.IslandsFactory; import com.bgsoftware.superiorskyblock.api.factory.PlayersFactory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.World; import java.math.BigDecimal; import java.util.UUID; public interface FactoriesManager { /** * Register a custom islands factory. * * @param islandsFactory The new factory to set. * If set to null, the default factory will be used. */ void registerIslandsFactory(@Nullable IslandsFactory islandsFactory); /** * Get the current islands factory. */ IslandsFactory getIslandsFactory(); /** * Register a custom players factory. * * @param playersFactory The new factory to set. * If set to null, the default factory will be used. */ void registerPlayersFactory(@Nullable PlayersFactory playersFactory); /** * Get the current players factory. */ PlayersFactory getPlayersFactory(); /** * Register a custom banks factory. * * @param banksFactory The new factory to set. * If set to null, the default factory will be used. */ void registerBanksFactory(@Nullable BanksFactory banksFactory); /** * Get the current banks factory. */ BanksFactory getBanksFactory(); /** * Register a custom database-bridge factory. * * @param databaseBridgeFactory The new factory to set. * If set to null, the default factory will be used. */ void registerDatabaseBridgeFactory(@Nullable DatabaseBridgeFactory databaseBridgeFactory); /** * Get the database bridge factory. */ DatabaseBridgeFactory getDatabaseBridgeFactory(); /** * Create a new Island object. * Warning: This island is not saved into the database unless inserting it manually! * * @param owner The owner of the island. * @param uuid The uuid of the island. * @param center The location of the island. * @param islandName The name of the island. * @param schemName The schematic used to create the island. */ Island createIsland(@Nullable SuperiorPlayer owner, UUID uuid, Location center, String islandName, String schemName); /** * Create a new builder for a {@link Island} object. */ Island.Builder createIslandBuilder(); /** * Create a new SuperiorPlayer object. * Warning: This player is not saved into the database unless inserting it manually! * * @param playerUUID The uuid of the player. */ SuperiorPlayer createPlayer(UUID playerUUID); /** * Create a new builder for a {@link SuperiorPlayer} object. */ SuperiorPlayer.Builder createPlayerBuilder(); /** * Create a {@link BlockOffset} object from given offsets. * * @param offsetX The x-coords offset. * @param offsetY The y-coords offset. * @param offsetZ The z-coords offset. */ BlockOffset createBlockOffset(int offsetX, int offsetY, int offsetZ); /** * Create a {@link BlockPosition} object from given block coords. * * @param world The name of the world of the block. * @param blockX The x-coords of the block. * @param blockY The y-coords of the block. * @param blockZ The z-coords of the block. * @deprecated See {@link #createBlockPosition(int, int, int)} */ @Deprecated BlockPosition createBlockPosition(String world, int blockX, int blockY, int blockZ); /** * Create a {@link BlockPosition} object from given block coords. * * @param blockX The x-coords of the block. * @param blockY The y-coords of the block. * @param blockZ The z-coords of the block. */ BlockPosition createBlockPosition(int blockX, int blockY, int blockZ); /** * Create a {@link BlockPosition} object from a location. * * @param location The location. */ BlockPosition createBlockPosition(Location location); /** * Create a {@link WorldPosition} object from given world coords. * * @param x The x-coords of the position. * @param y The y-coords of the position. * @param z The z-coords of the position. */ WorldPosition createWorldPosition(double x, double y, double z); /** * Create a {@link WorldPosition} object from given world coords. * * @param x The x-coords of the position. * @param y The y-coords of the position. * @param z The z-coords of the position. * @param yaw The yaw of the position. * @param pitch The pitch of the position. */ WorldPosition createWorldPosition(double x, double y, double z, float yaw, float pitch); /** * Create a {@link WorldPosition} object from a location. * * @param location The location. */ WorldPosition createWorldPosition(Location location); /** * Create a new bank transaction. * * @param player The player that made the transaction. * Can be null if console made it. * @param action The transaction action * @param position The position of the transaction. * @param time The time the transaction was made. * @param failureReason The reason of failure for this transaction, if exists. * On successful transactions, empty string should be set. * @param amount The amount of money that was transferred in this transaction. */ BankTransaction createTransaction(@Nullable UUID player, BankAction action, int position, long time, String failureReason, BigDecimal amount); /** * Create a new world info. * * @param worldName The name of the world. * @param dimension The dimension of the world. */ WorldInfo createWorldInfo(String worldName, Dimension dimension); /** * Create a new game sound instance. * * @param sound The sound to play. * @param volume The volume to play the sound. * @param pitch The pitch to play the sound. */ GameSound createGameSound(Sound sound, float volume, float pitch); /** * Create a new builder for a {@link SchematicOptions} object. * * @param schematicName The name of the schematic to create. */ SchematicOptions.Builder createSchematicOptionsBuilder(String schematicName); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; import java.math.BigDecimal; import java.util.List; import java.util.UUID; public interface GridManager extends IDatabaseBridgeHolder { /** * Create a new island. * * @param superiorPlayer The new owner for the island. * @param schemName The schematic that should be used. * @param bonus A starting worth for the island. * @param biome A starting biome for the island. * @param islandName The name of the new island. */ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName); /** * Create a new island. * * @param superiorPlayer The new owner for the island. * @param schemName The schematic that should be used. * @param bonus A starting worth for the island. * @param biome A starting biome for the island. * @param islandName The name of the new island. * @param offset Should the island have an offset for it's values? If disabled, the bonus will be given. */ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName, boolean offset); /** * Create a new island. * * @param superiorPlayer The new owner for the island. * @param schemName The schematic that should be used. * @param bonusWorth A starting worth for the island. * @param bonusLevel A starting level for the island. * @param biome A starting biome for the island. * @param islandName The name of the new island. * @param offset Should the island have an offset for it's values? If disabled, the bonus will be given. */ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonusWorth, BigDecimal bonusLevel, Biome biome, String islandName, boolean offset); /** * Create a new island. * * @param superiorPlayer The new owner for the island. * @param schemName The schematic that should be used. * @param bonusWorth A starting worth for the island. * @param bonusLevel A starting level for the island. * @param biome A starting biome for the island. * @param islandName The name of the new island. * @param offset Should the island have an offset for it's values? If disabled, the bonus will be given. * @param spawnOffset The offset to teleport the player to from the center of the schematic */ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonusWorth, BigDecimal bonusLevel, Biome biome, String islandName, boolean offset, @Nullable BlockOffset spawnOffset); /** * Create a new island. * * @param builder The builder for the island. * @param biome A starting biome for the island. * @param offset Should the island have an offset for its values? If disabled, the bonus will be given. */ void createIsland(Island.Builder builder, Biome biome, boolean offset); /** * Create a new island. * * @param builder The builder for the island. * @param biome A starting biome for the island. * @param offset Should the island have an offset for its values? If disabled, the bonus will be given. * @param spawnOffset The offset to teleport the player to from the center of the schematic */ void createIsland(Island.Builder builder, Biome biome, boolean offset, @Nullable BlockOffset spawnOffset); /** * Set the creation algorithm of islands. * * @param islandCreationAlgorithm The new algorithm to set. * If null, the default one will be used. */ void setIslandCreationAlgorithm(@Nullable IslandCreationAlgorithm islandCreationAlgorithm); /** * Get the currently used island creation algorithm. */ IslandCreationAlgorithm getIslandCreationAlgorithm(); /** * Checks if a player has an active request for creating an island. * * @param superiorPlayer The player to check. */ boolean hasActiveCreateRequest(SuperiorPlayer superiorPlayer); /** * Start the island preview task for a specific player. * * @param superiorPlayer The player to start preview for. * @param schemName The schematic to preview. * @param islandName The requested island name by the player. */ void startIslandPreview(SuperiorPlayer superiorPlayer, String schemName, String islandName); /** * Cancel the island preview for a specific player. * * @param superiorPlayer The player to cancel preview for. */ void cancelIslandPreview(SuperiorPlayer superiorPlayer); /** * Cancel all active island previews. */ void cancelAllIslandPreviews(); /** * Check if a player has an ongoing island preview task. * * @param superiorPlayer The player to check. */ @Nullable IslandPreview getIslandPreview(SuperiorPlayer superiorPlayer); /** * Delete an island. * * @param island The island to delete. */ void deleteIsland(Island island); /** * Get the island of a specific player. * * @param superiorPlayer The player to check. * @return The island of the player. May be null. * @deprecated See {@link SuperiorPlayer#getIsland()} */ @Nullable @Deprecated Island getIsland(SuperiorPlayer superiorPlayer); /** * Get the island in a specific position from one of the top lists. * Positions are starting from 0. * * @param position The position to check. * @param sortingType The sorting type that should be considered. * @return The island in that position. May be null. */ @Nullable Island getIsland(int position, SortingType sortingType); /** * Get the position of an island. * Positions are starting from 0. * * @param island The island to check. * @param sortingType The sorting type that should be considered. * @return The position of the island. */ int getIslandPosition(Island island, SortingType sortingType); /** * Get an island by it's owner uuid. * * @param uuid The uuid of the owner. * @return The island of the owner. May be null. * @deprecated See {@link SuperiorPlayer#getIsland()} */ @Nullable @Deprecated Island getIsland(UUID uuid); /** * Get an island by it's uuid. * * @param uuid The uuid of the island. * @return The island with that UUID. May be null. */ @Nullable Island getIslandByUUID(UUID uuid); /** * Get an island by it's name. * * @param islandName The name to check. * @return The island with that name. May be null. */ @Nullable Island getIsland(String islandName); /** * Get an island at an exact position in the world. * * @param location The position to check. * @return The island at that position. May be null. */ @Nullable Island getIslandAt(@Nullable Location location); /** * Get an island from a chunk. * * @param chunk The chunk to check. * @return The island at that position. May be null. * @deprecated See {@link #getIslandsAt(Chunk)} */ @Nullable @Deprecated Island getIslandAt(@Nullable Chunk chunk); /** * Get all the islands from a chunk. * * @param chunk The chunk to check. * @return The islands at that position. */ @Nullable List getIslandsAt(@Nullable Chunk chunk); /** * Transfer an island's leadership to another owner. * * @param oldOwner The old owner of the island. * @param newOwner The new owner of the island. * @deprecated Does nothing. See {@link Island#transferIsland(SuperiorPlayer)} */ @Deprecated void transferIsland(UUID oldOwner, UUID newOwner); /** * Get the amount of islands. */ int getSize(); /** * Sort the islands. * * @param sortingType The sorting type to use. */ void sortIslands(SortingType sortingType); /** * Sort the islands. * * @param sortingType The sorting type to use. * @param onFinish Callback runnable. */ void sortIslands(SortingType sortingType, @Nullable Runnable onFinish); /** * Get the spawn island object. */ Island getSpawnIsland(); /** * Get the world of an island by the dimension. * If the dimension is disabled in config, null will be returned. * * @param dimension The world dimension. * @param island The island to check. */ @Nullable World getIslandsWorld(Island island, Dimension dimension); /** * Get the dimension of an islands world. * If the island is not an islands world, null will be returned. * * @param world The world to check. */ @Nullable Dimension getIslandsWorldDimension(World world); /** * Get the {@link WorldInfo} of the world of an island by the dimension. * The world might not be loaded at the time of calling this method. * * @param island The island to check. * @param dimension The world dimension. * @return The world info for the given dimension, or null if this dimension is not enabled. */ @Nullable WorldInfo getIslandsWorldInfo(Island island, Dimension dimension); /** * Get the {@link WorldInfo} of the world of an island by its name. * The world might not be loaded at the time of calling this method. * * @param island The island to check. * @param worldName The name of the world. * @return The world info for the given name, or null if this name is not an islands world. */ @Nullable WorldInfo getIslandsWorldInfo(Island island, String worldName); /** * Checks if the given world is an islands world. * Can be the normal world, the nether world (if enabled in config) or the end world (if enabled in config) */ boolean isIslandsWorld(World world); /** * Register a world as a islands world. * This will add all protections to that world, however - no islands will by physically there. * * @param world The world to register as an islands world. * @throws IllegalArgumentException if the world couldn't be registered */ void registerIslandWorld(World world); /** * Get all registered worlds. */ List getRegisteredWorlds(); /** * Get all the islands ordered by a specific sorting type. * * @param sortingType The sorting type to order the list by. * @return A list of uuids of the island owners. * @deprecated See {@link #getIslands(SortingType)} */ @Deprecated List getAllIslands(SortingType sortingType); /** * Get all the islands unordered. */ List getIslands(); /** * Get all the islands ordered by a specific sorting type. * * @param sortingType The sorting type to order the list by. * @return A list of uuids of the island owners. */ List getIslands(SortingType sortingType); /** * Get the block amount of a specific block. * * @param block The block to check. * @deprecated see {@link StackedBlocksManager} */ @Deprecated int getBlockAmount(Block block); /** * Get the block amount of a specific location. * * @param location The location to check. * @deprecated see {@link StackedBlocksManager} */ @Deprecated int getBlockAmount(Location location); /** * Set a new amount for a specific block. * * @param block The block to set the amount to. * @param amount The new amount of the block. * @deprecated see {@link StackedBlocksManager} */ @Deprecated void setBlockAmount(Block block, int amount); /** * Get all the stacked blocks on the server. * * @deprecated see {@link StackedBlocksManager} */ @Deprecated List getStackedBlocks(); /** * Calculate the worth of all the islands on the server. */ void calcAllIslands(); /** * Calculate the worth of all the islands on the server. * * @param callback Runnable that will be ran when process is finished. */ void calcAllIslands(@Nullable Runnable callback); /** * Make the island to be deleted when server stops. * * @param island The island to delete. */ void addIslandToPurge(Island island); /** * Remove the island from being deleted when server stops. * * @param island The island to keep. */ void removeIslandFromPurge(Island island); /** * Check if the island will be deleted when the server stops? */ boolean isIslandPurge(Island island); /** * Get all the islands that will be deleted when the server stops. */ List getIslandsToPurge(); /** * Add a new sorting type to the registry of islands. * * @param sortingType The new sorting type to register. */ void registerSortingType(SortingType sortingType); /** * Get the total worth of all the islands. * This value is updated every minute, so it might not be 100% accurate. */ BigDecimal getTotalWorth(); /** * Get the total level of all the islands. * This value is updated every minute, so it might not be 100% accurate. */ BigDecimal getTotalLevel(); /** * Get the location of the last island that was generated. * The location's getWorld will always return null. * * @deprecated See {@link #getLastIslandPosition()} */ @Deprecated Location getLastIslandLocation(); /** * Set the location of the last island. * Warning: Do not use this method unless you know what you're doing * * @param location The location to set. * @deprecated See {@link #setLastIslandPosition(BlockPosition)} */ @Deprecated void setLastIslandLocation(Location location); /** * Get the position of the last island that was generated. */ BlockPosition getLastIslandPosition(); /** * Set the position of the last island. * Warning: Do not use this method unless you know what you're doing * * @param blockPosition The position to set. */ void setLastIslandPosition(BlockPosition blockPosition); /** * Get the islands container. */ IslandsContainer getIslandsContainer(); /** * Set a new islands container. * * @param islandsContainer The new islands container to set. */ void setIslandsContainer(IslandsContainer islandsContainer); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/KeysManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.function.Supplier; public interface KeysManager { /** * Get the key of an entity type. * * @param entityType The entity type to check. */ Key getKey(EntityType entityType); /** * Get the key of an entity type. * * @param entityTypeName The name of the entity type to create key for. */ Key getEntityTypeKey(String entityTypeName); /** * Get the key of an entity. * * @param entity The entity to check. */ Key getKey(Entity entity); /** * Get the key of a block. * * @param block The block to check. */ Key getKey(Block block); /** * Get the key of a block-state. * * @param blockState The block-state to check. */ Key getKey(BlockState blockState); /** * Get the key of an item-stack. * * @param itemStack The item-stack to check. */ Key getKey(ItemStack itemStack); /** * Get the key of a material and data. * * @param material The material to check. * @param data The data to check. */ Key getKey(Material material, short data); /** * Get the key of a material. * * @param material The material to create key for. */ Key getKey(Material material); /** * Get the key of a material and data, split by ':' (optionally). * * @param type The combined material-data pair to create key for. */ Key getMaterialAndDataKey(String type); /** * Get the key of a spawner block with specific entity type. * * @param entityType The entity type of the spawner to create key for. */ Key getSpawnerKey(EntityType entityType); /** * Get the key of a spawner block with specific entity type. * * @param entityTypeName The name of the entity type of the spawner to create key for. */ Key getSpawnerKey(String entityTypeName); /** * Get the key of a string. * * @param key The string to check. */ Key getKey(String key); /** * Get the key of a global-key and a sub-key. * * @param globalKey The global key * @param subKey The sub key */ Key getKey(String globalKey, String subKey); /** * Create a new empty {@link KeySet} instance. */ KeySet createKeySet(Supplier> setCreator); /** * Create a new {@link KeySet} instance from the given collection. * If the provided collection is also a {@link KeySet}, the exact same instance of that set is returned. * Otherwise, the returned {@link KeySet} is a copy of that collection. * * @param collection The collection to create {@link KeySet} from. */ KeySet createKeySet(Supplier> setCreator, Collection collection); /** * Create a new empty {@link KeyMap } instance. */ KeyMap createKeyMap(Supplier> mapCreator); /** * Create a new {@link KeyMap} instance from the given map. * If the provided map is also a {@link KeyMap}, the exact same instance of the map is returned. * Otherwise, the returned {@link KeyMap} is a copy of that map. * * @param map The map to create {@link KeySet} from. */ KeyMap createKeyMap(Supplier> mapCreator, Map map); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/MenusManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.MenuCommands; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.parser.MenuParser; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.Map; public interface MenusManager { /** * Open the bank-logs menu. * Used to display all logs of bank transactions. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to display bank logs for. */ void openBankLogs(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the bank-logs menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshBankLogs(Island island); /** * Open the biomes-menu. * Used to display and choose biomes for the island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to change biomes for. */ void openBiomes(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island biomes menu for a player. * * @param superiorPlayer The player to open the menu for. * @deprecated see {@link #openBiomes(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandBiomesMenu(SuperiorPlayer superiorPlayer); /** * Open the border-color menu. * Used to change the color of the world border for a player. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openBorderColor(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the border color menu for a player. * * @param superiorPlayer The player to open the menu for. * @deprecated see {@link #openBorderColor(SuperiorPlayer, ISuperiorMenu)} */ @Deprecated void openBorderColorMenu(SuperiorPlayer superiorPlayer); /** * Open the confirm-ban menu. * Used to confirm a ban of an island member. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to ban the player from. * @param bannedPlayer The player that will be banned. */ void openConfirmBan(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer bannedPlayer); /** * Open the confirm-disband menu. * Used to confirm disband of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to disband. */ void openConfirmDisband(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the confirm disband menu for a player. * * @param superiorPlayer The player to open the menu for. * @deprecated see {@link #openConfirmDisband(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openConfirmDisbandMenu(SuperiorPlayer superiorPlayer); /** * Open the confirm-kick menu. * Used to confirm a kick of an island member. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to kick the player from. * @param kickedPlayer The player that will be kicked. */ void openConfirmKick(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer kickedPlayer); /** * Open the confirm-leave menu. * Used to confirm leaving of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the confirm-transfer menu. * Used to confirm the transfer of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to ban the player from. * @param newOwner The player that will be banned. */ void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner); /** * Open the control-panel menu. * Used when opening the control panel of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to open the control panel of. */ void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island panel menu for a player. * * @param superiorPlayer The player to open the menu for. * @deprecated {@link #openControlPanel(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandPanelMenu(SuperiorPlayer superiorPlayer); /** * Open the coops menu. * Used when opening the coops menu of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get coop-members from. */ void openCoops(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the coops-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshCoops(Island island); /** * Open the block-counts menu. * Used when opening the counts menu of an island (using /is counts, for example) * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get block counts from. */ void openCounts(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island counts menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the block counts from. * @deprecated see {@link #openCounts(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandCountsMenu(SuperiorPlayer superiorPlayer, Island island); /** * Refresh the counts-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshCounts(Island island); /** * Open the global-warps menu. * Used when running the /is warp command. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openGlobalWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the global warps menu for a player. * * @param superiorPlayer The player to open the menu for. * @deprecated see {@link #openGlobalWarps(SuperiorPlayer, ISuperiorMenu)} */ @Deprecated void openGlobalWarpsMenu(SuperiorPlayer superiorPlayer); /** * Refresh the global-warps menu. */ void refreshGlobalWarps(); /** * Open the island-bank menu. * Used when running the /is bank command. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to open the bank for. */ void openIslandBank(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the island bank menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshIslandBank(Island island); /** * Open the banned-players menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to check the members of. */ void openIslandBannedPlayers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the banned-players menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshIslandBannedPlayers(Island island); /** * Open the island-chests menu. * Used to open the shared chests menu of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to open the shared-chests menu for. */ void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the island-chests menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshIslandChest(Island island); /** * Open the islands-creation menu. * Used when creating a new island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param islandName The desired name of the new island. */ void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName); /** * Open the island creation menu for a player. * * @param superiorPlayer The player to open the menu for. * @param islandName The name to give the island if the player creates a new island. * @deprecated see {@link #openIslandCreation(SuperiorPlayer, ISuperiorMenu, String)} */ @Deprecated void openIslandCreationMenu(SuperiorPlayer superiorPlayer, String islandName); /** * Open the rate-menu. * Used when giving a rating for an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to give a rating. */ void openIslandRate(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island rate menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The target island to give the rating. * @deprecated see {@link #openIslandRate(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandRateMenu(SuperiorPlayer superiorPlayer, Island island); /** * Open the ratings-menu. * Used when checking given ratings of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get ratings from. */ void openIslandRatings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island ratings menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the ratings from. * @deprecated see {@link #openIslandRatings(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandRatingsMenu(SuperiorPlayer superiorPlayer, Island island); /** * Refresh the ratings-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshIslandRatings(Island island); /** * Open the member-manage menu. * Used when managing an island member. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param islandMember The island member to manage. */ void openMemberManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember); /** * Open the member manage menu for a player. * * @param superiorPlayer The player to open the menu for. * @param targetPlayer The target player to manage. * @deprecated see {@link #openMemberManage(SuperiorPlayer, ISuperiorMenu, SuperiorPlayer)} */ @Deprecated void openMemberManageMenu(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer); /** * Destroy the member-manage menus for a specific island member. * * @param islandMember The island member to close menus of. */ void destroyMemberManage(SuperiorPlayer islandMember); /** * Used to open the member-role menu. * Used when changing a role of an island member. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param islandMember The island member to change role for. */ void openMemberRole(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember); /** * Open the member role menu for a player. * * @param superiorPlayer The player to open the menu for. * @param targetPlayer The target player to manage their role. * @deprecated see {@link #openMemberRole(SuperiorPlayer, ISuperiorMenu, SuperiorPlayer)} */ @Deprecated void openMemberRoleMenu(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer); /** * Destroy the member-role menus for a specific island member. * * @param islandMember The island member to close menus of. */ void destroyMemberRole(SuperiorPlayer islandMember); /** * Open the members-menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to check the members of. */ void openMembers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island members menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the members from. * @deprecated {@link #openMembers(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandMembersMenu(SuperiorPlayer superiorPlayer, Island island); /** * Refresh the members-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshMembers(Island island); /** * Open the missions-menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the main island missions menu for a player. * * @param superiorPlayer The player to open the menu for. * @deprecated see {@link #openMissions(SuperiorPlayer, ISuperiorMenu)} */ @Deprecated void openIslandMainMissionsMenu(SuperiorPlayer superiorPlayer); /** * Open the missions-menu of a specific category. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param missionCategory The category to get missions from. */ void openMissionsCategory(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, MissionCategory missionCategory); /** * Open the island missions menu for a player. * * @param superiorPlayer The player to open the menu for. * @param islandMissions Should island missions be displayed or player missions? * @deprecated Unused menu. */ @Deprecated void openIslandMissionsMenu(SuperiorPlayer superiorPlayer, boolean islandMissions); /** * Refresh the missions-menu for a specific category. * * @param missionCategory The category to refresh the menus for. */ void refreshMissionsCategory(MissionCategory missionCategory); /** * Open the permissions-menu. * Used when changing island-permissions of a player on an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to change permissions in. * @param permissiblePlayer The player to change permissions for. */ void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer permissiblePlayer); /** * Open the island permissions menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island that holds the permissions. * @param targetPlayer The target player to see their permissions. * @deprecated see {@link #openPermissions(SuperiorPlayer, ISuperiorMenu, Island, SuperiorPlayer)} */ @Deprecated void openIslandPermissionsMenu(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer); /** * Open the permissions-menu. * Used when changing island-permissions of an island-role on an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to change permissions in. * @param permissibleRole The island-role to change permissions for. */ void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, PlayerRole permissibleRole); /** * Open the island permissions menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island that holds the permissions. * @param playerRole The target role to see their permissions. * @deprecated see {@link #openPermissions(SuperiorPlayer, ISuperiorMenu, Island, PlayerRole)} */ @Deprecated void openIslandPermissionsMenu(SuperiorPlayer superiorPlayer, Island island, PlayerRole playerRole); /** * Refresh the permissions-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshPermissions(Island island); /** * Refresh the permissions-menu of a player for a specific island. * * @param island The island to refresh the menus for. * @param permissiblePlayer The player to change permissions. */ void refreshPermissions(Island island, SuperiorPlayer permissiblePlayer); /** * Refresh the permissions-menu of an island role for a specific island. * * @param island The island to refresh the menus for. * @param permissibleRole The island role to change permissions for. */ void refreshPermissions(Island island, PlayerRole permissibleRole); /** * Update the island permission in the menu. * * @param islandPrivilege The permission to update. */ void updatePermission(IslandPrivilege islandPrivilege); /** * Open the player-language menu. * Used when a player changes his language. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openPlayerLanguage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the language menu for a player. * * @param superiorPlayer The player to open the menu for. * @deprecated see {@link #openPlayerLanguage(SuperiorPlayer, ISuperiorMenu)} */ @Deprecated void openPlayerLanguageMenu(SuperiorPlayer superiorPlayer); /** * Open the island-settings menu. * Used when changing island-settings. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to change settings for. */ void openSettings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island settings menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the settings from. * @deprecated see {@link #openSettings(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandSettingsMenu(SuperiorPlayer superiorPlayer, Island island); /** * Refresh the island-settings menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshSettings(Island island); /** * Update the island settings in the menu. * * @param islandFlag The settings to update. */ @Deprecated void updateSettings(IslandFlag islandFlag); /** * Open the top-islands menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param sortingType The type of sorting of islands to use. */ void openTopIslands(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SortingType sortingType); /** * Open the islands top menu for a player. * * @param superiorPlayer The player to open the menu for. * @param sortingType The sorting type you want to open. * @deprecated see {@link #openTopIslands(SuperiorPlayer, ISuperiorMenu, SortingType)} */ @Deprecated void openIslandsTopMenu(SuperiorPlayer superiorPlayer, SortingType sortingType); /** * Refresh the top-islands menu for a specific sorting type. * * @param sortingType The sorting type to refresh. */ void refreshTopIslands(SortingType sortingType); /** * Open the unique-visitors menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get visitors from. */ void openUniqueVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the unique island visitors menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the visitors from. * @deprecated see {@link #openUniqueVisitors(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openUniqueVisitorsMenu(SuperiorPlayer superiorPlayer, Island island); /** * Refresh the unique-visitors menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshUniqueVisitors(Island island); /** * Open the upgrades-menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get upgrade levels from. */ void openUpgrades(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island upgrade menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the upgrades from. * @deprecated see {@link #openUpgrades(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandUpgradeMenu(SuperiorPlayer superiorPlayer, Island island); /** * Refresh the upgrades-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshUpgrades(Island island); /** * Open the values-menu. * Used when right-clicking an island in the top-islands menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get values from. */ void openValues(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the island values menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the values from. * @deprecated see {@link #openValues(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandValuesMenu(SuperiorPlayer superiorPlayer, Island island); /** * Refresh the values-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshValues(Island island); /** * Open the visitors-menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get visitors from. */ void openVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the visitors-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshVisitors(Island island); /** * Open the island visitors menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the visitors from. * @deprecated see {@link #openVisitors(SuperiorPlayer, ISuperiorMenu, Island)} */ @Deprecated void openIslandVisitorsMenu(SuperiorPlayer superiorPlayer, Island island); /** * Open the warp categories menu * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get warp categories from. */ void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the warp categories menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshWarpCategories(Island island); /** * Destroy the warp-categories menus for a specific island. * * @param island The island to close menus of. */ void destroyWarpCategories(Island island); /** * Open the warp-category icon edit menu. * Used when editing an icon of a warp category. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetCategory The warp category to edit the icon for. */ void openWarpCategoryIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory); /** * Open the warp category manage menu. * Used when managing a warp category. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetCategory The warp category to manage. */ void openWarpCategoryManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory); /** * Refresh the warp category manage menu for a specific warp category. * * @param warpCategory The warp category to refresh the menus for. */ void refreshWarpCategoryManage(WarpCategory warpCategory); /** * Open the warp icon edit menu. * Used when editing an icon of a warp. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetWarp The warp to edit the icon for. */ void openWarpIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp); /** * Open the warp manage menu. * Used when managing a warp. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetWarp The warp to manage. */ void openWarpManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp); /** * Refresh the warp manage menu for a specific warp. * * @param islandWarp The warp to refresh the menus for. */ void refreshWarpManage(IslandWarp islandWarp); /** * Open the warps menu. * Used to look for all warps in a category. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetCategory The category to get warps from. */ void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory); /** * Open the island warps menu for a player. * * @param superiorPlayer The player to open the menu for. * @param island The island to get the warps from. * @deprecated see {@link #openWarps(SuperiorPlayer, ISuperiorMenu, WarpCategory)} */ @Deprecated void openIslandWarpsMenu(SuperiorPlayer superiorPlayer, Island island); /** * Refresh the warps-menu for a specific island. * * @param warpCategory The warp category to refresh the menus for. */ void refreshWarps(WarpCategory warpCategory); /** * Destroy the warp-categories menus for a specific warp category. * * @param warpCategory The warp category to close menus of. */ void destroyWarps(WarpCategory warpCategory); /** * Register a new menu to the plugin. * * @param menu The menu to register. */ void registerMenu(Menu menu); /** * Get a menu by its identifier. * * @param identifier The identifier of the menu. */ @Nullable , A extends ViewArgs> Menu getMenu(String identifier); /** * Get all the registered menus. */ Map> getMenus(); /** * Get all the custom menus that were registered. */ Map> getCustomMenus(); /** * Create a new pattern builder for building a menu. */ > MenuLayout.Builder createPatternBuilder(); /** * Create a new pattern builder for building a paged-based menu. */ , E> PagedMenuLayout.Builder createPagedPatternBuilder(); /** * Create a new button builder. */ > MenuTemplateButton.Builder createButtonBuilder( Class viewButtonType, MenuTemplateButton.MenuViewButtonCreator viewButtonCreator); /** * Create a new button builder. */ , E> PagedMenuTemplateButton.Builder createPagedButtonBuilder( Class viewButtonType, PagedMenuTemplateButton.PagedMenuViewButtonCreator viewButtonCreator); /** * Get the parser instance. */ MenuParser getParser(); /** * Get the commands executor instance. */ MenuCommands getMenuCommands(); /** * Helper method to cast the new {@link MenuView} object to the old {@link ISuperiorMenu} object. */ @Deprecated ISuperiorMenu getOldMenuFromView(MenuView menuView); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/MissionsManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.List; import java.util.function.Consumer; public interface MissionsManager { /** * Get a mission by its name. * * @param name The name to check. */ @Nullable Mission getMission(String name); /** * Get a list of all the missions. */ List> getAllMissions(); /** * Get a list of all missions that are player missions. */ List> getPlayerMissions(); /** * Get a list of all missions that are island missions. */ List> getIslandMissions(); /** * Get a mission category by its name. * * @param name The name to check. */ @Nullable MissionCategory getMissionCategory(String name); /** * Get all the mission categories. */ List getMissionCategories(); /** * Check whether or not the player has already completed the mission. * * @param superiorPlayer The player to check. * @param mission The mission to check. * @return True if player has completed, otherwise false. */ boolean hasCompleted(SuperiorPlayer superiorPlayer, Mission mission); /** * Check whether or not a player can complete a mission. * * @param superiorPlayer The player to check. * @param mission The mission to check. * @return True if player can complete, otherwise false. */ boolean canComplete(SuperiorPlayer superiorPlayer, Mission mission); /** * Check whether or not a player can complete a mission, without considering progress. * * @param superiorPlayer The player to check. * @param mission The mission to check. * @return True if player can complete, otherwise false. */ boolean canCompleteNoProgress(SuperiorPlayer superiorPlayer, Mission mission); /** * Check whether or not the player can complete the mission again. * * @param superiorPlayer The player to check. * @param mission The mission to check. * @return True if player can complete, otherwise false. */ boolean canCompleteAgain(SuperiorPlayer superiorPlayer, Mission mission); /** * Check whether or not a player has all the required missions to complete a mission. * * @param superiorPlayer The player to check. * @param mission The mission to check. * @return True if player has all required missions, otherwise false. */ boolean hasAllRequiredMissions(SuperiorPlayer superiorPlayer, Mission mission); /** * Check whether or not a player can pass all the checks to complete a mission. * * @param superiorPlayer The player to check. * @param mission The mission to check. * @return True if player can pass all checks, otherwise false. */ boolean canPassAllChecks(SuperiorPlayer superiorPlayer, Mission mission); /** * Reward a player for completing a specific mission. * * @param mission The mission that was completed. * @param superiorPlayer The player to reward. * @param checkAutoReward Whether or not the auto reward flag should be checked. */ void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward); /** * Reward a player for completing a specific mission. * * @param mission The mission that was completed. * @param superiorPlayer The player to reward. * @param checkAutoReward Whether or not the auto reward flag should be checked. * @param forceReward Should the plugin force the reward to the player (no checks will be ran) */ void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward, boolean forceReward); /** * Reward a player for completing a specific mission. * * @param mission The mission that was completed. * @param superiorPlayer The player to reward. * @param checkAutoReward Whether or not the auto reward flag should be checked. * @param forceReward Should the plugin force the reward to the player (no checks will be ran) * @param result The result of the reward. */ void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward, boolean forceReward, @Nullable Consumer result); /** * Save all data related to missions. * All the data is saved into a yaml file. */ void saveMissionsData(); /** * Load all data related to missions. * All the data is loaded from a yaml file. */ void loadMissionsData(); /** * Load all data related to missions of specific missions. * All the data is loaded from a yaml file. */ void loadMissionsData(List> missionsList); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/ModulesManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.modules.ModuleLoadTime; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import java.io.File; import java.io.IOException; import java.util.Collection; public interface ModulesManager { /** * Register a new module to the plugin. * * @param pluginModule The module to register. */ void registerModule(PluginModule pluginModule); /** * Register a new module to the plugin from a file. * * @param moduleFile The module to register. */ PluginModule registerModule(File moduleFile) throws IOException, ReflectiveOperationException; /** * Unregister a module from the plugin. * * @param pluginModule The module to unregister. */ void unregisterModule(PluginModule pluginModule); /** * Get a module by its name. * * @param name The name of the module. */ @Nullable PluginModule getModule(String name); /** * Get all the active modules currently running. */ Collection getModules(); /** * Enable a specific module. * * @param pluginModule The module to load. */ void enableModule(PluginModule pluginModule); /** * Enable all modules with a specific module load time. * * @param moduleLoadTime The module load time to load modules with. */ void enableModules(ModuleLoadTime moduleLoadTime); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/PlayersManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.entity.Player; import java.util.List; import java.util.UUID; public interface PlayersManager { /** * Get a player by it's name. * * @param name The name to check. * @return The player with that name. */ @Nullable SuperiorPlayer getSuperiorPlayer(String name); /** * Get a player by a player. * * @param player The player to check. */ SuperiorPlayer getSuperiorPlayer(Player player); /** * Get a player by it's uuid. * * @param uuid The uuid to check. * @return The player with that uuid. */ SuperiorPlayer getSuperiorPlayer(UUID uuid); /** * Get all the players that joined the server. */ List getAllPlayers(); /** * Get a player role by it's weight. * * @param weight The weight to check. * @return The player role with that weight. */ @Nullable @Deprecated PlayerRole getPlayerRole(int weight); /** * Get a player role by it's id. * * @param id The id to check. * @return The player role with that weight. */ @Nullable @Deprecated PlayerRole getPlayerRoleFromId(int id); /** * Get a player role by it's name. * * @param name The name to check. * @return The player role with that name. * If there's no role with that name, IllegalArgumentException will be thrown. * @deprecated see {@link RolesManager} */ @Deprecated PlayerRole getPlayerRole(String name); /** * Get the default role that players are assigned with when they join an island. * * @deprecated see {@link RolesManager} */ @Deprecated PlayerRole getDefaultRole(); /** * Get the highest role in the ladder - aka, leader's role. * * @deprecated see {@link RolesManager} */ @Deprecated PlayerRole getLastRole(); /** * Get the guest's role. * * @deprecated see {@link RolesManager} */ @Deprecated PlayerRole getGuestRole(); /** * Get the co-op's role. * * @deprecated see {@link RolesManager} */ @Deprecated PlayerRole getCoopRole(); /** * Get a list of all the roles. * * @deprecated see {@link RolesManager} */ @Deprecated List getRoles(); /** * Get the players container. */ PlayersContainer getPlayersContainer(); /** * Set a new players container. * * @param playersContainer The new players container to set. */ void setPlayersContainer(PlayersContainer playersContainer); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/ProvidersManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.superiorskyblock.api.hooks.AFKProvider; import com.bgsoftware.superiorskyblock.api.hooks.ChunksProvider; import com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider; import com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider; import com.bgsoftware.superiorskyblock.api.hooks.MenusProvider; import com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider; import com.bgsoftware.superiorskyblock.api.hooks.PricesProvider; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider; import com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksProvider; import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.hooks.listener.ISkinsListener; import com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener; import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldsListener; import java.util.List; public interface ProvidersManager { /** * Get the currently used spawners-provider. */ SpawnersProvider getSpawnersProvider(); /** * Set custom spawners provider for the plugin. * * @param spawnersProvider The spawner provider to set. */ void setSpawnersProvider(SpawnersProvider spawnersProvider); /** * Get the currently used stacked-blocks provider. */ StackedBlocksProvider getStackedBlocksProvider(); /** * Set a custom stacked-blocks provider for the plugin. * * @param stackedBlocksProvider The stacked-blocks provider to set. */ void setStackedBlocksProvider(StackedBlocksProvider stackedBlocksProvider); /** * Get the currently used stacked-entities provider. */ List getEntitiesProviders(); /** * Add a custom entities provider for the plugin. * * @param entitiesProvider The entities provider to add. */ void addEntitiesProvider(EntitiesProvider entitiesProvider); /** * Get the currently used economy-provider. */ EconomyProvider getEconomyProvider(); /** * Set custom economy provider for the plugin. * * @param economyProvider The economy provider to set. */ void setEconomyProvider(EconomyProvider economyProvider); /** * Get the currently used worlds-provider. */ WorldsProvider getWorldsProvider(); /** * Set a custom worlds provider for the plugin. * * @param worldsProvider The worlds provider to set. */ void setWorldsProvider(WorldsProvider worldsProvider); /** * Get the currently used chunks-provider. */ ChunksProvider getChunksProvider(); /** * Set a custom chunks provider for the plugin. * * @param chunksProvider The chunks provider to set. */ void setChunksProvider(ChunksProvider chunksProvider); /** * Get the currently used bank-economy provider. */ EconomyProvider getBankEconomyProvider(); /** * Set custom economy provider for the island banks. * * @param economyProvider The economy provider to set. */ void setBankEconomyProvider(EconomyProvider economyProvider); /** * Get the currently used afk providers. */ List getAFKProviders(); /** * Add AFK Provider to the plugin. * * @param afkProvider The afk-provider to add. */ void addAFKProvider(AFKProvider afkProvider); /** * Get the currently used menus-provider. */ MenusProvider getMenusProvider(); /** * Set a new menus-provider to the plugin. * * @param menuProvider The new menus-provider to use. */ void setMenusProvider(MenusProvider menuProvider); /** * Get the currently used permissions-provider. */ PermissionsProvider getPermissionsProvider(); /** * Set a new permissions-provider to the plugin. * * @param permissionsProvider The new permissions-provider to use. */ void setPermissionsProvider(PermissionsProvider permissionsProvider); /** * Get the currently used prices-provider. */ PricesProvider getPricesProvider(); /** * Set a new prices-provider to the plugin. * * @param pricesProvider The new prices-provider to use. */ void setPricesProvider(PricesProvider pricesProvider); /** * Get the currently used vanish-provider. */ VanishProvider getVanishProvider(); /** * Set a new vanish-provider to the plugin. * * @param vanishProvider The new vanish-provider to use. */ void setVanishProvider(VanishProvider vanishProvider); /** * Register a new skins listener. * * @param skinsListener The new skins listener to register. */ void registerSkinsListener(ISkinsListener skinsListener); /** * Unregister a skins listener. * * @param skinsListener The new skins listener to unregister. */ void unregisterSkinsListener(ISkinsListener skinsListener); /** * Register a new stacked-blocks listener. * * @param stackedBlocksListener The new stacked-blocks listener to register. */ void registerStackedBlocksListener(IStackedBlocksListener stackedBlocksListener); /** * Unregister a stacked-blocks listener. * * @param stackedBlocksListener The stacked-blocks listener to unregister. */ void unregisterStackedBlocksListener(IStackedBlocksListener stackedBlocksListener); /** * Register a new worlds listener. * * @param worldsListener The new worlds listener to register. */ void registerWorldsListener(IWorldsListener worldsListener); /** * Unregister a worlds listener. * * @param worldsListener The worlds listener to unregister. */ void unregisterWorldsListener(IWorldsListener worldsListener); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/RolesManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import java.util.List; public interface RolesManager { /** * Get a player role by it's weight. * * @param weight The weight to check. * @return The player role with that weight. */ @Nullable PlayerRole getPlayerRole(int weight); /** * Get a player role by it's id. * * @param id The id to check. * @return The player role with that weight. */ @Nullable PlayerRole getPlayerRoleFromId(int id); /** * Get a player role by it's name. * * @param name The name to check. * @return The player role with that name. * If there's no role with that name, IllegalArgumentException will be thrown. */ PlayerRole getPlayerRole(String name); /** * Get the default role that players are assigned with when they join an island. */ PlayerRole getDefaultRole(); /** * Get the highest role in the ladder - aka, leader's role. */ PlayerRole getLastRole(); /** * Get the guest's role. */ PlayerRole getGuestRole(); /** * Get the co-op's role. */ PlayerRole getCoopRole(); /** * Get a list of all the roles. */ List getRoles(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/SchematicManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import java.util.List; public interface SchematicManager { /** * Get a schematic by it's name. * * @param name The name to check. * @return The schematic with that name. */ @Nullable Schematic getSchematic(String name); /** * Get a list of all the schematics. */ List getSchematics(); /** * Register a new schematic parser. * Files will be parsed using the registered schematics. The plugin will attempt to parse the schematic files * using each of the parsers in the same order they were registered. If no parsers are available, or no parser * could parse the file, the plugin will use the default parser. * * @param schematicParser The schematic-parser to register. */ void registerSchematicParser(SchematicParser schematicParser); /** * Get all the registered parsers, in the same order they were registered. */ List getSchematicParsers(); /** * Save a schematic. * Calls the {@link #saveSchematic(SuperiorPlayer, String, boolean)} with saveAir set to false. * * @param superiorPlayer The player who saves the schematic. * @param schematicName The schematic name. */ void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName); /** * Save a schematic. * Calls the {@link #saveSchematic(Location, Location, SchematicOptions, Runnable)} method with default values. * * @param superiorPlayer The player who saves the schematic. * @param schematicName The schematic name. * @param saveAir Whether to save air blocks into the schematic. */ void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName, boolean saveAir); /** * Save a schematic. * * @param pos1 First position for the schematic. * @param pos2 Second position for the schematic. * @param offsetX The offset x value for the schematic (from minimum location between the two) * @param offsetY The offset y value for the schematic (from minimum location between the two) * @param offsetZ The offset z value for the schematic (from minimum location between the two) * @param schematicName The new schematic name that will be created. */ void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, String schematicName); /** * Save a schematic. * * @param pos1 First position for the schematic. * @param pos2 Second position for the schematic. * @param offsetX The offset x value for the schematic (from minimum location between the two) * @param offsetY The offset y value for the schematic (from minimum location between the two) * @param offsetZ The offset z value for the schematic (from minimum location between the two) * @param yaw The yaw value of the schematic. * @param pitch The pitch value of the schematic. * @param schematicName The new schematic name that will be created. */ void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, String schematicName); /** * Save a schematic. * * @param pos1 First position for the schematic. * @param pos2 Second position for the schematic. * @param offsetX The offset x value for the schematic (from minimum location between the two) * @param offsetY The offset y value for the schematic (from minimum location between the two) * @param offsetZ The offset z value for the schematic (from minimum location between the two) * @param schematicName The new schematic name that will be created. * @param callable A runnable that will be ran after the task is completed. */ void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, String schematicName, Runnable callable); /** * Save a schematic. * * @param pos1 First position for the schematic. * @param pos2 Second position for the schematic. * @param offsetX The offset x value for the schematic (from minimum location between the two) * @param offsetY The offset y value for the schematic (from minimum location between the two) * @param offsetZ The offset z value for the schematic (from minimum location between the two) * @param yaw The yaw value of the schematic. * @param pitch The pitch value of the schematic. * @param schematicName The new schematic name that will be created. * @param callable A runnable that will be ran after the task is completed. */ void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, String schematicName, @Nullable Runnable callable); /** * Save a schematic. * * @param pos1 First position for the schematic. * @param pos2 Second position for the schematic. * @param schematicOptions The options for creating the new schematic. */ void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions); /** * Save a schematic. * * @param pos1 First position for the schematic. * @param pos2 Second position for the schematic. * @param schematicOptions The options for creating the new schematic. * @param callable A runnable that will be ran after the task is completed. */ void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions, @Nullable Runnable callable); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/StackedBlocksManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder; import com.bgsoftware.superiorskyblock.api.key.Key; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import java.util.Map; public interface StackedBlocksManager extends IDatabaseBridgeHolder { /** * Get the block amount in a specific block. * * @param block The block to check. */ int getStackedBlockAmount(Block block); /** * Get the block amount in a specific location. * * @param location The location to check. */ int getStackedBlockAmount(Location location); /** * Get the block's key in a specific location. * * @param location The location to check. */ @Nullable Key getStackedBlockKey(Location location); /** * Set a new amount for a specific block. * * @param block The block to set the amount to. * @param amount The new amount of the block. */ boolean setStackedBlock(Block block, int amount); /** * Set a new amount for a specific block. * * @param location The location of the block. * @param blockKey The key of the block. * @param amount The new amount of the block. * @return true on success. */ boolean setStackedBlock(Location location, Key blockKey, int amount); /** * Remove stacked block at a specific location. * * @param location The location of the stacked block. * @return The amount of the removed block, or 1 if there were no blocks in the specified location. */ int removeStackedBlock(Location location); /** * Remove stacked blocks at a specific chunk. * * @param chunk The chunk to remove stacked blocks from. * @return The stacked blocks in the provided chunk. */ Map removeStackedBlocks(Chunk chunk); /** * Remove stacked blocks at a specific chunk. * * @param world The world of the chunk. * @param chunkX The x-coords value of the chunk. * @param chunkZ The z-coords value of the chunk. * @return The stacked blocks in the provided chunk. */ Map removeStackedBlocks(World world, int chunkX, int chunkZ); /** * Get all the stacked blocks in a specific chunk. * * @param chunk The chunk to get stacked blocks from. */ Map getStackedBlocks(Chunk chunk); /** * Get all the stacked blocks in a specific chunk. * * @param world The world of the chunk. * @param chunkX The x-coords value of the chunk. * @param chunkZ The z-coords value of the chunk. */ Map getStackedBlocks(World world, int chunkX, int chunkZ); /** * Get all the stacked blocks on the server. */ Map getStackedBlocks(); /** * Update the hologram of a stacked block. * * @param location The location of the stacked block. */ void updateStackedBlockHologram(Location location); /** * Update the holograms of stacked-blocks in a specific chunk. * * @param chunk The chunk to update holograms in. */ void updateStackedBlockHolograms(Chunk chunk); /** * Remove the hologram of a stacked block. * * @param location The location of the stacked block. */ void removeStackedBlockHologram(Location location); /** * Remove the holograms of stacked-blocks in a specific chunk. * * @param chunk The chunk to update holograms in. */ void removeStackedBlockHolograms(Chunk chunk); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/UpgradesManager.java ================================================ package com.bgsoftware.superiorskyblock.api.handlers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; import java.util.Collection; public interface UpgradesManager { /** * Get an upgrade by it's name. * * @param upgradeName The name of the upgrade. */ @Nullable Upgrade getUpgrade(String upgradeName); /** * Get an upgrade by it's menu slot. * * @param slot The slot of the upgrade. */ @Nullable Upgrade getUpgrade(int slot); /** * Add a new upgrade. * * @param upgrade The upgrade to add. */ void addUpgrade(Upgrade upgrade); /** * Get an upgrade object that contains all the default values from config. */ Upgrade getDefaultUpgrade(); /** * Check whether or not an upgrade with the provided name exists or not. * * @param upgradeName The name to check. */ boolean isUpgrade(String upgradeName); /** * Get all the upgrades of the plugin. */ Collection getUpgrades(); /** * Register custom upgrade cost loader * * @param id The id of the loader. * @param costLoader the loader you're registering */ void registerUpgradeCostLoader(String id, UpgradeCostLoader costLoader); /** * Get all registered cost loader */ Collection getUpgradesCostLoaders(); /** * Get upgrade cost loader by its id */ @Nullable UpgradeCostLoader getUpgradeCostLoader(String id); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/AFKProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import org.bukkit.entity.Player; public interface AFKProvider { /** * Check whether a player is considered AFK. * * @param player The player to check. */ boolean isAFK(Player player); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/ChunksProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import org.bukkit.Chunk; import org.bukkit.World; import java.util.concurrent.CompletableFuture; public interface ChunksProvider { /** * Load a chunk in the world. * * @param world The world to load chunk from. * @param chunkX X-coords of the chunk. * @param chunkZ Z-coords of the chunk. * @return CompletableFuture of the chunk instance. */ CompletableFuture loadChunk(World world, int chunkX, int chunkZ); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/EconomyProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.math.BigDecimal; public interface EconomyProvider { /** * Get the amount of money a specific user has in his bank. * * @param superiorPlayer The player to check. */ BigDecimal getBalance(SuperiorPlayer superiorPlayer); /** * Deposit money into a player's bank. * * @param superiorPlayer The player to deposit money to. * @param amount The amount to deposit. * @return A result object for the transaction. */ EconomyResult depositMoney(SuperiorPlayer superiorPlayer, double amount); /** * Withdraw money from a player's bank. * * @param superiorPlayer The player to withdraw money from. * @param amount The amount to withdraw. * @return A result object for the transaction. */ EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, double amount); class EconomyResult { @Nullable private final String errorMessage; private final double transactionMoney; public EconomyResult(String errorMessage) { this(errorMessage, 0); } public EconomyResult(double transactionMoney) { this("", transactionMoney); } public EconomyResult(@Nullable String errorMessage, double transactionMoney) { this.errorMessage = errorMessage; this.transactionMoney = transactionMoney; } /** * Get the error that occurred. */ @Nullable public String getErrorMessage() { return errorMessage; } /** * Get the amount of money involved in the transaction. */ public double getTransactionMoney() { return transactionMoney; } /** * Check if the transaction has failed. */ public boolean hasFailed() { return errorMessage != null && !errorMessage.isEmpty(); } } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/EntitiesProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import org.bukkit.entity.Entity; public interface EntitiesProvider { /** * Should the plugin track the entity {@param entity}? * This is relevant for spawning, de-spawning and entity limits. *

* Please note: The entity provided to this function may be in unloaded chunks. * Do not attempt to change its attributes in this method in any way. * * @param entity The entity to check. */ boolean shouldTrackEntity(Entity entity); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import org.bukkit.World; public interface LazyWorldsProvider extends WorldsProvider { /** * Prepare world for teleportation. * * @param island The target island. * @param environment The environment of the world to prepare. * @param finishCallback Callback function after the preparation is finished. */ @Deprecated default void prepareWorld(Island island, World.Environment environment, Runnable finishCallback) { prepareWorld(island, Dimension.getByName(environment.name()), finishCallback); } /** * Prepare world for teleportation. * * @param island The target island. * @param dimension The dimension of the world to prepare. * @param finishCallback Callback function after the preparation is finished. */ void prepareWorld(Island island, Dimension dimension, Runnable finishCallback); /** * Get the {@link WorldInfo} of the world of an island by the environment. * The world does not have to be loaded. * * @param island The island to check. * @param environment The world environment. * @return The world info for the given environment, or null if this environment is not enabled. */ @Deprecated @Nullable default WorldInfo getIslandsWorldInfo(Island island, World.Environment environment) { return getIslandsWorldInfo(island, Dimension.getByName(environment.name())); } /** * Get the {@link WorldInfo} of the world of an island by the dimension. * The world does not have to be loaded. * * @param island The island to check. * @param dimension The world dimension. * @return The world info for the given dimension, or null if this dimension is not enabled. */ @Nullable WorldInfo getIslandsWorldInfo(Island island, Dimension dimension); /** * Get the {@link WorldInfo} of the world of an island by its name. * The world does not have to be loaded. * * @param island The island to check. * @param worldName The name of the world. * @return The world info for the given name, or null if this name is not an islands world. */ @Nullable WorldInfo getIslandsWorldInfo(Island island, String worldName); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public interface MenusProvider { /** * Initialize the menus. */ void initializeMenus(); /** * Open the bank-logs menu. * Used to display all logs of bank transactions. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to display bank logs for. */ void openBankLogs(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the bank-logs menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshBankLogs(Island island); /** * Open the biomes-menu. * Used to display and choose biomes for the island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to change biomes for. */ void openBiomes(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the border-color menu. * Used to change the color of the world border for a player. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openBorderColor(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the confirm-ban menu. * Used to confirm a ban of an island member. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to ban the player from. * @param bannedPlayer The player that will be banned. */ void openConfirmBan(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer bannedPlayer); /** * Open the confirm-disband menu. * Used to confirm disband of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to disband. */ void openConfirmDisband(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the confirm-kick menu. * Used to confirm a kick of an island member. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to kick the player from. * @param kickedPlayer The player that will be kicked. */ void openConfirmKick(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer kickedPlayer); /** * Open the confirm-leave menu. * Used to confirm leaving of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the confirm-transfer menu. * Used to confirm the transfer of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to ban the player from. * @param newOwner The player that will be banned. */ void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner); /** * Open the control-panel menu. * Used when opening the control panel of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to open the control panel of. */ void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the coops menu. * Used when opening the coops menu of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get coop-members from. */ void openCoops(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the coops-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshCoops(Island island); /** * Open the block-counts menu. * Used when opening the counts menu of an island (using /is counts, for example) * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get block counts from. */ void openCounts(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the counts-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshCounts(Island island); /** * Open the global-warps menu. * Used when running the /is warp command. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openGlobalWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Refresh the global-warps menu. */ void refreshGlobalWarps(); /** * Open the island-bank menu. * Used when running the /is bank command. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to open the bank for. */ void openIslandBank(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the island bank menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshIslandBank(Island island); /** * Open the island-banned-players menu. * Used when running the /is ban command. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to open the menu for. */ void openIslandBannedPlayers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the banned-players menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshIslandBannedPlayers(Island island); /** * Open the island-chests menu. * Used to open the shared chests menu of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to open the shared-chests menu for. */ void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the island-chests menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshIslandChest(Island island); /** * Get island creation config for specific schematic. * * @param schematic The schematic to get the creation config for. */ MenuIslandCreationConfig getIslandCreationConfig(Schematic schematic); /** * Open the islands-creation menu. * Used when creating a new island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param islandName The desired name of the new island. */ void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName); /** * Open the rate-menu. * Used when giving a rating for an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to give a rating. */ void openIslandRate(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Open the ratings-menu. * Used when checking given ratings of an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get ratings from. */ void openIslandRatings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the ratings-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshIslandRatings(Island island); /** * Open the member-manage menu. * Used when managing an island member. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param islandMember The island member to manage. */ void openMemberManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember); /** * Destroy the member-manage menus for a specific island member. * * @param islandMember The island member to close menus of. */ void destroyMemberManage(SuperiorPlayer islandMember); /** * Used to open the member-role menu. * Used when changing a role of an island member. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param islandMember The island member to change role for. */ void openMemberRole(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember); /** * Destroy the member-role menus for a specific island member. * * @param islandMember The island member to close menus of. */ void destroyMemberRole(SuperiorPlayer islandMember); /** * Open the members-menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to check the members of. */ void openMembers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the members-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshMembers(Island island); /** * Open the missions-menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the missions-menu of a specific category. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param missionCategory The category to get missions from. */ void openMissionsCategory(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, MissionCategory missionCategory); /** * Refresh the missions-menu for a specific category. * * @param missionCategory The category to refresh the menus for. */ void refreshMissionsCategory(MissionCategory missionCategory); /** * Open the permissions-menu. * Used when changing island-permissions of a player on an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to change permissions in. * @param permissiblePlayer The player to change permissions for. */ void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer permissiblePlayer); /** * Open the permissions-menu. * Used when changing island-permissions of an island-role on an island. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to change permissions in. * @param permissibleRole The island-role to change permissions for. */ void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, PlayerRole permissibleRole); /** * Refresh the permissions-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshPermissions(Island island); /** * Refresh the permissions-menu of a player for a specific island. * * @param island The island to refresh the menus for. * @param permissiblePlayer The player to change permissions. */ void refreshPermissions(Island island, SuperiorPlayer permissiblePlayer); /** * Refresh the permissions-menu of an island role for a specific island. * * @param island The island to refresh the menus for. * @param permissibleRole The island role to change permissions for. */ void refreshPermissions(Island island, PlayerRole permissibleRole); /** * Update the island permission in the menu. * * @param islandPrivilege The permission to update. */ void updatePermission(IslandPrivilege islandPrivilege); /** * Open the player-language menu. * Used when a player changes his language. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. */ void openPlayerLanguage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); /** * Open the island-settings menu. * Used when changing island-settings. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to change settings for. */ void openSettings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the island-settings menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshSettings(Island island); /** * Update the island settings in the menu. * * @param islandFlag The settings to update. */ void updateSettings(IslandFlag islandFlag); /** * Open the top-islands menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param sortingType The type of sorting of islands to use. */ void openTopIslands(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SortingType sortingType); /** * Refresh the top-islands menu for a specific sorting type. * * @param sortingType The sorting type to refresh. */ void refreshTopIslands(SortingType sortingType); /** * Open the unique-visitors menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get visitors from. */ void openUniqueVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the unique-visitors menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshUniqueVisitors(Island island); /** * Open the upgrades-menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get upgrade levels from. */ void openUpgrades(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the upgrades-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshUpgrades(Island island); /** * Open the values-menu. * Used when right-clicking an island in the top-islands menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get values from. */ void openValues(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the values-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshValues(Island island); /** * Open the visitors-menu. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get visitors from. */ void openVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the visitors-menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshVisitors(Island island); /** * Open the warp categories menu * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetIsland The island to get warp categories from. */ void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland); /** * Refresh the warp categories menu for a specific island. * * @param island The island to refresh the menus for. */ void refreshWarpCategories(Island island); /** * Destroy the warp-categories menus for a specific island. * * @param island The island to close menus of. */ void destroyWarpCategories(Island island); /** * Open the warp-category icon edit menu. * Used when editing an icon of a warp category. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetCategory The warp category to edit the icon for. */ void openWarpCategoryIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory); /** * Open the warp category manage menu. * Used when managing a warp category. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetCategory The warp category to manage. */ void openWarpCategoryManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory); /** * Refresh the warp category manage menu for a specific warp category. * * @param warpCategory The warp category to refresh the menus for. */ void refreshWarpCategoryManage(WarpCategory warpCategory); /** * Open the warp icon edit menu. * Used when editing an icon of a warp. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetWarp The warp to edit the icon for. */ void openWarpIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp); /** * Open the warp manage menu. * Used when managing a warp. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetWarp The warp to manage. */ void openWarpManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp); /** * Refresh the warp manage menu for a specific warp. * * @param islandWarp The warp to refresh the menus for. */ void refreshWarpManage(IslandWarp islandWarp); /** * Open the warps-menu. * Used to look for all warps in a category. * * @param targetPlayer The player to open the menu for. * @param previousMenu The previous menu that was opened, if exists. * @param targetCategory The category to get warps from. */ void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory); /** * Refresh the warps-menu for a specific island. * * @param warpCategory The warp category to refresh the menus for. */ void refreshWarps(WarpCategory warpCategory); /** * Destroy the warp-categories menus for a specific warp category. * * @param warpCategory The warp category to close menus of. */ void destroyWarps(WarpCategory warpCategory); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/PermissionsProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import org.bukkit.entity.Player; public interface PermissionsProvider { /** * Check whether a player has permission. * * @param player The player to check permissions for. * @param permission The permission to check. * @return whether the player has permission excluding his operator status. * This means that the permission must be given explicitly to the player for the method to return true. */ boolean hasPermission(Player player, String permission); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/PricesProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import java.math.BigDecimal; import java.util.concurrent.CompletableFuture; public interface PricesProvider { /** * Get price of a block/item. * * @param key The key of the block or the item. * @return The price of that block/item. */ BigDecimal getPrice(Key key); /** * Get the correct block-key for a price. * Mostly used for legacy-versions where data values of blocks can be ignored. * * @param blockKey The original block-key. * @return The correct-block key for a price. */ @Nullable Key getBlockKey(Key blockKey); /** * Get a CompletableFuture that is completed when all prices and data of this provider are ready. */ default CompletableFuture getWhenPricesAreReady() { return CompletableFuture.completedFuture(null); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/SpawnersProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.objects.Pair; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; public interface SpawnersProvider { /** * Get a pair that represents information about a spawner in a specific location. * This method is called async first, and if the string in the pair is null, it will be called synced later. * The integer represents the amount of spawners in that location, and the string represents the entity type. * * @param location The location to check. */ Pair getSpawner(Location location); /** * Get the spawner type from an item. * May return null in-case the spawner has no entity inside it. * * @param itemStack The item to check. */ @Nullable String getSpawnerType(ItemStack itemStack); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/SpawnersSnapshotProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import org.bukkit.Chunk; import org.bukkit.World; /** * SpawnersProvider based on snapshots, similar concept to ChunkSnapshot from Bukkit. * The plugin will take a snapshot when calculating a chunk, and will release it once it's done * calculation of that chunk. Snapshots are taken sync, however reading them is done async. * Thread-safety must be implemented in order to not get weird issues. */ public interface SpawnersSnapshotProvider extends SpawnersProvider { /** * Take a snapshot of a chunk. * * @param chunk The chunk to take a snapshot of. */ void takeSnapshot(Chunk chunk); /** * Release a snapshot of a chunk. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ void releaseSnapshot(World world, int chunkX, int chunkZ); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/StackedBlocksProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import org.bukkit.World; import java.util.Collection; public interface StackedBlocksProvider { /** * Get all stacked blocks in a chunk. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @return Collection of pairs representing the stacked blocks. * The key of the pair is a Key object of the block. * The value of the pair is the amount of the block. */ Collection> getBlocks(World world, int chunkX, int chunkZ); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/StackedBlocksSnapshotProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import org.bukkit.Chunk; import org.bukkit.World; /** * StackedBlocksProvider based on snapshots, similar concept to ChunkSnapshot from Bukkit. * The plugin will take a snapshot when calculating a chunk, and will release it once it's done * calculation of that chunk. Snapshots are taken sync, however reading them is done async. * Thread-safety must be implemented in order to not get weird issues. */ public interface StackedBlocksSnapshotProvider extends StackedBlocksProvider { /** * Take a snapshot of a chunk. * * @param chunk The chunk to take a snapshot of. */ void takeSnapshot(Chunk chunk); /** * Release a snapshot of a chunk. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ void releaseSnapshot(World world, int chunkX, int chunkZ); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/VanishProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import org.bukkit.entity.Player; public interface VanishProvider { /** * Check whether a player is vanished from online players. * * @param player The player to check */ boolean isVanished(Player player); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import org.bukkit.Location; import org.bukkit.World; import java.util.UUID; public interface WorldsProvider { /** * Prepare all the island worlds on startup. */ void prepareWorlds(); /** * Get the world of an island by the dimension. * If the world is not loaded, this method should load the world before returning. * * @param dimension The world dimension. * @param island The island to check. */ @Nullable World getIslandsWorld(Island island, Dimension dimension); /** * Get the world of an island by the environment. * If the world is not loaded, this method should load the world before returning. * * @param environment The world environment. * @param island The island to check. */ @Deprecated @Nullable default World getIslandsWorld(Island island, World.Environment environment) { return getIslandsWorld(island, Dimension.getByName(environment.name())); } /** * Get the dimension of an islands world. * If the island is not an islands world, null will be returned. * * @param world The world to check. */ @Nullable Dimension getIslandsWorldDimension(World world); /** * Checks if the given world is an islands world. * * @param world The world to check. */ boolean isIslandsWorld(World world); /** * Get the location for a new island that is created. * * @param previousLocation The location of the previous island that was created. * @param islandsHeight The default islands height. * @param maxIslandSize The default maximum island size. * @param islandOwner The owner of the island. * @param islandUUID The UUID of the island. * @deprecated See {@link #getNextLocation(BlockPosition, int, int, UUID, UUID)} */ default Location getNextLocation(Location previousLocation, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID) { return getNextLocation(SuperiorSkyblockAPI.getFactory().createBlockPosition(previousLocation), islandsHeight, maxIslandSize, islandOwner, islandUUID); } /** * Get the location for a new island that is created. * * @param previousPosition The position of the previous island that was created. * @param islandsHeight The default islands height. * @param maxIslandSize The default maximum island size. * @param islandOwner The owner of the island. * @param islandUUID The UUID of the island. */ Location getNextLocation(BlockPosition previousPosition, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID); /** * Callback upon finishing of creation of islands. * * @param islandLocation The location of the new island. * @param islandOwner The owner of the island. * @param islandUUID The UUID of the island. */ void finishIslandCreation(Location islandLocation, UUID islandOwner, UUID islandUUID); /** * Prepare teleportation of an entity to an island. * * @param island The target island. * @param location The location that the entity will be teleported to. * @param finishCallback Callback function after the preparation is finished. */ void prepareTeleport(Island island, Location location, Runnable finishCallback); /** * Check whether or not normal worlds are enabled. */ default boolean isNormalEnabled() { return isDimensionEnabled(Dimension.getByName("NORMAL")); } /** * Check whether or not normal worlds are unlocked for islands by default. */ default boolean isNormalUnlocked() { return isDimensionUnlocked(Dimension.getByName("NORMAL")); } /** * Check whether or not nether worlds are enabled. */ default boolean isNetherEnabled() { return isDimensionEnabled(Dimension.getByName("NETHER")); } /** * Check whether or not nether worlds are unlocked for islands by default. */ default boolean isNetherUnlocked() { return isDimensionUnlocked(Dimension.getByName("NETHER")); } /** * Check whether or not end worlds are enabled. */ default boolean isEndEnabled() { return isDimensionEnabled(Dimension.getByName("THE_END")); } /** * Check whether or not end worlds are unlocked for islands by default. */ default boolean isEndUnlocked() { return isDimensionUnlocked(Dimension.getByName("THE_END")); } /** * Check whether a dimension is enabled on the server. * * @param dimension The dimension to check. */ boolean isDimensionEnabled(Dimension dimension); /** * Check whether a dimension is unlocked for islands by default. */ boolean isDimensionUnlocked(Dimension dimension); /** * Add a listener to when worlds are loaded by the provider. * This is called by the plugin to listen to changes and fix things within island worlds. * * @param worldLoadListener The callback to listener. */ default void addWorldLoadListener(IWorldLoadListener worldLoadListener) { throw new UnsupportedOperationException("This operation is not supported by this WorldProvider."); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/ISkinsListener.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks.listener; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; /** * Listener for changes of skins of players. */ public interface ISkinsListener { /** * Update the skin of a player. * * @param superiorPlayer The player to update the skin for. */ void setSkinTexture(SuperiorPlayer superiorPlayer); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IStackedBlocksListener.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks.listener; import org.bukkit.OfflinePlayer; import org.bukkit.block.Block; /** * Listener for changes of stacked-blocks */ public interface IStackedBlocksListener { /** * Record a block-action related to stacked-blocks. * * @param offlinePlayer The player that interacted with the stacked-block. * @param block The stacked-block * @param action The action that was performed. */ void recordBlockAction(OfflinePlayer offlinePlayer, Block block, Action action); enum Action { BLOCK_PLACE, BLOCK_BREAK } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IWorldLoadListener.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks.listener; import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.World; /** * Listener used for {@link WorldsProvider#addWorldLoadListener(IWorldLoadListener)} */ public interface IWorldLoadListener { /** * The method to be called when a world is loaded. * * @param world The world that was loaded. * @param worldDimension The dimension of the world. * @param flags Flags to what the listener can do. More info at {@link WorldLoadFlags} */ void onWorldLoad(World world, Dimension worldDimension, @WorldLoadFlags int flags); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IWorldsListener.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks.listener; /** * Listener for updates of worlds. */ public interface IWorldsListener { /** * Load a world. * * @param worldName the name of the world to load. */ void loadWorld(String worldName); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/world/WorldLoadFlags.java ================================================ package com.bgsoftware.superiorskyblock.api.hooks.world; import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; /** * The integer value element annotated with {@link WorldLoadFlags} represents flags related to what to do * when a world is loaded. It is mainly used within the default {@link IWorldLoadListener} interface of the plugin. */ public @interface WorldLoadFlags { /** * Enable dragon fights for end worlds. */ int END_DRAGON_FIGHT = 1 << 0; /** * Remove the anti-xray world patches. */ int REMOVE_ANTI_XRAY = 1 << 1; /** * Update the ocean level of the world to the configured islands-height. */ int UPDATE_OCEAN_LEVEL = 1 << 2; /** * Make the plugin listen to block neighbor changes and self-changing blocks. */ int LISTEN_BLOCK_CHANGES = 1 << 3; } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/BlockChangeResult.java ================================================ package com.bgsoftware.superiorskyblock.api.island; /** * Result of one of the block change methods of {@link Island} */ public enum BlockChangeResult { /** * No blocks were available in the block counts map provided. */ NO_AVAILABLE_BLOCKS, /** * The block provided had no value configured for it and therefore was not tracked. */ MISSING_BLOCK_VALUE, /** * Tried to track a block change for the spawn island. */ SPAWN_ISLAND, /** * The block change was tracked successfully. */ SUCCESS } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.annotations.Size; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public class DelegateIsland implements Island { protected final Island handle; protected DelegateIsland(Island handle) { this.handle = handle; } @Override public SuperiorPlayer getOwner() { return this.handle.getOwner(); } @Override public UUID getUniqueId() { return this.handle.getUniqueId(); } @Override public long getCreationTime() { return this.handle.getCreationTime(); } @Override public String getCreationTimeDate() { return this.handle.getCreationTimeDate(); } @Override public void updateDatesFormatter() { this.handle.updateDatesFormatter(); } @Override public IslandCache getCache() { return this.handle.getCache(); } @Override public List getIslandMembers(boolean includeOwner) { return this.handle.getIslandMembers(includeOwner); } @Override public List getIslandMembers(PlayerRole... playerRoles) { return this.handle.getIslandMembers(playerRoles); } @Override public List getBannedPlayers() { return this.handle.getBannedPlayers(); } @Override public List getIslandVisitors() { return this.handle.getIslandVisitors(); } @Override public List getIslandVisitors(boolean vanishPlayers) { return this.handle.getIslandVisitors(vanishPlayers); } @Override public List getAllPlayersInside() { return this.handle.getAllPlayersInside(); } @Override public List getUniqueVisitors() { return this.handle.getUniqueVisitors(); } @Override public List> getUniqueVisitorsWithTimes() { return this.handle.getUniqueVisitorsWithTimes(); } @Override public void inviteMember(SuperiorPlayer superiorPlayer) { this.handle.inviteMember(superiorPlayer); } @Override public void revokeInvite(SuperiorPlayer superiorPlayer) { this.handle.revokeInvite(superiorPlayer); } @Override public boolean isInvited(SuperiorPlayer superiorPlayer) { return this.handle.isInvited(superiorPlayer); } @Override public List getInvitedPlayers() { return this.handle.getInvitedPlayers(); } @Override public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { this.handle.addMember(superiorPlayer, playerRole); } @Override @Deprecated public void kickMember(SuperiorPlayer superiorPlayer) { this.handle.kickMember(superiorPlayer); } @Override public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason) { this.handle.removeMember(superiorPlayer, memberRemoveReason); } @Override public boolean isMember(SuperiorPlayer superiorPlayer) { return this.handle.isMember(superiorPlayer); } @Override public void banMember(SuperiorPlayer superiorPlayer) { this.handle.banMember(superiorPlayer); } @Override public void banMember(SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer whom) { this.handle.banMember(superiorPlayer, whom); } @Override public void unbanMember(SuperiorPlayer superiorPlayer) { this.handle.unbanMember(superiorPlayer); } @Override public boolean isBanned(SuperiorPlayer superiorPlayer) { return this.handle.isBanned(superiorPlayer); } @Override public void addCoop(SuperiorPlayer superiorPlayer) { this.handle.addCoop(superiorPlayer); } @Override public void removeCoop(SuperiorPlayer superiorPlayer) { this.handle.removeCoop(superiorPlayer); } @Override public boolean isCoop(SuperiorPlayer superiorPlayer) { return this.handle.isCoop(superiorPlayer); } @Override public List getCoopPlayers() { return this.handle.getCoopPlayers(); } @Override public int getCoopLimit() { return this.handle.getCoopLimit(); } @Override public int getCoopLimitRaw() { return this.handle.getCoopLimitRaw(); } @Override public void setCoopLimit(int coopLimit) { this.handle.setCoopLimit(coopLimit); } @Override public void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside) { this.handle.setPlayerInside(superiorPlayer, inside); } @Override public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean checkCoopStatus) { return this.handle.isVisitor(superiorPlayer, checkCoopStatus); } @Override public Location getCenter(Dimension dimension) { return this.handle.getCenter(dimension); } @Override public BlockPosition getCenterPosition() { return this.handle.getCenterPosition(); } @Override public CompletableFuture accessIslandWorld(Dimension dimension) { return this.handle.accessIslandWorld(dimension); } @Override public Location getIslandHome(Dimension dimension) { return this.handle.getIslandHome(dimension); } @Override public WorldPosition getIslandHomePosition(Dimension dimension) { return this.handle.getIslandHomePosition(dimension); } @Override public Map getIslandHomesAsDimensions() { return this.handle.getIslandHomesAsDimensions(); } @Override public Map getIslandHomes() { return this.handle.getIslandHomes(); } @Override public void setIslandHome(Location homeLocation) { this.handle.setIslandHome(homeLocation); } @Override @Deprecated public void setIslandHome(Dimension dimension, Location homeLocation) { this.handle.setIslandHome(dimension, homeLocation); } @Override public void setIslandHome(Dimension dimension, WorldPosition homePosition) { this.handle.setIslandHome(dimension, homePosition); } @Override public Location getVisitorsLocation(Dimension dimension) { return this.handle.getVisitorsLocation(dimension); } @Override public WorldPosition getVisitorsPosition(Dimension dimension) { return this.handle.getVisitorsPosition(dimension); } @Override public void setVisitorsLocation(@Nullable Location visitorsLocation) { this.handle.setVisitorsLocation(visitorsLocation); } @Override public void setVisitorsLocation(Dimension dimension, WorldPosition visitorsPosition) { this.handle.setVisitorsLocation(dimension, visitorsPosition); } @Override public Location getMinimum() { return this.handle.getMinimum(); } @Override public BlockPosition getMinimumPosition() { return this.handle.getMinimumPosition(); } @Override public Location getMinimumProtected() { return this.handle.getMinimumProtected(); } @Override public BlockPosition getMinimumProtectedPosition() { return this.handle.getMinimumProtectedPosition(); } @Override public Location getMaximum() { return this.handle.getMaximum(); } @Override public BlockPosition getMaximumPosition() { return this.handle.getMaximumPosition(); } @Override public Location getMaximumProtected() { return this.handle.getMaximumProtected(); } @Override public BlockPosition getMaximumProtectedPosition() { return this.handle.getMaximumProtectedPosition(); } @Override public List getAllChunks() { return this.handle.getAllChunks(); } @Override public List getAllChunks(@IslandChunkFlags int flags) { return this.handle.getAllChunks(flags); } @Override public List getAllChunks(Dimension dimension) { return this.handle.getAllChunks(dimension); } @Override public List getAllChunks(Dimension dimension, @IslandChunkFlags int flags) { return this.handle.getAllChunks(dimension, flags); } @Override public List getLoadedChunks() { return this.handle.getLoadedChunks(); } @Override public List getLoadedChunks(@IslandChunkFlags int flags) { return this.handle.getLoadedChunks(flags); } @Override public List getLoadedChunks(Dimension dimension) { return this.handle.getLoadedChunks(dimension); } @Override public List getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags) { return this.handle.getLoadedChunks(dimension, flags); } @Override public List> getAllChunksAsync(Dimension dimension) { return this.handle.getAllChunksAsync(dimension); } @Override public List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags) { return this.handle.getAllChunksAsync(dimension, flags); } @Override public List> getAllChunksAsync(Dimension dimension, Consumer onChunkLoad) { return this.handle.getAllChunksAsync(dimension, onChunkLoad); } @Override public List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags, Consumer onChunkLoad) { return this.handle.getAllChunksAsync(dimension, flags, onChunkLoad); } @Override public void resetChunks() { this.handle.resetChunks(); } @Override public void resetChunks(@Nullable Runnable onFinish) { this.handle.resetChunks(onFinish); } @Override public void resetChunks(Dimension dimension) { this.handle.resetChunks(dimension); } @Override public void resetChunks(Dimension dimension, Runnable onFinish) { this.handle.resetChunks(dimension, onFinish); } @Override public void resetChunks(@IslandChunkFlags int flags) { this.handle.resetChunks(flags); } @Override public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) { this.handle.resetChunks(flags, onFinish); } @Override public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) { this.handle.resetChunks(dimension, flags); } @Override public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, Runnable onFinish) { this.handle.resetChunks(dimension, flags, onFinish); } @Override public boolean isInside(Location location) { return this.handle.isInside(location); } @Override public boolean isInside(Location location, int extraRadius) { return this.handle.isInside(location, extraRadius); } @Override public boolean isInside(Location location, double extraRadius) { return this.handle.isInside(location, extraRadius); } @Override public boolean isInside(BlockPosition blockPosition) { return this.handle.isInside(blockPosition); } @Override public boolean isInside(BlockPosition blockPosition, int extraRadius) { return this.handle.isInside(blockPosition, extraRadius); } @Override public boolean isInside(BlockPosition blockPosition, double extraRadius) { return this.handle.isInside(blockPosition, extraRadius); } @Override public boolean isInside(WorldPosition worldPosition) { return this.handle.isInside(worldPosition); } @Override public boolean isInside(WorldPosition worldPosition, int extraRadius) { return this.handle.isInside(worldPosition, extraRadius); } @Override public boolean isInside(WorldPosition worldPosition, double extraRadius) { return this.handle.isInside(worldPosition, extraRadius); } @Override public boolean isInside(Chunk chunk) { return this.handle.isInside(chunk); } @Override public boolean isInside(World world, int chunkX, int chunkZ) { return this.handle.isInside(world, chunkX, chunkZ); } @Override public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) { return this.handle.isInside(world, chunkX, chunkZ, extraRadius); } @Override public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) { return this.handle.isInside(world, chunkX, chunkZ, extraRadius); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { return this.handle.isInside(worldInfo, chunkX, chunkZ); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { return this.handle.isInside(worldInfo, chunkX, chunkZ, extraRadius); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { return this.handle.isInside(worldInfo, chunkX, chunkZ, extraRadius); } @Override public boolean isInside(int chunkX, int chunkZ) { return this.handle.isInside(chunkX, chunkZ); } @Override public boolean isInside(int chunkX, int chunkZ, int extraRadius) { return this.handle.isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInside(int chunkX, int chunkZ, double extraRadius) { return this.handle.isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(Location location) { return this.handle.isInsideRange(location); } @Override public boolean isInsideRange(Location location, int extraRadius) { return this.handle.isInsideRange(location, extraRadius); } @Override public boolean isInsideRange(Location location, double extraRadius) { return this.handle.isInsideRange(location, extraRadius); } @Override public boolean isInsideRange(BlockPosition blockPosition) { return this.handle.isInsideRange(blockPosition); } @Override public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) { return this.handle.isInsideRange(blockPosition, extraRadius); } @Override public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) { return this.handle.isInsideRange(blockPosition, extraRadius); } @Override public boolean isInsideRange(WorldPosition worldPosition) { return this.handle.isInsideRange(worldPosition); } @Override public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) { return this.handle.isInsideRange(worldPosition, extraRadius); } @Override public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) { return this.handle.isInsideRange(worldPosition, extraRadius); } @Override public boolean isInsideRange(Chunk chunk) { return this.handle.isInsideRange(chunk); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ) { return this.handle.isInsideRange(world, chunkX, chunkZ); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) { return this.handle.isInsideRange(world, chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) { return this.handle.isInsideRange(world, chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) { return this.handle.isInsideRange(worldInfo, chunkX, chunkZ); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { return this.handle.isInsideRange(worldInfo, chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { return this.handle.isInsideRange(worldInfo, chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(int chunkX, int chunkZ) { return this.handle.isInsideRange(chunkX, chunkZ); } @Override public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) { return this.handle.isInsideRange(chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) { return this.handle.isInsideRange(chunkX, chunkZ, extraRadius); } @Override @Deprecated public boolean isNormalEnabled() { return this.handle.isNormalEnabled(); } @Override @Deprecated public void setNormalEnabled(boolean enabled) { this.handle.setNormalEnabled(enabled); } @Override @Deprecated public boolean isNetherEnabled() { return this.handle.isNetherEnabled(); } @Override @Deprecated public void setNetherEnabled(boolean enabled) { this.handle.setNetherEnabled(enabled); } @Override @Deprecated public boolean isEndEnabled() { return this.handle.isEndEnabled(); } @Override @Deprecated public void setEndEnabled(boolean enabled) { this.handle.setEndEnabled(enabled); } @Override public boolean isDimensionEnabled(Dimension dimension) { return this.handle.isDimensionEnabled(dimension); } @Override public void setDimensionEnabled(Dimension dimension, boolean enabled) { this.handle.setDimensionEnabled(dimension, enabled); } @Override public Collection getUnlockedWorlds() { return this.handle.getUnlockedWorlds(); } @Override public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege) { return this.handle.hasPermission(sender, islandPrivilege); } @Override public boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege) { return this.handle.hasPermission(superiorPlayer, islandPrivilege); } @Override public boolean hasPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) { return this.handle.hasPermission(playerRole, islandPrivilege); } @Override @Deprecated public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege, boolean value) { this.handle.setPermission(playerRole, islandPrivilege, value); } @Override public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) { this.handle.setPermission(playerRole, islandPrivilege); } @Override public void resetPermissions() { this.handle.resetPermissions(); } @Override public void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value) { this.handle.setPermission(superiorPlayer, islandPrivilege, value); } @Override public void resetPermissions(SuperiorPlayer superiorPlayer) { this.handle.resetPermissions(superiorPlayer); } @Override public PermissionNode getPermissionNode(SuperiorPlayer superiorPlayer) { return this.handle.getPermissionNode(superiorPlayer); } @Override public PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege) { return this.handle.getRequiredPlayerRole(islandPrivilege); } @Override public Map getPlayerPermissions() { return this.handle.getPlayerPermissions(); } @Override public Map getRolePermissions() { return this.handle.getRolePermissions(); } @Override public boolean isSpawn() { return this.handle.isSpawn(); } @Override public String getName() { return this.handle.getName(); } @Override public void setName(String islandName) { this.handle.setName(islandName); } @Override @Deprecated public String getRawName() { return this.handle.getRawName(); } @Override public String getStrippedName() { return this.handle.getStrippedName(); } @Override public String getFormattedName() { return this.handle.getFormattedName(); } @Override public String getDescription() { return this.handle.getDescription(); } @Override public void setDescription(String description) { this.handle.setDescription(description); } @Override public void disbandIsland() { this.handle.disbandIsland(); } @Override public boolean transferIsland(SuperiorPlayer superiorPlayer) { return this.handle.transferIsland(superiorPlayer); } @Override public void replacePlayers(SuperiorPlayer originalPlayer, SuperiorPlayer newPlayer) { this.handle.replacePlayers(originalPlayer, newPlayer); } @Override public void calcIslandWorth(@Nullable SuperiorPlayer asker) { this.handle.calcIslandWorth(asker); } @Override public void calcIslandWorth(@Nullable SuperiorPlayer asker, @Nullable Runnable callback) { this.handle.calcIslandWorth(asker, callback); } @Override public IslandCalculationAlgorithm getCalculationAlgorithm() { return this.handle.getCalculationAlgorithm(); } @Override public void updateBorder() { this.handle.updateBorder(); } @Override public void updateIslandFly(SuperiorPlayer superiorPlayer) { this.handle.updateIslandFly(superiorPlayer); } @Override public int getIslandSize() { return this.handle.getIslandSize(); } @Override public void setIslandSize(int islandSize) { this.handle.setIslandSize(islandSize); } @Override public int getIslandSizeRaw() { return this.handle.getIslandSizeRaw(); } @Override public String getDiscord() { return this.handle.getDiscord(); } @Override public void setDiscord(String discord) { this.handle.setDiscord(discord); } @Override public String getPaypal() { return this.handle.getPaypal(); } @Override public void setPaypal(String paypal) { this.handle.setPaypal(paypal); } @Override public Biome getBiome() { return this.handle.getBiome(); } @Override public void setBiome(Biome biome) { this.handle.setBiome(biome); } @Override public void setBiome(Biome biome, boolean updateBlocks) { this.handle.setBiome(biome, updateBlocks); } @Override public boolean isLocked() { return this.handle.isLocked(); } @Override public void setLocked(boolean locked) { this.handle.setLocked(locked); } @Override public boolean isIgnored() { return this.handle.isIgnored(); } @Override public void setIgnored(boolean ignored) { this.handle.setIgnored(ignored); } @Override public void sendMessage(String message) { this.handle.sendMessage(message); } @Override public void sendMessage(String message, UUID... ignoredMembers) { this.handle.sendMessage(message, ignoredMembers); } @Override public void sendMessage(IMessageComponent messageComponent) { this.handle.sendMessage(messageComponent); } @Override public void sendMessage(IMessageComponent messageComponent, Object... args) { this.handle.sendMessage(messageComponent, args); } @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers) { this.handle.sendMessage(messageComponent, ignoredMembers); } @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers, Object... args) { this.handle.sendMessage(messageComponent, ignoredMembers, args); } @Override public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut) { this.handle.sendTitle(title, subtitle, fadeIn, duration, fadeOut); } @Override public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers) { this.handle.sendTitle(title, subtitle, fadeIn, duration, fadeOut, ignoredMembers); } @Override public void executeCommand(String command, boolean onlyOnlineMembers) { this.handle.executeCommand(command, onlyOnlineMembers); } @Override public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) { this.handle.executeCommand(command, onlyOnlineMembers, ignoredMembers); } @Override public boolean isBeingRecalculated() { return this.handle.isBeingRecalculated(); } @Override public void updateLastTime() { this.handle.updateLastTime(); } @Override public void setCurrentlyActive() { this.handle.setCurrentlyActive(); } @Override public void completeMission(Mission mission) { this.handle.completeMission(mission); } @Override public void setCurrentlyActive(boolean active) { this.handle.setCurrentlyActive(active); } @Override public void resetMission(Mission mission) { this.handle.resetMission(mission); } @Override public boolean isCurrentlyActive() { return this.handle.isCurrentlyActive(); } @Override public boolean hasCompletedMission(Mission mission) { return this.handle.hasCompletedMission(mission); } @Override public long getLastTimeUpdate() { return this.handle.getLastTimeUpdate(); } @Override public boolean canCompleteMissionAgain(Mission mission) { return this.handle.canCompleteMissionAgain(mission); } @Override public void setLastTimeUpdate(long lastTimeUpdate) { this.handle.setLastTimeUpdate(lastTimeUpdate); } @Override public int getAmountMissionCompleted(Mission mission) { return this.handle.getAmountMissionCompleted(mission); } @Override public IslandBank getIslandBank() { return this.handle.getIslandBank(); } @Override public void setAmountMissionCompleted(Mission mission, int finishCount) { this.handle.setAmountMissionCompleted(mission, finishCount); } @Override public BigDecimal getBankLimit() { return this.handle.getBankLimit(); } @Override public List> getCompletedMissions() { return this.handle.getCompletedMissions(); } @Override public void setBankLimit(BigDecimal bankLimit) { this.handle.setBankLimit(bankLimit); } @Override public Map, Integer> getCompletedMissionsWithAmounts() { return this.handle.getCompletedMissionsWithAmounts(); } @Override public BigDecimal getBankLimitRaw() { return this.handle.getBankLimitRaw(); } @Override public DatabaseBridge getDatabaseBridge() { return this.handle.getDatabaseBridge(); } @Override public boolean giveInterest(boolean checkOnlineOwner) { return this.handle.giveInterest(checkOnlineOwner); } @Override public PersistentDataContainer getPersistentDataContainer() { return this.handle.getPersistentDataContainer(); } @Override public long getLastInterestTime() { return this.handle.getLastInterestTime(); } @Override public boolean isPersistentDataContainerEmpty() { return this.handle.isPersistentDataContainerEmpty(); } @Override public void setLastInterestTime(long lastInterest) { this.handle.setLastInterestTime(lastInterest); } @Override public void savePersistentDataContainer() { this.handle.savePersistentDataContainer(); } @Override public long getNextInterest() { return this.handle.getNextInterest(); } @Override public void handleBlockPlace(Block block) { this.handle.handleBlockPlace(block); } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block) { return this.handle.handleBlockPlaceWithResult(block); } @Override public void handleBlockPlace(Key key) { this.handle.handleBlockPlace(key); } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key) { return this.handle.handleBlockPlaceWithResult(key); } @Override public void handleBlockPlace(Block block, @Size int amount) { this.handle.handleBlockPlace(block, amount); } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount) { return this.handle.handleBlockPlaceWithResult(block, amount); } @Override public void handleBlockPlace(Key key, @Size int amount) { this.handle.handleBlockPlace(key, amount); } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount) { return this.handle.handleBlockPlaceWithResult(key, amount); } @Override public void handleBlockPlace(Block block, @Size int amount, @IslandBlockFlags int flags) { this.handle.handleBlockPlace(block, amount, flags); } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount, @IslandBlockFlags int flags) { return this.handle.handleBlockPlaceWithResult(block, amount, flags); } @Override public void handleBlockPlace(Key key, @Size int amount, @IslandBlockFlags int flags) { this.handle.handleBlockPlace(key, amount, flags); } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @IslandBlockFlags int flags) { return this.handle.handleBlockPlaceWithResult(key, amount, flags); } @Override @Deprecated public void handleBlockPlace(Block block, @Size int amount, boolean save) { this.handle.handleBlockPlace(block, amount, save); } @Override @Deprecated public void handleBlockPlace(Key key, @Size int amount, boolean save) { this.handle.handleBlockPlace(key, amount, save); } @Override @Deprecated public void handleBlockPlace(Key key, BigInteger amount, boolean save) { this.handle.handleBlockPlace(key, amount, save); } @Override @Deprecated public void handleBlockPlace(Key key, BigInteger amount, boolean save, boolean updateLastTimeStatus) { this.handle.handleBlockPlace(key, amount, save, updateLastTimeStatus); } @Override public void handleBlocksPlace(Map blocks) { this.handle.handleBlocksPlace(blocks); } @Override public Map handleBlocksPlaceWithResult(Map blocks) { return this.handle.handleBlocksPlaceWithResult(blocks); } @Override public void handleBlocksPlace(Map blocks, @IslandBlockFlags int flags) { this.handle.handleBlocksPlace(blocks, flags); } @Override public Map handleBlocksPlaceWithResult(Map blocks, @IslandBlockFlags int flags) { return this.handle.handleBlocksPlaceWithResult(blocks, flags); } @Override public void handleBlockBreak(Block block) { this.handle.handleBlockBreak(block); } @Override public BlockChangeResult handleBlockBreakWithResult(Block block) { return this.handle.handleBlockBreakWithResult(block); } @Override public void handleBlockBreak(Key key) { this.handle.handleBlockBreak(key); } @Override public BlockChangeResult handleBlockBreakWithResult(Key key) { return this.handle.handleBlockBreakWithResult(key); } @Override public void handleBlockBreak(Block block, @Size int amount) { this.handle.handleBlockBreak(block, amount); } @Override public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount) { return this.handle.handleBlockBreakWithResult(block, amount); } @Override public void handleBlockBreak(Key key, @Size int amount) { this.handle.handleBlockBreak(key, amount); } @Override public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount) { return this.handle.handleBlockBreakWithResult(key, amount); } @Override public void handleBlockBreak(Block block, @Size int amount, @IslandBlockFlags int flags) { this.handle.handleBlockBreak(block, amount, flags); } @Override public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount, @IslandBlockFlags int flags) { return this.handle.handleBlockBreakWithResult(block, amount, flags); } @Override public void handleBlockBreak(Key key, @Size int amount, @IslandBlockFlags int flags) { this.handle.handleBlockBreak(key, amount, flags); } @Override public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, @IslandBlockFlags int flags) { return this.handle.handleBlockBreakWithResult(key, amount, flags); } @Override @Deprecated public void handleBlockBreak(Block block, @Size int amount, boolean save) { this.handle.handleBlockBreak(block, amount, save); } @Override @Deprecated public void handleBlockBreak(Key key, @Size int amount, boolean save) { this.handle.handleBlockBreak(key, amount, save); } @Override @Deprecated public void handleBlockBreak(Key key, BigInteger amount, boolean save) { this.handle.handleBlockBreak(key, amount, save); } @Override public void handleBlocksBreak(Map blocks) { this.handle.handleBlocksBreak(blocks); } @Override public Map handleBlocksBreakWithResult(Map blocks) { return this.handle.handleBlocksBreakWithResult(blocks); } @Override public void handleBlocksBreak(Map blocks, @IslandBlockFlags int flags) { this.handle.handleBlocksBreak(blocks, flags); } @Override public Map handleBlocksBreakWithResult(Map blocks, @IslandBlockFlags int flags) { return this.handle.handleBlocksBreakWithResult(blocks, flags); } @Override public boolean isChunkDirty(World world, int chunkX, int chunkZ) { return this.handle.isChunkDirty(world, chunkX, chunkZ); } @Override public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { return this.handle.isChunkDirty(worldName, chunkX, chunkZ); } @Override public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) { return this.handle.isChunkDirty(worldInfo, chunkX, chunkZ); } @Override public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { this.handle.markChunkDirty(world, chunkX, chunkZ, save); } @Override public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { this.handle.markChunkDirty(worldInfo, chunkX, chunkZ, save); } @Override public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { this.handle.markChunkEmpty(world, chunkX, chunkZ, save); } @Override public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { this.handle.markChunkEmpty(worldInfo, chunkX, chunkZ, save); } @Override public BigInteger getBlockCountAsBigInteger(Key key) { return this.handle.getBlockCountAsBigInteger(key); } @Override public Map getBlockCountsAsBigInteger() { return this.handle.getBlockCountsAsBigInteger(); } @Override public BigInteger getExactBlockCountAsBigInteger(Key key) { return this.handle.getExactBlockCountAsBigInteger(key); } @Override public void clearBlockCounts() { this.handle.clearBlockCounts(); } @Override public IslandBlocksTrackerAlgorithm getBlocksTracker() { return this.handle.getBlocksTracker(); } @Override public BigDecimal getWorth() { return this.handle.getWorth(); } @Override public BigDecimal getRawWorth() { return this.handle.getRawWorth(); } @Override public BigDecimal getBonusWorth() { return this.handle.getBonusWorth(); } @Override public void setBonusWorth(BigDecimal bonusWorth) { this.handle.setBonusWorth(bonusWorth); } @Override public BigDecimal getBonusLevel() { return this.handle.getBonusLevel(); } @Override public void setBonusLevel(BigDecimal bonusLevel) { this.handle.setBonusLevel(bonusLevel); } @Override public BigDecimal getIslandLevel() { return this.handle.getIslandLevel(); } @Override public BigDecimal getRawLevel() { return this.handle.getRawLevel(); } @Override public UpgradeLevel getUpgradeLevel(Upgrade upgrade) { return this.handle.getUpgradeLevel(upgrade); } @Override public void setUpgradeLevel(Upgrade upgrade, int level) { this.handle.setUpgradeLevel(upgrade, level); } @Override public Map getUpgrades() { return this.handle.getUpgrades(); } @Override public void syncUpgrades() { this.handle.syncUpgrades(); } @Override public void updateUpgrades() { this.handle.updateUpgrades(); } @Override public long getLastTimeUpgrade() { return this.handle.getLastTimeUpgrade(); } @Override public boolean hasActiveUpgradeCooldown() { return this.handle.hasActiveUpgradeCooldown(); } @Override public double getCropGrowthMultiplier() { return this.handle.getCropGrowthMultiplier(); } @Override public void setCropGrowthMultiplier(double cropGrowth) { this.handle.setCropGrowthMultiplier(cropGrowth); } @Override public double getCropGrowthRaw() { return this.handle.getCropGrowthRaw(); } @Override public double getSpawnerRatesMultiplier() { return this.handle.getSpawnerRatesMultiplier(); } @Override public void setSpawnerRatesMultiplier(double spawnerRates) { this.handle.setSpawnerRatesMultiplier(spawnerRates); } @Override public double getSpawnerRatesRaw() { return this.handle.getSpawnerRatesRaw(); } @Override public double getMobDropsMultiplier() { return this.handle.getMobDropsMultiplier(); } @Override public void setMobDropsMultiplier(double mobDrops) { this.handle.setMobDropsMultiplier(mobDrops); } @Override public double getMobDropsRaw() { return this.handle.getMobDropsRaw(); } @Override public int getBlockLimit(Key key) { return this.handle.getBlockLimit(key); } @Override public int getExactBlockLimit(Key key) { return this.handle.getExactBlockLimit(key); } @Override public Key getBlockLimitKey(Key key) { return this.handle.getBlockLimitKey(key); } @Override public Map getBlocksLimits() { return this.handle.getBlocksLimits(); } @Override public Map getCustomBlocksLimits() { return this.handle.getCustomBlocksLimits(); } @Override public void clearBlockLimits() { this.handle.clearBlockLimits(); } @Override public void setBlockLimit(Key key, int limit) { this.handle.setBlockLimit(key, limit); } @Override public void removeBlockLimit(Key key) { this.handle.removeBlockLimit(key); } @Override public boolean hasReachedBlockLimit(Key key) { return this.handle.hasReachedBlockLimit(key); } @Override public boolean hasReachedBlockLimit(Key key, @Size int amount) { return this.handle.hasReachedBlockLimit(key, amount); } @Override public int getEntityLimit(EntityType entityType) { return this.handle.getEntityLimit(entityType); } @Override public int getEntityLimit(Key key) { return this.handle.getEntityLimit(key); } @Override public Map getEntitiesLimitsAsKeys() { return this.handle.getEntitiesLimitsAsKeys(); } @Override public Map getCustomEntitiesLimits() { return this.handle.getCustomEntitiesLimits(); } @Override public void clearEntitiesLimits() { this.handle.clearEntitiesLimits(); } @Override public void setEntityLimit(EntityType entityType, int limit) { this.handle.setEntityLimit(entityType, limit); } @Override public void setEntityLimit(Key key, int limit) { this.handle.setEntityLimit(key, limit); } @Override public void removeEntityLimit(Key key) { this.handle.removeEntityLimit(key); } @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType) { return this.handle.hasReachedEntityLimit(entityType); } @Override public CompletableFuture hasReachedEntityLimit(Key key) { return this.handle.hasReachedEntityLimit(key); } @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType, @Size int amount) { return this.handle.hasReachedEntityLimit(entityType, amount); } @Override public CompletableFuture hasReachedEntityLimit(Key key, @Size int amount) { return this.handle.hasReachedEntityLimit(key, amount); } @Override public IslandEntitiesTrackerAlgorithm getEntitiesTracker() { return this.handle.getEntitiesTracker(); } @Override public int getTeamLimit() { return this.handle.getTeamLimit(); } @Override public void setTeamLimit(int teamLimit) { this.handle.setTeamLimit(teamLimit); } @Override public int getTeamLimitRaw() { return this.handle.getTeamLimitRaw(); } @Override public int getWarpsLimit() { return this.handle.getWarpsLimit(); } @Override public void setWarpsLimit(int warpsLimit) { this.handle.setWarpsLimit(warpsLimit); } @Override public int getWarpsLimitRaw() { return this.handle.getWarpsLimitRaw(); } @Override public void setPotionEffect(PotionEffectType type, int level) { this.handle.setPotionEffect(type, level); } @Override public void removePotionEffect(PotionEffectType type) { this.handle.removePotionEffect(type); } @Override public int getPotionEffectLevel(PotionEffectType type) { return this.handle.getPotionEffectLevel(type); } @Override public Map getPotionEffects() { return this.handle.getPotionEffects(); } @Override public Map getCustomPotionEffects() { return this.handle.getCustomPotionEffects(); } @Override public void applyEffects(SuperiorPlayer superiorPlayer) { this.handle.applyEffects(superiorPlayer); } @Override public void applyEffects() { this.handle.applyEffects(); } @Override public void removeEffects(SuperiorPlayer superiorPlayer) { this.handle.removeEffects(superiorPlayer); } @Override public void removeEffects() { this.handle.removeEffects(); } @Override public void clearEffects() { this.handle.clearEffects(); } @Override public void setRoleLimit(PlayerRole playerRole, int limit) { this.handle.setRoleLimit(playerRole, limit); } @Override public void removeRoleLimit(PlayerRole playerRole) { this.handle.removeRoleLimit(playerRole); } @Override public int getRoleLimit(PlayerRole playerRole) { return this.handle.getRoleLimit(playerRole); } @Override public int getRoleLimitRaw(PlayerRole playerRole) { return this.handle.getRoleLimitRaw(playerRole); } @Override public Map getRoleLimits() { return this.handle.getRoleLimits(); } @Override public Map getCustomRoleLimits() { return this.handle.getCustomRoleLimits(); } @Override public WarpCategory createWarpCategory(String name) { return this.handle.createWarpCategory(name); } @Nullable @Override public WarpCategory getWarpCategory(String name) { return this.handle.getWarpCategory(name); } @Nullable @Override public WarpCategory getWarpCategory(int slot) { return this.handle.getWarpCategory(slot); } @Override public void renameCategory(WarpCategory warpCategory, String newName) { this.handle.renameCategory(warpCategory, newName); } @Override public void deleteCategory(WarpCategory warpCategory) { this.handle.deleteCategory(warpCategory); } @Override public Map getWarpCategories() { return this.handle.getWarpCategories(); } @Override public IslandWarp createWarp(String name, Location location, @Nullable WarpCategory warpCategory) { return this.handle.createWarp(name, location, warpCategory); } @Override public IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, WarpCategory warpCategory) { return this.handle.createWarp(name, worldInfo, position, warpCategory); } @Override public void renameWarp(IslandWarp islandWarp, String newName) { this.handle.renameWarp(islandWarp, newName); } @Nullable @Override public IslandWarp getWarp(Location location) { return this.handle.getWarp(location); } @Nullable @Override public IslandWarp getWarp(String name) { return this.handle.getWarp(name); } @Override public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) { this.handle.warpPlayer(superiorPlayer, warpName); } @Override public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) { this.handle.warpPlayer(superiorPlayer, warpName, force); } @Override public void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location location) { this.handle.deleteWarp(superiorPlayer, location); } @Override public void deleteWarp(String name) { this.handle.deleteWarp(name); } @Override public Map getIslandWarps() { return this.handle.getIslandWarps(); } @Override public Rating getRating(SuperiorPlayer superiorPlayer) { return this.handle.getRating(superiorPlayer); } @Override public void setRating(SuperiorPlayer superiorPlayer, Rating rating) { this.handle.setRating(superiorPlayer, rating); } @Override public void removeRating(SuperiorPlayer superiorPlayer) { this.handle.removeRating(superiorPlayer); } @Override public double getTotalRating() { return this.handle.getTotalRating(); } @Override public int getRatingAmount() { return this.handle.getRatingAmount(); } @Override public Map getRatings() { return this.handle.getRatings(); } @Override public void removeRatings() { this.handle.removeRatings(); } @Override public boolean hasSettingsEnabled(IslandFlag islandFlag) { return this.handle.hasSettingsEnabled(islandFlag); } @Override public Map getAllSettings() { return this.handle.getAllSettings(); } @Override public void enableSettings(IslandFlag islandFlag) { this.handle.enableSettings(islandFlag); } @Override public void disableSettings(IslandFlag islandFlag) { this.handle.disableSettings(islandFlag); } @Override public void resetSettings() { this.handle.resetSettings(); } @Override public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) { this.handle.setGeneratorPercentage(key, percentage, dimension); } @Override public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension, @Nullable SuperiorPlayer caller, boolean callEvent) { return this.handle.setGeneratorPercentage(key, percentage, dimension, caller, callEvent); } @Override public int getGeneratorPercentage(Key key, Dimension dimension) { return this.handle.getGeneratorPercentage(key, dimension); } @Override public Map getGeneratorPercentages(Dimension dimension) { return this.handle.getGeneratorPercentages(dimension); } @Override public void setGeneratorAmount(Key key, int amount, Dimension dimension) { this.handle.setGeneratorAmount(key, amount, dimension); } @Override public void removeGeneratorAmount(Key key, Dimension dimension) { this.handle.removeGeneratorAmount(key, dimension); } @Override public int getGeneratorAmount(Key key, Dimension dimension) { return this.handle.getGeneratorAmount(key, dimension); } @Override public int getGeneratorTotalAmount(Dimension dimension) { return this.handle.getGeneratorTotalAmount(dimension); } @Override public Map getGeneratorAmounts(Dimension dimension) { return this.handle.getGeneratorAmounts(dimension); } @Override public Map getCustomGeneratorAmounts(Dimension dimension) { return this.handle.getCustomGeneratorAmounts(dimension); } @Override public void clearGeneratorAmounts(Dimension dimension) { this.handle.clearGeneratorAmounts(dimension); } @Nullable @Override public Key generateBlock(Location location, boolean optimizeDefaultBlock) { return this.handle.generateBlock(location, optimizeDefaultBlock); } @Override public Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock) { return this.handle.generateBlock(location, dimension, optimizeDefaultBlock); } @Override public boolean wasSchematicGenerated(Dimension dimension) { return this.handle.wasSchematicGenerated(dimension); } @Override public void setSchematicGenerate(Dimension dimension) { this.handle.setSchematicGenerate(dimension); } @Override public void setSchematicGenerate(Dimension dimension, boolean generated) { this.handle.setSchematicGenerate(dimension, generated); } @Override public Collection getGeneratedSchematics() { return this.handle.getGeneratedSchematics(); } @Override public String getSchematicName() { return this.handle.getSchematicName(); } @Override public int getPosition(SortingType sortingType) { return this.handle.getPosition(sortingType); } @Override public IslandChest[] getChest() { return this.handle.getChest(); } @Override public int getChestSize() { return this.handle.getChestSize(); } @Override public void setChestRows(int index, int rows) { this.handle.setChestRows(index, rows); } @Override public int compareTo(Island o) { return this.handle.compareTo(o); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandChest.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; public class DelegateIslandChest implements IslandChest { protected final IslandChest handle; protected DelegateIslandChest(IslandChest handle) { this.handle = handle; } @Override public Island getIsland() { return this.handle.getIsland(); } @Override public int getIndex() { return this.handle.getIndex(); } @Override public int getRows() { return this.handle.getRows(); } @Override public void setRows(int rows) { this.handle.setRows(rows); } @Override public ItemStack[] getContents() { return this.handle.getContents(); } @Override public void openChest(SuperiorPlayer superiorPlayer) { this.handle.openChest(superiorPlayer); } @Override public Inventory getInventory() { return this.handle.getInventory(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.GameMode; import org.bukkit.Location; public class DelegateIslandPreview implements IslandPreview { protected final IslandPreview handle; protected DelegateIslandPreview(IslandPreview handle) { this.handle = handle; } @Override public SuperiorPlayer getPlayer() { return this.handle.getPlayer(); } @Override public Location getLocation() { return this.handle.getLocation(); } @Override public Location getLocation(Location location) { return this.handle.getLocation(location); } @Override public String getSchematic() { return this.handle.getSchematic(); } @Override public String getIslandName() { return this.handle.getIslandName(); } @Override public GameMode getPreviousGameMode() { return this.handle.getPreviousGameMode(); } @Override public void handleConfirm() { this.handle.handleConfirm(); } @Override public void handleCancel() { this.handle.handleCancel(); } @Override public void handleEscape() { this.handle.handleEscape(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegatePermissionNode.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import java.util.Map; public class DelegatePermissionNode implements PermissionNode { protected final PermissionNode handle; protected DelegatePermissionNode(PermissionNode handle) { this.handle = handle; } @Override public boolean hasPermission(IslandPrivilege islandPrivilege) { return this.handle.hasPermission(islandPrivilege); } @Override public void setPermission(IslandPrivilege islandPrivilege, boolean value) { this.handle.setPermission(islandPrivilege, value); } @Override public Map getCustomPermissions() { return this.handle.getCustomPermissions(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.annotations.Size; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder; import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.enums.SyncStatus; import com.bgsoftware.superiorskyblock.api.events.IslandChangeGeneratorRateEvent; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.persistence.IPersistentDataHolder; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public interface Island extends Comparable, IMissionsHolder, IPersistentDataHolder, IDatabaseBridgeHolder { /* * General methods */ /** * Get the owner of the island. */ SuperiorPlayer getOwner(); /** * Get the unique-id of the island. */ UUID getUniqueId(); /** * Get the creation time of the island. */ long getCreationTime(); /** * Get the creation time of the island, in a formatted string. */ String getCreationTimeDate(); /** * Re-sync the island with a new dates formatter. */ void updateDatesFormatter(); /** * Get the island cache. */ IslandCache getCache(); /* * Player related methods */ /** * Get the list of members of the island. * * @param includeOwner Whether the owner should be returned. */ List getIslandMembers(boolean includeOwner); /** * Get the list of members of the island with specific roles. * * @param playerRoles The roles to filter with. */ List getIslandMembers(PlayerRole... playerRoles); /** * Get the list of all banned players. */ List getBannedPlayers(); /** * Get the list of all visitors that are on the island, including vanished ones. */ List getIslandVisitors(); /** * Get the list of all visitors that are on the island. * * @param vanishPlayers Should vanish players be included? */ List getIslandVisitors(boolean vanishPlayers); /** * Get the list of all the players that are on the island. */ List getAllPlayersInside(); /** * Get all the visitors that visited the island until now. */ List getUniqueVisitors(); /** * Get all the visitors that visited the island until now, with the time they last visited. */ List> getUniqueVisitorsWithTimes(); /** * Invite a player to the island. * * @param superiorPlayer The player to invite. */ void inviteMember(SuperiorPlayer superiorPlayer); /** * Revoke an invitation of a player. * * @param superiorPlayer The player to revoke his invite. */ void revokeInvite(SuperiorPlayer superiorPlayer); /** * Checks whether the player has been invited to the island. */ boolean isInvited(SuperiorPlayer superiorPlayer); /** * Get all the invited players of the island. */ List getInvitedPlayers(); /** * Add a player to the island. * * @param superiorPlayer The player to add. * @param playerRole The role to give to the player. */ void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole); /** * Kick a member from the island. * * @param superiorPlayer The player to kick. * @deprecated See {@link #removeMember(SuperiorPlayer, MemberRemoveReason)} */ @Deprecated void kickMember(SuperiorPlayer superiorPlayer); /** * Remove a member from the island. * * @param superiorPlayer The player to remove. * @param memberRemoveReason The reason for removal. */ void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason); /** * Check whether a player is a member of the island. * * @param superiorPlayer The player to check. */ boolean isMember(SuperiorPlayer superiorPlayer); /** * Ban a member from the island. * * @param superiorPlayer The player to ban. */ void banMember(SuperiorPlayer superiorPlayer); /** * Ban a member from the island. * * @param superiorPlayer The player to ban. * @param whom The player that executed the ban command. * If null, CONSOLE will be chosen as the banner. */ void banMember(SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer whom); /** * Unban a player from the island. * * @param superiorPlayer The player to unban. */ void unbanMember(SuperiorPlayer superiorPlayer); /** * Checks whether a player is banned from the island. * * @param superiorPlayer The player to check. */ boolean isBanned(SuperiorPlayer superiorPlayer); /** * Add a player to the island as a co-op member. * * @param superiorPlayer The player to add. */ void addCoop(SuperiorPlayer superiorPlayer); /** * Remove a player from being a co-op member. * * @param superiorPlayer The player to remove. */ void removeCoop(SuperiorPlayer superiorPlayer); /** * Check whether a player is a co-op member of the island. * * @param superiorPlayer The player to check. */ boolean isCoop(SuperiorPlayer superiorPlayer); /** * Get the list of all co-op players. */ List getCoopPlayers(); /** * Get the coop players limit of the island. */ int getCoopLimit(); /** * Get the coop players limit of the island that was set using a command. */ int getCoopLimitRaw(); /** * Set the coop players limit of the island. * * @param coopLimit The coop players limit to set. */ void setCoopLimit(int coopLimit); /** * Update status of a player if he's inside the island or not. * * @param superiorPlayer The player to add. */ void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside); /** * Check whether a player is a visitor of the island or not. * * @param superiorPlayer The player to check. * @param checkCoopStatus Whether to check for coop status or not. * If enabled, coops will not be considered as visitors. */ boolean isVisitor(SuperiorPlayer superiorPlayer, boolean checkCoopStatus); /* * Location related methods */ /** * Get the center location of the island, depends on the world dimension. * * @param dimension The dimension. */ Location getCenter(Dimension dimension); /** * Get the center position of the island. */ BlockPosition getCenterPosition(); /** * Access the island's world. * This method will load the world safely if it is not loaded. * * @param dimension The dimension of the island world. */ CompletableFuture accessIslandWorld(Dimension dimension); /** * Get the members' home location of the island, depends on the world dimension. * * @param dimension The dimension. */ @Nullable Location getIslandHome(Dimension dimension); /** * Get the members' home location of the island, depends on the world dimension. * * @param dimension The dimension. */ @Nullable WorldPosition getIslandHomePosition(Dimension dimension); /** * Get all the home locations of the island. * If the world is not loaded, the location's getWorld will return null. */ Map getIslandHomesAsDimensions(); /** * Get all the home positions of the island. */ Map getIslandHomes(); /** * Set the home location of the island. * The location will be set for the world provided in {@param homeLocation} * * @param homeLocation The new home location. */ void setIslandHome(Location homeLocation); /** * Set the home position of the island. * The world of {@param homeLocation} is ignored. * * @param dimension The dimension to change home position for. * @param homeLocation The new home location. * @deprecated See {@link #setIslandHome(Dimension, WorldPosition)} */ @Deprecated void setIslandHome(Dimension dimension, @Nullable Location homeLocation); /** * Set the home position of the island. * * @param dimension The dimension to change home position for. * @param homePosition The new home position. */ void setIslandHome(Dimension dimension, @Nullable WorldPosition homePosition); /** * Get the visitors' teleport location of the island. * If the world is unloaded, the location's getWorld method will return null. * * @param dimension The dimension to get the visitors-location from. * Currently unused, it has no effect. */ @Nullable Location getVisitorsLocation(Dimension dimension); /** * Get the visitors' teleport position of the island. * * @param dimension The dimension to get the visitors-position from. * Currently unused, it has no effect. */ @Nullable WorldPosition getVisitorsPosition(Dimension dimension); /** * Set the visitors' teleport location of the island. * * @param visitorsLocation The new visitors location. */ void setVisitorsLocation(@Nullable Location visitorsLocation); /** * Set the visitors' teleport position of the island. * * @param dimension The dimension to change the visitors-position. * Currently unused, it has no effect. * @param visitorsPosition The new visitors position. */ void setVisitorsLocation(Dimension dimension, @Nullable WorldPosition visitorsPosition); /** * Get the minimum location of the island. * If the world is unloaded, the location's getWorld will return null. */ Location getMinimum(); /** * Get the minimum location of the island. */ BlockPosition getMinimumPosition(); /** * Get the minimum protected location of the island. * If the world is unloaded, the location's getWorld will return null. */ Location getMinimumProtected(); /** * Get the minimum location of the island. */ BlockPosition getMinimumProtectedPosition(); /** * Get the maximum location of the island. * If the world is unloaded, the location's getWorld will return null. */ Location getMaximum(); /** * Get the maximum location of the island. */ BlockPosition getMaximumPosition(); /** * Get the minimum protected location of the island. * If the world is unloaded, the location's getWorld will return null. */ Location getMaximumProtected(); /** * Get the minimum protected location of the island. */ BlockPosition getMaximumProtectedPosition(); /** * Get all the chunks of the island from all the environments. * Similar to {@link #getAllChunks(int)} with 0 as flags parameter. */ List getAllChunks(); /** * Get all the chunks of the island from all the environments. * * @param flags See {@link IslandChunkFlags} */ List getAllChunks(@IslandChunkFlags int flags); /** * Get all the chunks of the island. * Similar to {@link #getAllChunks(Dimension, int)} with 0 as flags parameter. * * @param dimension The environment to get the chunks from. */ List getAllChunks(Dimension dimension); /** * Get all the chunks of the island. * * @param dimension The dimension to get the chunks from. * @param flags See {@link IslandChunkFlags} */ List getAllChunks(Dimension dimension, @IslandChunkFlags int flags); /** * Get all the loaded chunks of the island. * Similar to {@link #getLoadedChunks(int)} with 0 as flags parameter. */ List getLoadedChunks(); /** * Get all the loaded chunks of the island. * * @param flags See {@link IslandChunkFlags} */ List getLoadedChunks(@IslandChunkFlags int flags); /** * Get all the loaded chunks of the island. * Similar to {@link #getLoadedChunks(Dimension, int)} with 0 as flags parameter. * * @param dimension The environment to get the chunks from. */ List getLoadedChunks(Dimension dimension); /** * Get all the loaded chunks of the island. * * @param dimension The dimension to get the chunks from. * @param flags See {@link IslandChunkFlags} */ List getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags); /** * Get all the chunks of the island asynchronized, including empty chunks. * Similar to {@link #getAllChunksAsync(Dimension, int, Consumer)}, with 0 as flags parameter. * * @param dimension The dimension to get the chunks from. */ List> getAllChunksAsync(Dimension dimension); /** * Get all the chunks of the island asynchronized, including empty chunks. * * @param dimension The dimension to get the chunks from. * @param flags See {@link IslandChunkFlags} */ List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags); /** * Get all the chunks of the island asynchronized, including empty chunks. * Similar to {@link #getAllChunksAsync(Dimension, int, Consumer)}, with 0 as flags parameter. * * @param dimension The dimension to get the chunks from. * @param onChunkLoad A consumer that will be ran when the chunk is loaded. Can be null. */ List> getAllChunksAsync(Dimension dimension, @Nullable Consumer onChunkLoad); /** * Get all the chunks of the island asynchronized, including empty chunks. * * @param dimension The dimension to get the chunks from. * @param flags See {@link IslandChunkFlags} * @param onChunkLoad A consumer that will be ran when the chunk is loaded. Can be null. */ List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags, @Nullable Consumer onChunkLoad); /** * Reset all the chunks of the island from all the worlds (will make all chunks empty). * Similar to {@link #resetChunks(int)}, with 0 as flags parameter. */ void resetChunks(); /** * Reset all the chunks of the island from all the worlds (will make all chunks empty). * Similar to {@link #resetChunks(int, Runnable)}, with 0 as flags parameter. * * @param onFinish Callback runnable. */ void resetChunks(@Nullable Runnable onFinish); /** * Reset all the chunks of the island (will make all chunks empty). * Similar to {@link #resetChunks(Dimension, int)}, with 0 as flags parameter. * * @param dimension The dimension to reset chunks in. */ void resetChunks(Dimension dimension); /** * Reset all the chunks of the island (will make all chunks empty). * * @param dimension The dimension to reset chunks in. * @param onFinish Callback runnable. */ void resetChunks(Dimension dimension, @Nullable Runnable onFinish); /** * Reset all the chunks of the island from all the worlds (will make all chunks empty). * * @param flags See {@link IslandChunkFlags} */ void resetChunks(@IslandChunkFlags int flags); /** * Reset all the chunks of the island from all the worlds (will make all chunks empty). * * @param flags See {@link IslandChunkFlags} * @param onFinish Callback runnable. */ void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish); /** * Reset all the chunks of the island (will make all chunks empty). * * @param dimension The dimension to reset chunks in. * @param flags See {@link IslandChunkFlags} */ void resetChunks(Dimension dimension, @IslandChunkFlags int flags); /** * Reset all the chunks of the island (will make all chunks empty). * * @param dimension The dimension to reset chunks in. * @param flags See {@link IslandChunkFlags} * @param onFinish Callback runnable. */ void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish); /** * Check if the location is inside the island's area. * Similar to {@link #isInside(Location, int)} or {@link #isInside(Location, double)} with extraRadius set to 0. * * @param location The location to check. */ boolean isInside(Location location); /** * Check if the location is inside the island's area. * * @param location The location to check. * @param extraRadius Add extra radius to the range. */ boolean isInside(Location location, int extraRadius); /** * Check if the location is inside the island's area. * * @param location The location to check. * @param extraRadius Add extra radius to the range. */ boolean isInside(Location location, double extraRadius); /** * Check if the location is inside the island's area. * The world is ignored in this case. * Similar to {@link #isInside(BlockPosition, int)} or {@link #isInside(BlockPosition, double)} with extraRadius set to 0. * * @param blockPosition The position to check. */ boolean isInside(BlockPosition blockPosition); /** * Check if the position is inside the island's area. * The world is ignored in this case. * * @param blockPosition The position to check. * @param extraRadius Add extra radius to the range. */ boolean isInside(BlockPosition blockPosition, int extraRadius); /** * Check if the position is inside the island's area. * * @param blockPosition The position to check. * @param extraRadius Add extra radius to the range. */ boolean isInside(BlockPosition blockPosition, double extraRadius); /** * Check if the location is inside the island's area. * The world is ignored in this case. * Similar to {@link #isInside(WorldPosition, int)} or {@link #isInside(WorldPosition, double)} with extraRadius set to 0. * * @param worldPosition The position to check. */ boolean isInside(WorldPosition worldPosition); /** * Check if the position is inside the island's area. * The world is ignored in this case. * * @param worldPosition The position to check. * @param extraRadius Add extra radius to the range. */ boolean isInside(WorldPosition worldPosition, int extraRadius); /** * Check if the position is inside the island's area. * * @param worldPosition The position to check. * @param extraRadius Add extra radius to the range. */ boolean isInside(WorldPosition worldPosition, double extraRadius); /** * Check if a chunk is inside the island's area. * Similar to {@link #isInside(World, int, int)} * * @param chunk The chunk to check. */ boolean isInside(Chunk chunk); /** * Check if a chunk location is inside the island's area. * Similar to {@link #isInside(World, int, int, int)} or {@link #isInside(World, int, int, double)} with extraRadius set to 0. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isInside(World world, int chunkX, int chunkZ); /** * Check if a chunk location is inside the island's area. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the range. */ boolean isInside(World world, int chunkX, int chunkZ, int extraRadius); /** * Check if a chunk location is inside the island's area. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the range. */ boolean isInside(World world, int chunkX, int chunkZ, double extraRadius); /** * Check if a chunk location is inside the island's area. * Similar to {@link #isInside(WorldInfo, int, int, int)} or {@link #isInside(WorldInfo, int, int, double)} with extraRadius set to 0. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ); /** * Check if a chunk location is inside the island's area. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the range. */ boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius); /** * Check if a chunk location is inside the island's area. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the range. */ boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius); /** * Check if a chunk position is inside the island's area. * The world in this case is ignored. * Similar to {@link #isInside(int, int, int)} or {@link #isInside(int, int, double)} with extraRadius set to 0. * * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isInside(int chunkX, int chunkZ); /** * Check if a chunk position is inside the island's area. * The world in this case is ignored. * * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the range. */ boolean isInside(int chunkX, int chunkZ, int extraRadius); /** * Check if a chunk position is inside the island's area. * The world in this case is ignored. * * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the range. */ boolean isInside(int chunkX, int chunkZ, double extraRadius); /** * Check if the location is inside the island's protected area. * * @param location The location to check. */ boolean isInsideRange(Location location); /** * Check if the location is inside the island's protected area. * * @param location The location to check. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(Location location, int extraRadius); /** * Check if the location is inside the island's protected area. * * @param location The location to check. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(Location location, double extraRadius); /** * Check if the position is inside the island's protected area. * The world in this case is ignored. * * @param blockPosition The position to check. */ boolean isInsideRange(BlockPosition blockPosition); /** * Check if the position is inside the island's protected area. * The world in this case is ignored. * * @param blockPosition The position to check. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(BlockPosition blockPosition, int extraRadius); /** * Check if the position is inside the island's protected area. * The world in this case is ignored. * * @param blockPosition The position to check. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(BlockPosition blockPosition, double extraRadius); /** * Check if the position is inside the island's protected area. * The world in this case is ignored. * * @param worldPosition The position to check. */ boolean isInsideRange(WorldPosition worldPosition); /** * Check if the position is inside the island's protected area. * The world in this case is ignored. * * @param worldPosition The position to check. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(WorldPosition worldPosition, int extraRadius); /** * Check if the position is inside the island's protected area. * The world in this case is ignored. * * @param worldPosition The position to check. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(WorldPosition worldPosition, double extraRadius); /** * Check if the chunk is inside the island's protected area. * * @param chunk The chunk to check. */ boolean isInsideRange(Chunk chunk); /** * Check if a chunk location is inside the island's protected area. * Similar to {@link #isInside(World, int, int, int)} or {@link #isInside(World, int, int, double)} with extraRadius set to 0. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isInsideRange(World world, int chunkX, int chunkZ); /** * Check if a chunk location is inside the island's protected area. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius); /** * Check if a chunk location is inside the island's protected area. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius); /** * Check if a chunk location is inside the island's protected area. * Similar to {@link #isInside(WorldInfo, int, int, int)} or {@link #isInside(WorldInfo, int, int, double)} with extraRadius set to 0. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ); /** * Check if a chunk location is inside the island's protected area. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius); /** * Check if a chunk location is inside the island's protected area. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius); /** * Check if a chunk position is inside the island's protected area. * The world in this case is ignored. * Similar to {@link #isInside(int, int, int)} or {@link #isInside(int, int, double)} with extraRadius set to 0. * * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isInsideRange(int chunkX, int chunkZ); /** * Check if a chunk position is inside the island's protected area. * The world in this case is ignored. * * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(int chunkX, int chunkZ, int extraRadius); /** * Check if a chunk position is inside the island's protected area. * The world in this case is ignored. * * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param extraRadius Add extra radius to the protected range. */ boolean isInsideRange(int chunkX, int chunkZ, double extraRadius); /** * Is the normal world enabled for the island? * * @deprecated See {@link #isDimensionEnabled(Dimension)} */ @Deprecated boolean isNormalEnabled(); /** * Enable/disable the normal world for the island. * * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)} */ @Deprecated void setNormalEnabled(boolean enabled); /** * Is the nether world enabled for the island? * * @deprecated See {@link #isDimensionEnabled(Dimension)} */ @Deprecated boolean isNetherEnabled(); /** * Enable/disable the nether world for the island. * * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)} */ @Deprecated void setNetherEnabled(boolean enabled); /** * Is the end world enabled for the island? * * @deprecated See {@link #isDimensionEnabled(Dimension)} */ @Deprecated boolean isEndEnabled(); /** * Enable/disable the end world for the island. * * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)} */ @Deprecated void setEndEnabled(boolean enabled); /** * Checks if a specific dimension is enabled for the island * * @param dimension The dimension to check. */ boolean isDimensionEnabled(Dimension dimension); /** * Enable/disable a world for the island. * * @param dimension The dimension to enable/disable. * @param enabled Status. */ void setDimensionEnabled(Dimension dimension, boolean enabled); /** * Get the unlocked worlds. */ Collection getUnlockedWorlds(); /* * Permissions related methods */ /** * Check if a CommandSender has a permission. * * @param sender The command-sender to check. * @param islandPrivilege The permission to check. */ boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege); /** * Check if a player has a permission. * * @param superiorPlayer The player to check. * @param islandPrivilege The permission to check. */ boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege); /** * Check if a role has a permission. * * @param playerRole The role to check. * @param islandPrivilege The permission to check. */ boolean hasPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege); /** * Set a permission to a specific role. * * @param playerRole The role to set the permission to. * @param islandPrivilege The permission to set. * @param value The value to give the permission (Unused) * @deprecated See {@link #setPermission(PlayerRole, IslandPrivilege)} */ @Deprecated void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege, boolean value); /** * Set a permission to a specific role. * * @param playerRole The role to set the permission to. * @param islandPrivilege The permission to set. */ void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege); /** * Reset the roles permissions to default values. */ void resetPermissions(); /** * Set a permission to a specific player. * * @param superiorPlayer The player to set the permission to. * @param islandPrivilege The permission to set. * @param value The value to give the permission. */ void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value); /** * Reset player permissions to default values. */ void resetPermissions(SuperiorPlayer superiorPlayer); /** * Get the permission-node of a player. * * @param superiorPlayer The player to check. */ PermissionNode getPermissionNode(SuperiorPlayer superiorPlayer); /** * Get the required role for a specific permission. * * @param islandPrivilege The permission to check. */ PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege); /** * Get all the custom player permissions of the island. */ Map getPlayerPermissions(); /** * Get the permissions and their required roles. */ Map getRolePermissions(); /* * General methods */ /** * Checks whether the island is the spawn island. */ boolean isSpawn(); /** * Set the name of the island. * * @param islandName The name to set. */ void setName(String islandName); /** * Get the name of the island in respect to color-support. * This method will call {@link #getFormattedName()} or {@link #getStrippedName()}, depends on color-support. */ String getName(); /** * Get the name of the island in its stripped form. * * @deprecated See {@link #getStrippedName()} */ @Deprecated String getRawName(); /** * Get the name of the island in its stripped form. * Unlike {@link #getName()}, this method will always return the stripped form of the name. */ String getStrippedName(); /** * Get the name of the island in its color-formatted form. * Unlike {@link #getName()}, this method will always return the color-formatted form of the name. */ String getFormattedName(); /** * Get the description of the island. */ String getDescription(); /** * Set the description of the island. * * @param description The description to set. */ void setDescription(String description); /** * Disband the island. */ void disbandIsland(); /** * Transfer the island's leadership to another player. * * @param superiorPlayer The player to transfer the leadership to. * @return True if the transfer was succeed, otherwise false. */ boolean transferIsland(SuperiorPlayer superiorPlayer); /** * Replace a player with a new player. * * @param originalPlayer The old player to be replaced. * @param newPlayer The new player. * If null, the original player should just be removed. * If this is the owner of the island, the island will be disbanded. */ void replacePlayers(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer); /** * Recalculate the island's worth value. * * @param asker The player who makes the operation. */ void calcIslandWorth(@Nullable SuperiorPlayer asker); /** * Recalculate the island's worth value. * * @param asker The player who makes the operation. * @param callback Runnable which will be ran when process is finished. */ void calcIslandWorth(@Nullable SuperiorPlayer asker, @Nullable Runnable callback); /** * Get the calculation algorithm used by this island. */ IslandCalculationAlgorithm getCalculationAlgorithm(); /** * Update the border of all the players inside the island. */ void updateBorder(); /** * Update the fly status for a player on this island. * * @param superiorPlayer The player to update. */ void updateIslandFly(SuperiorPlayer superiorPlayer); /** * Get the island radius of the island. */ int getIslandSize(); /** * Set the radius of the island. * * @param islandSize The radius for the island. */ void setIslandSize(int islandSize); /** * Get the island radius of the island that was set with a command. */ int getIslandSizeRaw(); /** * Get the discord that is associated with the island. */ String getDiscord(); /** * Set the discord that will be associated with the island. */ void setDiscord(String discord); /** * Get the paypal that is associated with the island. */ String getPaypal(); /** * Get the paypal that will be associated with the island. */ void setPaypal(String paypal); /** * The current biome of the island. */ Biome getBiome(); /** * Change the biome of the island's area. */ void setBiome(Biome biome); /** * Change the biome of the island's area. * * @param updateBlocks Whether the blocks get updated or not. */ void setBiome(Biome biome, boolean updateBlocks); /** * Check whether the island is locked to visitors. */ boolean isLocked(); /** * Lock or unlock the island to visitors. * * @param locked Whether the island should be locked to visitors. */ void setLocked(boolean locked); /** * Checks whether the island is ignored in the top islands. */ boolean isIgnored(); /** * Set whether the island should be ignored in the top islands. */ void setIgnored(boolean ignored); /** * Send a plain message to all the members of the island. * * @param message The message to send */ void sendMessage(String message); /** * Send a plain message to all the members of the island. * * @param message The message to send * @param ignoredMembers An array of ignored members. */ void sendMessage(String message, UUID... ignoredMembers); /** * Send a message to all the members of the island. * * @param messageComponent The message to send */ void sendMessage(IMessageComponent messageComponent); /** * Send a message to all the members of the island. * * @param messageComponent The message to send * @param args Arguments for the component. */ void sendMessage(IMessageComponent messageComponent, Object... args); /** * Send a message to all the members of the island. * * @param messageComponent The message to send * @param ignoredMembers An array of ignored members. */ void sendMessage(IMessageComponent messageComponent, List ignoredMembers); /** * Send a message to all the members of the island. * * @param messageComponent The message to send * @param ignoredMembers An array of ignored members. * @param args Arguments for the component. */ void sendMessage(IMessageComponent messageComponent, List ignoredMembers, Object... args); /** * Send a plain message to all the members of the island. * * @param title The main title to send. * @param subtitle The sub title to send. * @param fadeIn The fade-in duration in ticks. * @param duration The title duration in ticks. * @param fadeOut The fade-out duration in ticks. */ void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut); /** * Send a plain message to all the members of the island. * * @param title The main title to send. * @param subtitle The sub title to send. * @param fadeIn The fade-in duration in ticks. * @param duration The title duration in ticks. * @param fadeOut The fade-out duration in ticks. * @param ignoredMembers An array of ignored members. */ void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers); /** * Execute a command on all the members of the island. * You can use {player-name} as a placeholder for the member's name. * * @param command The command to execute. * @param onlyOnlineMembers Whether the command should be executed only for online members. */ void executeCommand(String command, boolean onlyOnlineMembers); /** * Execute a command on all the members of the island. * You can use {player-name} as a placeholder for the member's name. * * @param command The command to execute. * @param onlyOnlineMembers Whether the command should be executed only for online members. * @param ignoredMembers An array of ignored members. */ void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers); /** * Checks whether the island is being recalculated currently. */ boolean isBeingRecalculated(); /** * Update the last time the island was used. */ void updateLastTime(); /** * Flag the island as a currently active island. */ void setCurrentlyActive(); /** * Set whether the island is currently active. * Active islands are islands that have at least one island member online. * * @param active Whether the island is active. */ void setCurrentlyActive(boolean active); /** * Check whether the island is currently active. * Active islands are islands that have at least one island member online. */ boolean isCurrentlyActive(); /** * Get the last time the island was updated. * In case the island is active, -1 will be returned. */ long getLastTimeUpdate(); /** * Set the last time the island was updated. * * @param lastTimeUpdate The last time the island was updated. */ void setLastTimeUpdate(long lastTimeUpdate); /* * Bank related methods */ /** * Get the bank of the island. */ IslandBank getIslandBank(); /** * Get the limit of the bank. */ BigDecimal getBankLimit(); /** * Set a new limit for the bank. * * @param bankLimit The limit to set. Use -1 to remove the limit. */ void setBankLimit(BigDecimal bankLimit); /** * Get the limit of the bank that was set using a command. */ BigDecimal getBankLimitRaw(); /** * Give the bank interest to this island. * * @param checkOnlineOwner Check if the island-owner was online recently. * @return Whether the money was given. */ boolean giveInterest(boolean checkOnlineOwner); /** * Get the last time that the bank interest was given. */ long getLastInterestTime(); /** * Set the last time that the bank interest was given. * * @param lastInterest The time it was given. */ void setLastInterestTime(long lastInterest); /** * Get the duration until the bank interest will be given again, in seconds */ long getNextInterest(); /* * Worth related methods */ /** * Handle a placement of a block. * This will save the block counts and update the last time status of the island. * * @param block The block that was placed. */ void handleBlockPlace(Block block); /** * Handle a placement of a block. * This will save the block counts and update the last time status of the island. * * @param block The block that was placed. * @return The result of the block place. */ BlockChangeResult handleBlockPlaceWithResult(Block block); /** * Handle a placement of a block's key. * This will save the block counts and update the last time status of the island. * * @param key The block's key that was placed. */ void handleBlockPlace(Key key); /** * Handle a placement of a block's key. * This will save the block counts and update the last time status of the island. * * @param key The block's key that was placed. * @return The result of the block place. */ BlockChangeResult handleBlockPlaceWithResult(Key key); /** * Handle a placement of a block with a specific amount. * This will save the block counts and update the last time status of the island. * * @param block The block that was placed. * @param amount The amount of the block. */ void handleBlockPlace(Block block, @Size int amount); /** * Handle a placement of a block with a specific amount. * This will save the block counts and update the last time status of the island. * * @param block The block that was placed. * @param amount The amount of the block. * @return The result of the block place. */ BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount); /** * Handle a placement of a block's key with a specific amount. * This will save the block counts and update the last time status of the island. * * @param key The block's key that was placed. * @param amount The amount of the block. */ void handleBlockPlace(Key key, @Size int amount); /** * Handle a placement of a block's key with a specific amount. * This will save the block counts and update the last time status of the island. * * @param key The block's key that was placed. * @param amount The amount of the block. * @return The result of the block place. */ BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount); /** * Handle a placement of a block with a specific amount. * * @param block The block that was placed. * @param amount The amount of the block. * @param flags See {@link IslandBlockFlags} */ void handleBlockPlace(Block block, @Size int amount, @IslandBlockFlags int flags); /** * Handle a placement of a block with a specific amount. * * @param block The block that was placed. * @param amount The amount of the block. * @param flags See {@link IslandBlockFlags} * @return The result of the block place. */ BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount, @IslandBlockFlags int flags); /** * Handle a placement of a block's key with a specific amount. * * @param key The block's key that was placed. * @param amount The amount of the block. * @param flags See {@link IslandBlockFlags} */ void handleBlockPlace(Key key, @Size int amount, @IslandBlockFlags int flags); /** * Handle a placement of a block's key with a specific amount. * * @param key The block's key that was placed. * @param amount The amount of the block. * @param flags See {@link IslandBlockFlags} * @return The result of the block place. */ BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @IslandBlockFlags int flags); /** * Handle a placement of a block with a specific amount. * This will update the last time status of the island. * * @param block The block that was placed. * @param amount The amount of the block. * @param save Whether the block counts should be saved into database. * @deprecated See {@link #handleBlockPlace(Block, int, int)} */ @Deprecated void handleBlockPlace(Block block, @Size int amount, boolean save); /** * Handle a placement of a block's key with a specific amount. * This will update the last time status of the island. * * @param key The block's key that was placed. * @param amount The amount of the block. * @param save Whether the block counts should be saved into database. * @deprecated See {@link #handleBlockPlace(Key, int, int)} */ @Deprecated void handleBlockPlace(Key key, @Size int amount, boolean save); /** * Handle a placement of a block's key with a specific amount. * This will update the last time status of the island. * * @param key The block's key that was placed. * @param amount The amount of the block. * @param save Whether the block counts should be saved into database. * @deprecated See {@link #handleBlockPlace(Key, int, int)} */ @Deprecated void handleBlockPlace(Key key, @Size BigInteger amount, boolean save); /** * Handle a placement of a block's key with a specific amount. * * @param key The block's key that was placed. * @param amount The amount of the block. * @param save Whether the block counts should be saved into database. * @param updateLastTimeStatus Whether to update last time island was updated or not. * @deprecated See {@link #handleBlockPlace(Key, int, int)} */ @Deprecated void handleBlockPlace(Key key, @Size BigInteger amount, boolean save, boolean updateLastTimeStatus); /** * Handle placements of many blocks in one time. * This will save the block counts and update the last time status of the island. * * @param blocks All the blocks to place. */ void handleBlocksPlace(Map blocks); /** * Handle placements of many blocks in one time. * This will save the block counts and update the last time status of the island. * * @param blocks All the blocks to place. * @return Results per block key. Only non-successful results will be returned. */ Map handleBlocksPlaceWithResult(Map blocks); /** * Handle placements of many blocks in one time. * * @param blocks All the blocks to place. * @param flags See {@link IslandBlockFlags} */ void handleBlocksPlace(Map blocks, @IslandBlockFlags int flags); /** * Handle placements of many blocks in one time. * * @param blocks All the blocks to place. * @param flags See {@link IslandBlockFlags} * @return Results per block key. Only non-successful results will be returned. */ Map handleBlocksPlaceWithResult(Map blocks, @IslandBlockFlags int flags); /** * Handle a break of a block. * This will save the block counts and update the last time status of the island. * * @param block The block that was broken. */ void handleBlockBreak(Block block); /** * Handle a break of a block. * This will save the block counts and update the last time status of the island. * * @param block The block that was broken. * @return The result of the block place. */ BlockChangeResult handleBlockBreakWithResult(Block block); /** * Handle a break of a block's key. * This will save the block counts and update the last time status of the island. * * @param key The block's key that was broken. */ void handleBlockBreak(Key key); /** * Handle a break of a block's key. * This will save the block counts and update the last time status of the island. * * @param key The block's key that was broken. * @return The result of the block place. */ BlockChangeResult handleBlockBreakWithResult(Key key); /** * Handle a break of a block with a specific amount. * This will save the block counts and update the last time status of the island. * * @param block The block that was broken. * @param amount The amount of the block. */ void handleBlockBreak(Block block, @Size int amount); /** * Handle a break of a block with a specific amount. * This will save the block counts and update the last time status of the island. * * @param block The block that was broken. * @param amount The amount of the block. * @return The result of the block place. */ BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount); /** * Handle a break of a block's key with a specific amount. * This will save the block counts and update the last time status of the island. * * @param key The block's key that was broken. * @param amount The amount of the block. */ void handleBlockBreak(Key key, @Size int amount); /** * Handle a break of a block's key with a specific amount. * This will save the block counts and update the last time status of the island. * * @param key The block's key that was broken. * @param amount The amount of the block. * @return The result of the block place. */ BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount); /** * Handle a break of a block with a specific amount. * * @param block The block that was broken. * @param amount The amount of the block. * @param flags See {@link IslandBlockFlags} */ void handleBlockBreak(Block block, @Size int amount, @IslandBlockFlags int flags); /** * Handle a break of a block with a specific amount. * * @param block The block that was broken. * @param amount The amount of the block. * @param flags See {@link IslandBlockFlags} */ BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount, @IslandBlockFlags int flags); /** * Handle a break of a block's key with a specific amount. * * @param key The block's key that was broken. * @param amount The amount of the block. * @param flags See {@link IslandBlockFlags} */ void handleBlockBreak(Key key, @Size int amount, @IslandBlockFlags int flags); /** * Handle a break of a block's key with a specific amount. * * @param key The block's key that was broken. * @param amount The amount of the block. * @param flags See {@link IslandBlockFlags} */ BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, @IslandBlockFlags int flags); /** * Handle a break of a block with a specific amount. * This will update the last time status of the island. * * @param block The block that was broken. * @param amount The amount of the block. * @param save Whether the block counts should be saved into the database. * @deprecated See {@link #handleBlockBreak(Block, int, int)} */ @Deprecated void handleBlockBreak(Block block, @Size int amount, boolean save); /** * Handle a break of a block with a specific amount. * This will update the last time status of the island. * * @param key The block's key that was broken. * @param amount The amount of the block. * @param save Whether the block counts should be saved into the database. * @deprecated See {@link #handleBlockBreak(Key, int, int)} */ @Deprecated void handleBlockBreak(Key key, @Size int amount, boolean save); /** * Handle a break of a block with a specific amount. * This will update the last time status of the island. * * @param key The block's key that was broken. * @param amount The amount of the block. * @param save Whether the block counts should be saved into the database. * @deprecated See {@link #handleBlockBreak(Key, int, int)} */ @Deprecated void handleBlockBreak(Key key, @Size BigInteger amount, boolean save); /** * Handle break of many blocks in one time. * This will save the block counts and update the last time status of the island. * * @param blocks All the blocks to break. */ void handleBlocksBreak(Map blocks); /** * Handle break of many blocks in one time. * This will save the block counts and update the last time status of the island. * * @param blocks All the blocks to break. * @return Results per block key. Only non-successful results will be returned. */ Map handleBlocksBreakWithResult(Map blocks); /** * Handle break of many blocks in one time. * * @param blocks All the blocks to break. * @param flags See {@link IslandBlockFlags} */ void handleBlocksBreak(Map blocks, @IslandBlockFlags int flags); /** * Handle break of many blocks in one time. * * @param blocks All the blocks to break. * @param flags See {@link IslandBlockFlags} * @return Results per block key. Only non-successful results will be returned. */ Map handleBlocksBreakWithResult(Map blocks, @IslandBlockFlags int flags); /** * Check whether a chunk has blocks inside it. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isChunkDirty(World world, int chunkX, int chunkZ); /** * Check whether a chunk has blocks inside it. * * @param worldName The name of the world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isChunkDirty(String worldName, int chunkX, int chunkZ); /** * Check whether a chunk has blocks inside it. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ); /** * Mark a chunk as it has blocks inside it. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param save Whether to save the changes to database. */ void markChunkDirty(World world, int chunkX, int chunkZ, boolean save); /** * Mark a chunk as it has blocks inside it. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param save Whether to save the changes to database. */ void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save); /** * Mark a chunk as it has no blocks inside it. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param save Whether to save the changes to database. */ void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save); /** * Mark a chunk as it has no blocks inside it. * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. * @param save Whether to save the changes to database. */ void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save); /** * Get the amount of blocks that are on the island. * * @param key The block's key to check. */ BigInteger getBlockCountAsBigInteger(Key key); /** * Get all the blocks that are on the island. */ Map getBlockCountsAsBigInteger(); /** * Get the amount of blocks that are on the island. * Unlike getBlockCount(Key), this method returns the count for * the exactly block that is given as a parameter. * * @param key The block's key to check. */ BigInteger getExactBlockCountAsBigInteger(Key key); /** * Clear all the block counts of the island. */ void clearBlockCounts(); /** * Get the blocks-tracker used by this island. */ IslandBlocksTrackerAlgorithm getBlocksTracker(); /** * Get the worth value of the island, including the money in the bank. */ BigDecimal getWorth(); /** * Get the worth value of the island, excluding bonus worth and the money in the bank. */ BigDecimal getRawWorth(); /** * Get the bonus worth of the island. */ BigDecimal getBonusWorth(); /** * Set a bonus worth for the island. * * @param bonusWorth The bonus to give. */ void setBonusWorth(BigDecimal bonusWorth); /** * Get the bonus level of the island. */ BigDecimal getBonusLevel(); /** * Set a bonus level for the island. * * @param bonusLevel The bonus to give. */ void setBonusLevel(BigDecimal bonusLevel); /** * Get the level of the island. */ BigDecimal getIslandLevel(); /** * Get the level value of the island, excluding the bonus level. */ BigDecimal getRawLevel(); /* * Upgrades related methods */ /** * Get the level of an upgrade for the island. * * @param upgrade The upgrade to check. */ UpgradeLevel getUpgradeLevel(Upgrade upgrade); /** * Set the level of an upgrade for the island. * * @param upgrade The upgrade to set the level. * @param level The level to set. */ void setUpgradeLevel(Upgrade upgrade, int level); /** * Get all the upgrades with their levels. */ Map getUpgrades(); /** * Sync all the upgrade values again. * This will remove custom values that were set using the set commands. */ void syncUpgrades(); /** * Update the upgrade values from default values of config & upgrades file. */ void updateUpgrades(); /** * Get the last time the island was upgraded. */ long getLastTimeUpgrade(); /** * Check if the island has an active upgrade cooldown. */ boolean hasActiveUpgradeCooldown(); /** * Get the crop-growth multiplier for the island. */ double getCropGrowthMultiplier(); /** * Set the crop-growth multiplier for the island. * * @param cropGrowth The multiplier to set. */ void setCropGrowthMultiplier(double cropGrowth); /** * Get the crop-growth multiplier for the island that was set using a command. */ double getCropGrowthRaw(); /** * Get the spawner-rates multiplier for the island. */ double getSpawnerRatesMultiplier(); /** * Set the spawner-rates multiplier for the island. * * @param spawnerRates The multiplier to set. */ void setSpawnerRatesMultiplier(double spawnerRates); /** * Get the spawner-rates multiplier for the island that was set using a command. */ double getSpawnerRatesRaw(); /** * Get the mob-drops multiplier for the island. */ double getMobDropsMultiplier(); /** * Set the mob-drops multiplier for the island. * * @param mobDrops The multiplier to set. */ void setMobDropsMultiplier(double mobDrops); /** * Get the mob-drops multiplier for the island that was set using a command. */ double getMobDropsRaw(); /** * Get the block limit of a block. * * @param key The block's key to check. */ int getBlockLimit(Key key); /** * Get the block limit of a block. * Unlike getBlockLimit(Key), this method returns the count for * the exactly block that is given as a parameter. * * @param key The block's key to check. */ int getExactBlockLimit(Key key); /** * Get the block key used as a limit for another block key. * * @param key The block's key to check. */ Key getBlockLimitKey(Key key); /** * Get all the blocks limits for the island. */ Map getBlocksLimits(); /** * Get all the custom blocks limits for the island. */ Map getCustomBlocksLimits(); /** * Clear all the block limits of the island. */ void clearBlockLimits(); /** * Set the block limit of a block. * * @param key The block's key to set the limit to. * @param limit The limit to set. */ void setBlockLimit(Key key, int limit); /** * Remove the limit of a block. * * @param key The block's key to remove it's limit. */ void removeBlockLimit(Key key); /** * A method to check if a specific block has reached the limit. * This method checks for the block and it's global block key. * * @param key The block's key to check. */ boolean hasReachedBlockLimit(Key key); /** * A method to check if a specific block has reached the limit. * This method checks for the block and it's global block key. * * @param key The block's key to check. * @param amount Amount of the block to be placed. */ boolean hasReachedBlockLimit(Key key, int amount); /** * Get the entity limit of an entity. * * @param entityType The entity's type to check. */ int getEntityLimit(EntityType entityType); /** * Get the entity limit of an entity. * * @param key The key of the entity to check. */ int getEntityLimit(Key key); /** * Get all the entities limits for the island. */ Map getEntitiesLimitsAsKeys(); /** * Get all the custom entities limits for the island. */ Map getCustomEntitiesLimits(); /** * Clear all the entities limits from the island. */ void clearEntitiesLimits(); /** * Set the entity limit of an entity. * * @param entityType The entity's type to set the limit to. * @param limit The limit to set. */ void setEntityLimit(EntityType entityType, int limit); /** * Set the entity limit of an entity. * * @param key The key of the entity to set the limit to. * @param limit The limit to set. */ void setEntityLimit(Key key, int limit); /** * Remove the limit of an entity. * * @param key The entity's key to remove it's limit. */ void removeEntityLimit(Key key); /** * A method to check if a specific entity has reached the limit. * * @param entityType The entity's type to check. */ CompletableFuture hasReachedEntityLimit(EntityType entityType); /** * A method to check if a specific entity has reached the limit. * * @param key The key of the entity to check. */ CompletableFuture hasReachedEntityLimit(Key key); /** * A method to check if a specific entity has reached the limit. * * @param amount The amount of entities that were added. * @param entityType The entity's type to check. */ CompletableFuture hasReachedEntityLimit(EntityType entityType, int amount); /** * A method to check if a specific entity has reached the limit. * * @param amount The amount of entities that were added. * @param key The key of the entity to check. */ CompletableFuture hasReachedEntityLimit(Key key, int amount); /** * Get the entities tracker used by the island. */ IslandEntitiesTrackerAlgorithm getEntitiesTracker(); /** * Get the team limit of the island. */ int getTeamLimit(); /** * Set the team limit of the island. * * @param teamLimit The team limit to set. */ void setTeamLimit(int teamLimit); /** * Get the team limit of the island that was set with a command. */ int getTeamLimitRaw(); /** * Get the warps limit of the island. */ int getWarpsLimit(); /** * Set the warps limit for the island. * * @param warpsLimit The limit to set. */ void setWarpsLimit(int warpsLimit); /** * Get the warps limit of the island that was set using a command. */ int getWarpsLimitRaw(); /** * Add a potion effect to the island. * * @param type The potion effect to add. * @param level The level of the potion effect. * If the level is 0 or below, then the effect will be removed. */ void setPotionEffect(PotionEffectType type, int level); /** * Remove a potion effect from the island. * * @param type The potion effect to remove. */ void removePotionEffect(PotionEffectType type); /** * Get the level of an island effect. * * @param type The potion to check. * @return The level of the potion. If 0, it means that this is not an active effect on the island. */ int getPotionEffectLevel(PotionEffectType type); /** * Get a list of all active island effects with their levels. */ Map getPotionEffects(); /** * Get a list of all custom active island effects with their levels. */ Map getCustomPotionEffects(); /** * Give all the island effects to a player. * If the player is offline, nothing will happen. * * @param superiorPlayer The player to give the effect to. */ void applyEffects(SuperiorPlayer superiorPlayer); /** * Give all the island effects to the players inside the island. */ void applyEffects(); /** * Remove all the island effects from a player. * If the player is offline, nothing will happen. * * @param superiorPlayer The player to remove the effects to. */ void removeEffects(SuperiorPlayer superiorPlayer); /** * Remove all the island effects from the players inside the island. */ void removeEffects(); /** * Remove all the effects from the island. */ void clearEffects(); /** * Set the limit of the amount of players that can have the role in the island. * * @param playerRole The role to set the limit to. * @param limit The limit to set. */ void setRoleLimit(PlayerRole playerRole, int limit); /** * Remove the limit of the amount of players that can have the role in the island. * * @param playerRole The role to remove the limit. */ void removeRoleLimit(PlayerRole playerRole); /** * Get the limit of players that can have the same role at a time. * * @param playerRole The role to check. */ int getRoleLimit(PlayerRole playerRole); /** * Get the limit of players that can have the same role at a time that was set using a command. * * @param playerRole The role to check. */ int getRoleLimitRaw(PlayerRole playerRole); /** * Get all the role limits for the island. */ Map getRoleLimits(); /** * Get all the custom role limits for the island. */ Map getCustomRoleLimits(); /* * Warps related methods */ /** * Create a new warp category. * If a category already exists, it will be returned instead of a new created one. * * @param name The name of the category. */ WarpCategory createWarpCategory(String name); /** * Get a warp category. * * @param name The name of the category. */ @Nullable WarpCategory getWarpCategory(String name); /** * Get a warp category by the slot inside the manage menu. * * @param slot The slot to check. */ @Nullable WarpCategory getWarpCategory(int slot); /** * Rename a category. * * @param warpCategory The category to rename. * @param newName A new name to set. */ void renameCategory(WarpCategory warpCategory, String newName); /** * Delete a warp category. * All the warps inside it will be deleted as well. * * @param warpCategory The category to delete. */ void deleteCategory(WarpCategory warpCategory); /** * Get all the warp categories of the island. */ Map getWarpCategories(); /** * Create a warp for the island. * * @param name The name of the warp. * @param location The location of the warp. * @param warpCategory The category to add the island. * @return The new island warp object. */ IslandWarp createWarp(String name, Location location, @Nullable WarpCategory warpCategory); /** * Create a warp for the island. * * @param name The name of the warp. * @param worldInfo The world of the warp. * @param position The position of the warp. * @param warpCategory The category to add the island. * @return The new island warp object. */ IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, @Nullable WarpCategory warpCategory); /** * Rename a warp. * * @param islandWarp The warp to rename. * @param newName A new name to set. */ void renameWarp(IslandWarp islandWarp, String newName); /** * Get an island warp in a specific location. * * @param location The location to check. */ @Nullable IslandWarp getWarp(Location location); /** * Get an island warp by it's name.. * * @param name The name to check. */ @Nullable IslandWarp getWarp(String name); /** * Teleport a player to a warp. * * @param superiorPlayer The player to teleport. * @param warpName The warp's name to teleport the player to. */ void warpPlayer(SuperiorPlayer superiorPlayer, String warpName); /** * Teleport a player to a warp. * * @param superiorPlayer The player to teleport. * @param warpName The warp's name to teleport the player to. * @param force Force teleportation of the player */ void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force); /** * Delete a warp from the island. * * @param superiorPlayer The player who requested the operation. * @param location The location of the warp. */ void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location location); /** * Delete a warp from the island. * * @param name The warp's name to delete. */ void deleteWarp(String name); /** * Get all the warps of the island. */ Map getIslandWarps(); /* * Ratings related methods */ /** * Get the rating that a player has given the island. * * @param superiorPlayer The player to check. */ Rating getRating(SuperiorPlayer superiorPlayer); /** * Set a rating of a player. * * @param superiorPlayer The player that sets the rating. * @param rating The rating to set. */ void setRating(SuperiorPlayer superiorPlayer, Rating rating); /** * Remove a rating of a player. * * @param superiorPlayer The player to remove the rating of. */ void removeRating(SuperiorPlayer superiorPlayer); /** * Get the total rating of the island. */ double getTotalRating(); /** * Get the amount of ratings that have have been given to the island. */ int getRatingAmount(); /** * Get all the ratings of the island. */ Map getRatings(); /** * Remove all the ratings of the island. */ void removeRatings(); /* * Settings related methods */ /** * Check whether a settings is enabled or not. * * @param islandFlag The settings to check. */ boolean hasSettingsEnabled(IslandFlag islandFlag); /** * Get all the settings of the island. * If the byte value is 1, the setting is enabled. Otherwise, it's disabled. */ Map getAllSettings(); /** * Enable an island settings. * * @param islandFlag The settings to enable. */ void enableSettings(IslandFlag islandFlag); /** * Disable an island settings. * * @param islandFlag The settings to disable. */ void disableSettings(IslandFlag islandFlag); /** * Reset the island settings to default values. */ void resetSettings(); /* * Generator related methods */ /** * Set a percentage for a specific key in a specific world. * Percentage can be between 0 and 100 (0 will remove the key from the list). * Calling this method will not make events get fired. *

* This function sets the amount of the key using the following formula: * amount = (percentage * total_amount) / (1 - percentage) *

* If the percentage is 100, the rest of the amounts will be cleared and * the material's amount will be set to 1. *

* The amount is rounded to ensure a smaller loss, and currently it's 1%~ loss. * * @param key The block to change the generator rate of. * @param percentage The percentage to set the new rate. * @param dimension The world to change the rates in. */ void setGeneratorPercentage(Key key, int percentage, Dimension dimension); /** * Set a percentage for a specific key in a specific world. * Percentage can be between 0 and 100 (0 will remove the key from the list). *

* This function sets the amount of the key using the following formula: * amount = (percentage * total_amount) / (1 - percentage) *

* If the percentage is 100, the rest of the amounts will be cleared and * the material's amount will be set to 1. *

* The amount is rounded to ensure a smaller loss, and currently it's 1%~ loss. * * @param key The block to change the generator rate of. * @param percentage The percentage to set the new rate. * @param dimension The world to change the rates in. * @param caller The player that changes the percentages (used for the event). * If null, it means the console did the operation. * @param callEvent Whether to call the {@link IslandChangeGeneratorRateEvent} * @return Whether the operation succeed. * The operation may fail if callEvent is true and the event was cancelled. */ boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension, @Nullable SuperiorPlayer caller, boolean callEvent); /** * Get the percentage for a specific key in a specific world. * The formula is (amount * 100) / total_amount. * * @param key The material key * @param dimension The world dimension. */ int getGeneratorPercentage(Key key, Dimension dimension); /** * Get the percentages of the materials for the cobblestone generator in the island for a specific world. */ Map getGeneratorPercentages(Dimension dimension); /** * Set an amount for a specific key in a specific world. */ void setGeneratorAmount(Key key, @Size int amount, Dimension dimension); /** * Remove a rate for a specific key in a specific world. */ void removeGeneratorAmount(Key key, Dimension dimension); /** * Get the amount of a specific key in a specific world. */ int getGeneratorAmount(Key key, Dimension dimension); /** * Get the total amount of all the generator keys together. */ int getGeneratorTotalAmount(Dimension dimension); /** * Get the amounts of the materials for the cobblestone generator in the island. */ Map getGeneratorAmounts(Dimension dimension); /** * Get the custom amounts of the materials for the cobblestone generator in the island. */ Map getCustomGeneratorAmounts(Dimension dimension); /** * Clear all the custom generator amounts for this island. */ void clearGeneratorAmounts(Dimension dimension); /** * Generate a block at a specified location. * The method calculates a block to generate from {@link #getGeneratorAmounts(Dimension)}. * It doesn't look for any conditions for generating it - lava, water, etc are not required. * The method will fail if there are no valid generator rates for the environment. * * @param location The location to generate block at. * @param optimizeDefaultBlock When set to true and the default block needs to be generated, the plugin will * not play any effect, count the block towards the block counts or set the block. * This is useful when calling the method from BlockFromToEvent, and instead of letting * the plugin do the logic of vanilla, the plugin lets the game do it. * @return The block type that was generated, null if failed. */ @Nullable Key generateBlock(Location location, boolean optimizeDefaultBlock); /** * Generate a block at a specified location. * The method calculates a block to generate from {@link #getGeneratorAmounts(Dimension)}. * It doesn't look for any conditions for generating it - lava, water, etc are not required. * The method will fail if there are no valid generator rates for the environment. * * @param location The location to generate block at. * @param dimension The world to get generator rates from. * @param optimizeDefaultBlock When set to true and the default block needs to be generated, the plugin will * not play any effect, count the block towards the block counts or set the block. * This is useful when calling the method from BlockFromToEvent, and instead of letting * the plugin do the logic of vanilla, the plugin lets the game do it. * @return The block type that was generated, null if failed. */ @Nullable Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock); /* * Schematic methods */ /** * Checks if a schematic was generated already. * * @param dimension The dimension to check. */ boolean wasSchematicGenerated(Dimension dimension); /** * Set schematic generated flag to true. * * @param dimension The dimension to set. */ void setSchematicGenerate(Dimension dimension); /** * Set schematic generated flag. * * @param dimension The dimension to set. * @param generated The flag to set. */ void setSchematicGenerate(Dimension dimension, boolean generated); /** * Get the generated schematics. */ Collection getGeneratedSchematics(); /** * Get the schematic that was used to create the island. */ String getSchematicName(); /* * Island top methods */ int getPosition(SortingType sortingType); /* * Vault related methods */ /** * Get the island chest. */ IslandChest[] getChest(); /** * Get the amount of pages the island chest has. */ int getChestSize(); /** * Set the amount of rows for the chest in a specific index. * * @param index The index of the page (0 or above) * @param rows The amount of rows for that page. */ void setChestRows(int index, int rows); /** * Create a new builder for a {@link Island} object. */ static Builder newBuilder() { return SuperiorSkyblockAPI.getFactory().createIslandBuilder(); } /** * The {@link Builder} interface is used to create {@link Island} objects with predefined values. * All of its methods are setters for all the values possible to create an island with. * Use {@link Builder#build()} to create the new {@link Island} object. You must set * {@link Builder#setOwner(SuperiorPlayer)}, {@link Builder#setUniqueId(UUID)} and * {@link Builder#setCenter(Location)} before creating a new {@link Island} */ interface Builder { Builder setOwner(@Nullable SuperiorPlayer owner); @Nullable SuperiorPlayer getOwner(); Builder setUniqueId(UUID uuid); UUID getUniqueId(); Builder setCenter(Location center); Location getCenter(); Builder setName(String islandName); String getName(); Builder setSchematicName(String schematicName); String getScehmaticName(); Builder setCreationTime(long creationTime); long getCreationTime(); Builder setDiscord(String discord); String getDiscord(); Builder setPaypal(String paypal); String getPaypal(); Builder setBonusWorth(BigDecimal bonusWorth); BigDecimal getBonusWorth(); Builder setBonusLevel(BigDecimal bonusLevel); BigDecimal getBonusLevel(); Builder setLocked(boolean isLocked); boolean isLocked(); Builder setIgnored(boolean isIgnored); boolean isIgnored(); Builder setDescription(String description); String getDescription(); Builder setGeneratedSchematic(Dimension dimension); Set getGeneratedSchematics(); Builder setUnlockedWorld(Dimension dimension); Set getUnlockedWorlds(); Builder setLastTimeUpdated(long lastTimeUpdated); long getLastTimeUpdated(); Builder setDirtyChunk(String worldName, int chunkX, int chunkZ); boolean isDirtyChunk(String worldName, int chunkX, int chunkZ); Builder setBlockCount(Key block, BigInteger count); KeyMap getBlockCounts(); Builder setEntityCount(Key entity, BigInteger count); KeyMap getEntityCounts(); Builder setIslandHome(Location location, Dimension dimension); Builder setIslandHome(Dimension dimension, WorldPosition worldPosition); Map getIslandHomesAsDimensions(); Builder addIslandMember(SuperiorPlayer superiorPlayer); List getIslandMembers(); Builder addBannedPlayer(SuperiorPlayer superiorPlayer); List getBannedPlayers(); Builder setPlayerPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value); Map getPlayerPermissions(); Builder setRolePermission(IslandPrivilege islandPrivilege, PlayerRole requiredRole); Map getRolePermissions(); Builder setUpgrade(Upgrade upgrade, int level); Map getUpgrades(); Builder setBlockLimit(Key block, int limit); KeyMap getBlockLimits(); Builder setRating(SuperiorPlayer superiorPlayer, Rating rating); Map getRatings(); Builder setCompletedMission(Mission mission, int finishCount); Map, Integer> getCompletedMissions(); Builder setIslandFlag(IslandFlag islandFlag, boolean value); Map getIslandFlags(); Builder setGeneratorRate(Key block, int rate, Dimension dimension); Map> getGeneratorRatesAsDimensions(); Builder addUniqueVisitor(SuperiorPlayer superiorPlayer, long visitTime); Map getUniqueVisitors(); Builder setEntityLimit(Key entity, int limit); KeyMap getEntityLimits(); Builder setIslandEffect(PotionEffectType potionEffectType, int level); Map getIslandEffects(); Builder setIslandChest(int index, ItemStack[] contents); List getIslandChests(); Builder setRoleLimit(PlayerRole playerRole, int limit); Map getRoleLimits(); Builder setVisitorHome(Location location, Dimension dimension); Builder setVisitorHome(Dimension dimension, WorldPosition worldPosition); Map getVisitorHomesAsDimensions(); Builder setIslandSize(int islandSize); int getIslandSize(); Builder setTeamLimit(int teamLimit); int getTeamLimit(); Builder setWarpsLimit(int warpsLimit); int getWarpsLimit(); Builder setCropGrowth(double cropGrowth); double getCropGrowth(); Builder setSpawnerRates(double spawnerRates); double getSpawnerRates(); Builder setMobDrops(double mobDrops); double getMobDrops(); Builder setCoopLimit(int coopLimit); int getCoopLimit(); Builder setBankLimit(BigDecimal bankLimit); BigDecimal getBankLimit(); Builder setBalance(BigDecimal balance); BigDecimal getBalance(); Builder setLastInterestTime(long lastInterestTime); long getLastInterestTime(); Builder addWarp(String name, String category, Location location, boolean isPrivate, @Nullable ItemStack icon); Builder addWarp(String name, String category, WorldInfo worldInfo, WorldPosition worldPosition, boolean isPrivate, @Nullable ItemStack icon); boolean hasWarp(String name); boolean hasWarp(Location location); boolean hasWarp(WorldInfo worldInfo, WorldPosition worldPosition); Builder addWarpCategory(String name, int slot, @Nullable ItemStack icon); boolean hasWarpCategory(String name); Builder addBankTransaction(BankTransaction bankTransaction); List getBankTransactions(); Builder setPersistentData(byte[] persistentData); byte[] getPersistentData(); Island build(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandBlockFlags.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.common.annotations.IntType; /** * The integer value element annotated with {@link IslandBlockFlags} represents flags related to what to do * when block change is recorded. It is mainly used within the {@link Island} interface and its methods. */ @IntType({IslandBlockFlags.SAVE_BLOCK_COUNTS, IslandBlockFlags.UPDATE_LAST_TIME_STATUS}) public @interface IslandBlockFlags { /** * Indicates to save block counts into the DB after the block count change. */ int SAVE_BLOCK_COUNTS = (1 << 0); /** * Indicates to update the last time the island was updated due to the block count change. */ int UPDATE_LAST_TIME_STATUS = (1 << 1); /** * Indicates to update block counts only for the provided blocks, and do not count global keys, limit keys, etc. */ int RAW_BLOCKS = (1 << 2); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandChest.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; public interface IslandChest extends InventoryHolder { /** * Get the island of the chest. */ Island getIsland(); /** * Get the index of this chest. */ int getIndex(); /** * Get the amount of rows for this chest. */ int getRows(); /** * Set the amount of rows for this chest. * * @param rows The new amount of rows. */ void setRows(int rows); /** * Get the contents of the chest. */ ItemStack[] getContents(); /** * Open this chest for a player. */ void openChest(SuperiorPlayer superiorPlayer); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandChunkFlags.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.common.annotations.IntType; /** * The integer value element annotated with {@link IslandChunkFlags} represents flags related to which chunks * to do the action on. It is mainly used within the {@link Island} interface and its methods. */ @IntType({IslandChunkFlags.ONLY_PROTECTED, IslandChunkFlags.NO_EMPTY_CHUNKS}) public @interface IslandChunkFlags { /** * Indicates to only do the action on chunks within the protected-radius of the island. */ int ONLY_PROTECTED = (1 << 0); /** * Indicates to only do the action on chunks that have blocks inside them. * It is generally a good practice to use this flag whenever possible to reduce performance impact. */ int NO_EMPTY_CHUNKS = (1 << 1); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandFlag.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class IslandFlag implements Enumerable { private static final Map islandFlags = new HashMap<>(); private static int ordinalCounter = 0; private final String name; private final int ordinal; private IslandFlag(String name) { this.name = name.toUpperCase(Locale.ENGLISH); this.ordinal = ordinalCounter++; } @Override public int ordinal() { return this.ordinal; } /** * Get all the island flags. */ public static Collection values() { return islandFlags.values(); } /** * Get an island flag by it's name. * * @param name The name to check. */ public static IslandFlag getByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); IslandFlag islandFlag = islandFlags.get(name.toUpperCase(Locale.ENGLISH)); Preconditions.checkNotNull(islandFlag, "Couldn't find an IslandFlag with the name " + name + "."); return islandFlag; } /** * Register a new island flag. * * @param name The name for the island flag. */ public static void register(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); name = name.toUpperCase(Locale.ENGLISH); Preconditions.checkState(!islandFlags.containsKey(name), "IslandFlag with the name " + name + " already exists."); islandFlags.put(name, new IslandFlag(name)); } /** * Get the name of the island flag. */ public String getName() { return name; } @Override public String toString() { return "IslandFlag{name=" + name + "}"; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.GameMode; import org.bukkit.Location; /** * Object that handles the data of the island preview task. */ public interface IslandPreview { /** * Get the player that is inside the preview. */ SuperiorPlayer getPlayer(); /** * Get the location of the island preview. */ Location getLocation(); /** * Get the location of the island preview. * * @param location Location object to re-use. */ @Nullable Location getLocation(@Nullable Location location); /** * Get the requested schematic. */ String getSchematic(); /** * Get the island name that was requested. */ String getIslandName(); /** * Get the game mode that the player had before the preview started. */ GameMode getPreviousGameMode(); /** * Handle confirmation of creation of the island. */ void handleConfirm(); /** * Handle cancellation of the creation of the island. */ void handleCancel(); /** * Handle escaping from the area of the preview. */ void handleEscape(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPrivilege.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class IslandPrivilege implements Enumerable { private static final Map islandPrivileges = new HashMap<>(); private static int ordinalCounter = 0; private final String name; private final Type type; private final int ordinal; private IslandPrivilege(String name, Type type) { this.name = name.toUpperCase(Locale.ENGLISH); this.type = type; this.ordinal = ordinalCounter++; } @Override public int ordinal() { return this.ordinal; } /** * Get the name of the island privilege. */ public String getName() { return name; } /** * Get the type of the privilege. */ public Type getType() { return type; } @Override public String toString() { return "IslandPrivilege{name=" + name + ", type=" + type + "}"; } /** * Get all the island privileges. */ public static Collection values() { return islandPrivileges.values(); } /** * Get an island privilege by it's name. * * @param name The name to check. */ public static IslandPrivilege getByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); IslandPrivilege islandPrivilege = islandPrivileges.get(name.toUpperCase(Locale.ENGLISH)); Preconditions.checkNotNull(islandPrivilege, "Couldn't find an IslandPrivilege with the name " + name + "."); return islandPrivilege; } /** * Register a new {@link Type#ACTION} island privilege. * * @param name The name for the island privilege. */ public static void register(String name) { register(name, Type.ACTION); } /** * Register a new island privilege. * * @param name The name for the island privilege. * @param type The type of the privilege. */ public static void register(String name, Type type) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkNotNull(type, "name parameter cannot be null."); name = name.toUpperCase(Locale.ENGLISH); Preconditions.checkState(!islandPrivileges.containsKey(name), "IslandPrivilege with the name " + name + " already exists."); islandPrivileges.put(name, new IslandPrivilege(name, type)); } /** * Represents the type of IslandPrivilege. */ public enum Type { /** * The ACTION type is given for privileges that allow player to do actions on islands. * Privileges of this type can be given to visitors, coops and players that are not part of the island team. */ ACTION, /** * The COMMAND type is given for privileges that give access to commands on the island. * Privileges of this type can only be given to players that are part of the island. */ COMMAND } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/PermissionNode.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import java.util.Map; public interface PermissionNode extends Cloneable { /** * Check whether or not the node has a permission. * * @param islandPrivilege The privilege to check. */ boolean hasPermission(IslandPrivilege islandPrivilege); /** * Set whether or not the node should have a permission. * * @param islandPrivilege The privilege to set. * @param value The value to set. */ void setPermission(IslandPrivilege islandPrivilege, boolean value); /** * Get all permissions set using the provided method. * This does not include default permissions. */ Map getCustomPermissions(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/PlayerRole.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.common.annotations.Nullable; public interface PlayerRole { /** * Get the id of the role. */ int getId(); /** * Get the name of the role. */ String getName(); /** * Get the display-name of the role. * This is shown in chat, placeholders, etc. */ String getDisplayName(); /** * Get the weight of the role in the ladder. */ int getWeight(); /** * Check whether or not the role is higher than another role. * * @param role The role to check. */ boolean isHigherThan(PlayerRole role); /** * Check whether or not the role is less than another role. * * @param role The role to check. */ boolean isLessThan(PlayerRole role); /** * Check whether or not the role is the first role in the ladder. */ boolean isFirstRole(); /** * Check whether or not the role is the last role in the ladder. */ boolean isLastRole(); /** * Check whether or not the role is the role is in the ladder. */ boolean isRoleLadder(); /** * Get the next role in the ladder. * Will return null if the role is not in the ladder, or it's the last role in the ladder. */ @Nullable PlayerRole getNextRole(); /** * Get the previous role in the ladder. * Will return null if the role is not in the ladder, or it's the first role in the ladder. */ @Nullable PlayerRole getPreviousRole(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/SortingType.java ================================================ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Map; public class SortingType implements Comparator, Enumerable { private static final Map sortingTypes = new HashMap<>(); private static int ordinalCounter = 0; private static final Comparator ISLAND_NAMES_COMPARATOR = (o1, o2) -> { String firstName = o1.getStrippedName().isEmpty() ? o1.getOwner() == null ? "null" : o1.getOwner().getName() : o1.getStrippedName(); String secondName = o2.getStrippedName().isEmpty() ? o2.getOwner() == null ? "null" : o2.getOwner().getName() : o2.getStrippedName(); return firstName.compareTo(secondName); }; private final String name; private final Comparator comparator; private final int ordinal; private SortingType(String name, Comparator comparator, boolean handleEqualsIslands) { this.name = name; this.comparator = !handleEqualsIslands ? comparator : (o1, o2) -> { int compare = comparator.compare(o1, o2); return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare; }; this.ordinal = ordinalCounter++; } @Override public int ordinal() { return this.ordinal; } /** * Get all the sorting types. */ public static Collection values() { return sortingTypes.values(); } /** * Get a sorting type by it's name. * * @param name The name to check. */ public static SortingType getByName(String name) { return sortingTypes.get(name); } /** * Register a new sorting type. * * @param name The name for the sorting type. * @param comparator The comparator for sorting the islands. */ public static void register(String name, Comparator comparator) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkNotNull(comparator, "comparator parameter cannot be null."); register(name, comparator, true); } /** * Register a new sorting type. * * @param name The name for the sorting type. * @param comparator The comparator for sorting the islands. * @param handleEqualsIslands Should the plugin handle equals islands? * If that's false, you should handle it on your own. */ public static void register(String name, Comparator comparator, boolean handleEqualsIslands) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkNotNull(comparator, "comparator parameter cannot be null."); Preconditions.checkState(!sortingTypes.containsKey(name), "SortingType with the name " + name + " already exists."); SortingType sortingType = new SortingType(name, comparator, handleEqualsIslands); sortingTypes.put(name, sortingType); SuperiorSkyblockAPI.getGrid().registerSortingType(sortingType); } /** * Get the name of the sorting type. */ public String getName() { return name; } /** * Get the comparator of the sorting type. */ public Comparator getComparator() { return comparator; } @Override public int compare(Island o1, Island o2) { return comparator.compare(o1, o2); } @Override public String toString() { return "SortingType{name=" + name + "}"; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandBlocksTrackerAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.island.algorithms; import com.bgsoftware.superiorskyblock.api.key.Key; import java.math.BigInteger; import java.util.Map; public class DelegateIslandBlocksTrackerAlgorithm implements IslandBlocksTrackerAlgorithm { protected final IslandBlocksTrackerAlgorithm handle; protected DelegateIslandBlocksTrackerAlgorithm(IslandBlocksTrackerAlgorithm handle) { this.handle = handle; } @Override public boolean trackBlock(Key key, BigInteger amount) { return this.handle.trackBlock(key, amount); } @Override public boolean untrackBlock(Key key, BigInteger amount) { return this.handle.untrackBlock(key, amount); } @Override public BigInteger getBlockCount(Key key) { return this.handle.getBlockCount(key); } @Override public BigInteger getExactBlockCount(Key key) { return this.handle.getExactBlockCount(key); } @Override public Map getBlockCounts() { return this.handle.getBlockCounts(); } @Override public void clearBlockCounts() { this.handle.clearBlockCounts(); } @Override public void setLoadingDataMode(boolean loadingDataMode) { this.handle.setLoadingDataMode(loadingDataMode); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandCalculationAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.island.algorithms; import com.bgsoftware.superiorskyblock.api.island.Island; import java.util.concurrent.CompletableFuture; public class DelegateIslandCalculationAlgorithm implements IslandCalculationAlgorithm { protected final IslandCalculationAlgorithm handle; protected DelegateIslandCalculationAlgorithm(IslandCalculationAlgorithm handle) { this.handle = handle; } @Override @Deprecated public CompletableFuture calculateIsland() { return this.handle.calculateIsland(); } @Override public CompletableFuture calculateIsland(Island island) { return this.handle.calculateIsland(island); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandEntitiesTrackerAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.island.algorithms; import com.bgsoftware.superiorskyblock.api.key.Key; import java.util.Map; public class DelegateIslandEntitiesTrackerAlgorithm implements IslandEntitiesTrackerAlgorithm { protected final IslandEntitiesTrackerAlgorithm handle; protected DelegateIslandEntitiesTrackerAlgorithm(IslandEntitiesTrackerAlgorithm handle) { this.handle = handle; } @Override public boolean trackEntity(Key key, int amount) { return this.handle.trackEntity(key, amount); } @Override public boolean untrackEntity(Key key, int amount) { return this.handle.untrackEntity(key, amount); } @Override public int getEntityCount(Key key) { return this.handle.getEntityCount(key); } @Override public Map getEntitiesCounts() { return this.handle.getEntitiesCounts(); } @Override public void clearEntityCounts() { this.handle.clearEntityCounts(); } @Override public void recalculateEntityCounts() { this.handle.recalculateEntityCounts(); } @Override public boolean canRecalculateEntityCounts() { return this.handle.canRecalculateEntityCounts(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/IslandBlocksTrackerAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.island.algorithms; import com.bgsoftware.superiorskyblock.api.key.Key; import java.math.BigInteger; import java.util.Map; public interface IslandBlocksTrackerAlgorithm { /** * Track a new block with a specific amount. * * @param key The block's key that should be tracked. * @param amount The amount of the block. * @return Whether the block was successfully tracked. */ boolean trackBlock(Key key, BigInteger amount); /** * Untrack a block with a specific amount. * * @param key The block's key that should be untracked. * @param amount The amount of the block. * @return Whether the block was successfully untracked. */ boolean untrackBlock(Key key, BigInteger amount); /** * Get the amount of blocks that are on the island. * * @param key The block's key to check. */ BigInteger getBlockCount(Key key); /** * Get the amount of blocks that are on the island. * Unlike getBlockCount(Key), this method returns the count for * the exactly block that is given as a parameter. * * @param key The block's key to check. */ BigInteger getExactBlockCount(Key key); /** * Get all the blocks that are on the island. */ Map getBlockCounts(); /** * Clear all the block counts of the island. */ void clearBlockCounts(); /** * Set whether the tracker should be in "loading data mode" or not. * When loading mode is enabled, the tracker should only track blocks for the given blocks * and not their variants (limits, global blocks, etc) * * @param loadingDataMode loading mode */ void setLoadingDataMode(boolean loadingDataMode); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/IslandCalculationAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.island.algorithms; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import java.math.BigInteger; import java.util.Map; import java.util.concurrent.CompletableFuture; public interface IslandCalculationAlgorithm { /** * Calculate the island blocks of the island. * * @return CompletableFuture instance of the result. * @deprecated See {@link #calculateIsland(Island)} */ @Deprecated default CompletableFuture calculateIsland() { throw new UnsupportedOperationException("This method is not supported anymore. Use calculateIsland(Island) instead."); } /** * Calculate the island blocks of the island. * * @param island The island to calculate blocks for. * @return CompletableFuture instance of the result. */ CompletableFuture calculateIsland(Island island); /** * Represents calculation result. */ interface IslandCalculationResult { /** * Get all block-counts that were calculated. */ Map getBlockCounts(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/IslandEntitiesTrackerAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.island.algorithms; import com.bgsoftware.superiorskyblock.api.key.Key; import java.util.Map; public interface IslandEntitiesTrackerAlgorithm { /** * Track a new entity with a specific amount. * * @param key The entity's key that should be tracked. * @param amount The amount of the entity. * @return Whether the entity was successfully tracked. */ boolean trackEntity(Key key, int amount); /** * Untrack a entity with a specific amount. * * @param key The entity's key that should be untracked. * @param amount The amount of the entity. * @return Whether the entity was successfully untracked. */ boolean untrackEntity(Key key, int amount); /** * Get the amount of entities that are on the island. * * @param key The entity's key to check. */ int getEntityCount(Key key); /** * Get all the entities that are on the island. */ Map getEntitiesCounts(); /** * Clear all the entity counts of the island. */ void clearEntityCounts(); /** * Recalculate entity counts on the island. */ void recalculateEntityCounts(); /** * Check if it possible to recalculate entity counts on the island. */ boolean canRecalculateEntityCounts(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/BankTransaction.java ================================================ package com.bgsoftware.superiorskyblock.api.island.bank; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.BankAction; import java.math.BigDecimal; import java.util.UUID; public interface BankTransaction { /** * Get the player that made the transaction. * Can be null if the console has made the transaction. */ @Nullable UUID getPlayer(); /** * Get the transaction action. */ BankAction getAction(); /** * Get the position of the transaction */ int getPosition(); /** * Get the time the transaction was made. */ long getTime(); /** * Get formatted time of the time the transaction was made. */ String getDate(); /** * Get the reason for failure of the transaction. * If succeed, an empty string will be returned. *

* Some fail reasons, such as "Not enough money", will not be logged. */ String getFailureReason(); /** * Get the amount that was withdrawn or deposited. * If the transaction failed, -1 will be returned. */ BigDecimal getAmount(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateBankTransaction.java ================================================ package com.bgsoftware.superiorskyblock.api.island.bank; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.BankAction; import java.math.BigDecimal; import java.util.UUID; public class DelegateBankTransaction implements BankTransaction { protected final BankTransaction handle; protected DelegateBankTransaction(BankTransaction handle) { this.handle = handle; } @Nullable @Override public UUID getPlayer() { return this.handle.getPlayer(); } @Override public BankAction getAction() { return this.handle.getAction(); } @Override public int getPosition() { return this.handle.getPosition(); } @Override public long getTime() { return this.handle.getTime(); } @Override public String getDate() { return this.handle.getDate(); } @Override public String getFailureReason() { return this.handle.getFailureReason(); } @Override public BigDecimal getAmount() { return this.handle.getAmount(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateIslandBank.java ================================================ package com.bgsoftware.superiorskyblock.api.island.bank; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.List; public class DelegateIslandBank implements IslandBank { protected final IslandBank handle; public DelegateIslandBank(IslandBank handle) { this.handle = handle; } @Override public BigDecimal getBalance() { return this.handle.getBalance(); } @Override public void setBalance(BigDecimal balance) { this.handle.setBalance(balance); } @Override public BankTransaction depositMoney(SuperiorPlayer superiorPlayer, BigDecimal amount) { return this.handle.depositMoney(superiorPlayer, amount); } @Override public BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal amount) { return this.handle.depositAdminMoney(commandSender, amount); } @Override public boolean canDepositMoney(BigDecimal amount) { return this.handle.canDepositMoney(amount); } @Override public BankTransaction withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal amount, @Nullable List commandsToExecute) { return this.handle.withdrawMoney(superiorPlayer, amount, commandsToExecute); } @Override public BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecimal amount) { return this.handle.withdrawAdminMoney(commandSender, amount); } @Override public List getAllTransactions() { return this.handle.getAllTransactions(); } @Override public List getTransactions(SuperiorPlayer superiorPlayer) { return this.handle.getTransactions(superiorPlayer); } @Override public List getConsoleTransactions() { return this.handle.getConsoleTransactions(); } @Override public void loadTransaction(BankTransaction bankTransaction) { this.handle.loadTransaction(bankTransaction); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/IslandBank.java ================================================ package com.bgsoftware.superiorskyblock.api.island.bank; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.List; public interface IslandBank { /** * Get balance in bank. */ BigDecimal getBalance(); /** * Set the balance in the bank. * This will not create any records, and used to load the balance from the database. */ void setBalance(BigDecimal balance); /** * Deposit money into the bank. * * @param superiorPlayer The player that deposited the money. * @param amount The amount to deposit. * @return The transaction details. */ BankTransaction depositMoney(SuperiorPlayer superiorPlayer, BigDecimal amount); /** * Deposit money into the bank, without taking money from any player. * * @param commandSender The player that deposited the money. * @param amount The amount to deposit. * @return The transaction details. */ BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal amount); /** * Whether it's possible to deposit money into the bank without exceeding the bank limit. * * @param amount The amount of money to deposit. */ boolean canDepositMoney(BigDecimal amount); /** * Withdraw money from the bank. * * @param superiorPlayer The player that withdrawn the money. * @param amount The amount to withdraw. * @param commandsToExecute Commands to execute instead of using the default economy provider. * The commands can use {0} as player's name placeholder, and {1} for the amount. * @return The transaction details. */ BankTransaction withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal amount, @Nullable List commandsToExecute); /** * Withdraw money from the bank, without giving it to any player. * * @param commandSender The player that withdrawn the money. * @param amount The amount to withdraw. * @return The transaction details. */ BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecimal amount); /** * Get all the transactions of the bank, sorted by the time they were created. */ List getAllTransactions(); /** * Get all the transactions made by a player. */ List getTransactions(SuperiorPlayer superiorPlayer); /** * Get all the transactions made by CONSOLE. */ List getConsoleTransactions(); /** * Load a transaction log. * Used to load transactions from the database. * * @param bankTransaction The transaction object to load. */ void loadTransaction(BankTransaction bankTransaction); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCache.java ================================================ package com.bgsoftware.superiorskyblock.api.island.cache; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import java.util.function.Function; /** * Island caches can be used by other plugins to store temporary data for an island, retrieve it, etc. * The cache is not persistent between server sessions. For persistent data solution, see {@link Island#getPersistentDataContainer()} * Data can be stored and retrieved by registering custom {@link IslandCacheKey} for your plugin. * The cache is thread-safe and can be accessed from multiple threads. */ public interface IslandCache { /** * Get the island this cache is for. */ Island getIsland(); /** * Store data in this cache. * * @param key The key to store. * @param value The value to store. * @return The old value that was stored in the cache, or null if not data was cached. */ @Nullable T store(IslandCacheKey key, T value); /** * Remove data from this cache. * * @param key The cache key. * @return The old value that was stored in the cache, or null if not data was cached. */ @Nullable T remove(IslandCacheKey key); /** * Get data that was stored. * * @param key The cache key * @return The value stored for the provided key, or null if no data was cached. */ @Nullable T get(IslandCacheKey key); /** * Get data that was stored. * * @param key The cache key * @param def The value to return in case the cache did not contain the provided key * @return The value stored for the provided key. */ T getOrDefault(IslandCacheKey key, T def); /** * Get data that was stored. * * @param key The cache key * @param mappingFunction The value to store in case the cache did not contain the provided key * @return The value stored for the provided key. */ T computeIfAbsent(IslandCacheKey key, Function, T> mappingFunction); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCacheKey.java ================================================ package com.bgsoftware.superiorskyblock.api.island.cache; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class IslandCacheKey implements Enumerable { private static final Map> islandCacheKeys = new HashMap<>(); private static int ordinalCounter = 0; private final String name; private final Class valueType; private final int ordinal; private IslandCacheKey(String name, Class valueType) { this.name = name.toUpperCase(Locale.ENGLISH); this.valueType = valueType; this.ordinal = ordinalCounter++; } /** * Get the name of the island cache key. */ public String getName() { return name; } /** * Get the type of the value for this cache-key. */ public Class getValueType() { return valueType; } @Override public int ordinal() { return this.ordinal; } @Override public String toString() { return "IslandCacheKey{name=" + name + "}"; } /** * Get all the island cache keys. */ public static Collection> values() { return islandCacheKeys.values(); } /** * Get an island cache key by its name. * * @param name The name to check. */ public static IslandCacheKey getByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); IslandCacheKey islandCacheKey = islandCacheKeys.get(name.toUpperCase(Locale.ENGLISH)); Preconditions.checkNotNull(islandCacheKey, "Couldn't find an IslandCacheKey with the name " + name + "."); return islandCacheKey; } /** * Register a new island cache key. * * @param name The name for the island cache key. */ public static void register(String name, Class valueType) { Preconditions.checkNotNull(name, "name parameter cannot be null."); name = name.toUpperCase(Locale.ENGLISH); Preconditions.checkState(!islandCacheKeys.containsKey(name), "IslandCacheKey with the name " + name + " already exists."); islandCacheKeys.put(name, new IslandCacheKey<>(name, valueType)); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java ================================================ package com.bgsoftware.superiorskyblock.api.island.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.SortingType; import org.bukkit.Location; import java.util.List; import java.util.UUID; public class DelegateIslandsContainer implements IslandsContainer { protected final IslandsContainer handle; protected DelegateIslandsContainer(IslandsContainer handle) { this.handle = handle; } @Override public void addIsland(Island island) { this.handle.addIsland(island); } @Override public void removeIsland(Island island) { this.handle.removeIsland(island); } @Nullable @Override public Island getIslandByUUID(UUID uuid) { return this.handle.getIslandByUUID(uuid); } @Override public Island getIslandByName(String name) { return this.handle.getIslandByName(name); } @Override public void updateIslandName(Island island, String oldName) { this.handle.updateIslandName(island, oldName); } @Nullable @Override @Deprecated public Island getIslandByLeader(UUID uuid) { return this.handle.getIslandByLeader(uuid); } @Nullable @Override public Island getIslandAtPosition(int position, SortingType sortingType) { return this.handle.getIslandAtPosition(position, sortingType); } @Override public int getIslandPosition(Island island, SortingType sortingType) { return this.handle.getIslandPosition(island, sortingType); } @Override public int getIslandsAmount() { return this.handle.getIslandsAmount(); } @Nullable @Override public Island getIslandAt(Location location) { return this.handle.getIslandAt(location); } @Override @Deprecated public void transferIsland(UUID oldLeader, UUID newLeader) { this.handle.transferIsland(oldLeader, newLeader); } @Override public void sortIslands(SortingType sortingType, @Nullable Runnable onFinish) { this.handle.sortIslands(sortingType, onFinish); } @Override public void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Runnable onFinish) { this.handle.sortIslands(sortingType, forceSort, onFinish); } @Override public void notifyChange(SortingType sortingType, Island island) { this.handle.notifyChange(sortingType, island); } @Override public List getSortedIslands(SortingType sortingType) { return this.handle.getSortedIslands(sortingType); } @Override public List getIslandsUnsorted() { return this.handle.getIslandsUnsorted(); } @Override public void addSortingType(SortingType sortingType, boolean sort) { this.handle.addSortingType(sortingType, sort); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/IslandsContainer.java ================================================ package com.bgsoftware.superiorskyblock.api.island.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import java.util.List; import java.util.UUID; public interface IslandsContainer { /** * Add an island to the islands container. * * @param island The island to add. */ void addIsland(Island island); /** * Remove an island from the islands container. * * @param island The island to remove. */ void removeIsland(Island island); /** * Get an island by its uuid. * * @param uuid The uuid of the island. */ @Nullable Island getIslandByUUID(UUID uuid); /** * Get an island by its name. * * @param name The name of the island. */ @Nullable Island getIslandByName(String name); /** * Update an island with a new name. * * @param island The island to update. * @param oldName The old name of the island. */ void updateIslandName(Island island, String oldName); /** * Get an island by its leader's uuid. * * @param uuid The uuid of the island's leader. * @deprecated Not supported anymore. */ @Nullable @Deprecated default Island getIslandByLeader(UUID uuid) { return SuperiorSkyblockAPI.getGrid().getIsland(uuid); } /** * Get an island by its position in the top-islands. * * @param position The position of the island. * @param sortingType The sorting-type to get islands from. */ @Nullable Island getIslandAtPosition(int position, SortingType sortingType); /** * Get the position of an island in the top-islands. * * @param island The island to get position of. * @param sortingType The sorting-type to get islands from. */ int getIslandPosition(Island island, SortingType sortingType); /** * Get the amount of islands on the server. */ int getIslandsAmount(); /** * Get an island at a location. * * @param location The location to get island in. */ @Nullable Island getIslandAt(Location location); /** * Transfer an island from a player to another one. * Warning: If you don't know what you're doing, do not use this method. * Instead, use {@link Island#transferIsland(SuperiorPlayer)}. * * @param oldLeader The uuid of the current leader. * @param newLeader The uuid of the new leader. * @deprecated Not supported anymore. */ @Deprecated default void transferIsland(UUID oldLeader, UUID newLeader) { } /** * Sort islands for the top-islands. * The islands will not get sorted if only one island exists, or no changes * were tracked by {@link #notifyChange(SortingType, Island)} * * @param sortingType The type of sorting to use. * @param onFinish Callback method */ void sortIslands(SortingType sortingType, @Nullable Runnable onFinish); /** * Sort islands for the top-islands. * * @param sortingType The type of sorting to use. * @param forceSort Whether to force-sort the islands. * When true, islands will get sorted even if only one island exists. * @param onFinish Callback method */ void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Runnable onFinish); /** * Notify about a change of a value for a specific sorting type for an island. * * @param sortingType The sorting-type. * @param island The island that had its value changed. */ void notifyChange(SortingType sortingType, Island island); /** * Get all islands sorted by a specific sorting-type. * * @param sortingType The type of sorting to use. */ List getSortedIslands(SortingType sortingType); /** * Get all islands. */ List getIslandsUnsorted(); /** * Add a new sorting-type. * * @param sortingType The sorting-type to add. * @param sort Whether to sort the islands or not when the sorting-type is added. */ void addSortingType(SortingType sortingType, boolean sort); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java ================================================ package com.bgsoftware.superiorskyblock.api.island.warps; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; public class DelegateIslandWarp implements IslandWarp { protected final IslandWarp handle; protected DelegateIslandWarp(IslandWarp handle) { this.handle = handle; } @Override public Island getIsland() { return this.handle.getIsland(); } @Override public String getName() { return this.handle.getName(); } @Override public void setName(String name) { this.handle.setName(name); } @Override public Location getLocation() { return this.handle.getLocation(); } @Override public Location getLocation(Location location) { return this.handle.getLocation(location); } @Override public void setLocation(Location location) { this.handle.setLocation(location); } @Override public WorldPosition getPosition() { return this.handle.getPosition(); } @Override public Dimension getPositionDimension() { return this.handle.getPositionDimension(); } @Override public void setPosition(Dimension dimension, WorldPosition worldPosition) { this.handle.setPosition(dimension, worldPosition); } @Override public boolean hasPrivateFlag() { return this.handle.hasPrivateFlag(); } @Override public void setPrivateFlag(boolean privateFlag) { this.handle.setPrivateFlag(privateFlag); } @Nullable @Override public ItemStack getRawIcon() { return this.handle.getRawIcon(); } @Nullable @Override public ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer) { return this.handle.getIcon(superiorPlayer); } @Override public void setIcon(@Nullable ItemStack icon) { this.handle.setIcon(icon); } @Override public WarpCategory getCategory() { return this.handle.getCategory(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateWarpCategory.java ================================================ package com.bgsoftware.superiorskyblock.api.island.warps; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.inventory.ItemStack; import java.util.List; public class DelegateWarpCategory implements WarpCategory { protected final WarpCategory handle; protected DelegateWarpCategory(WarpCategory handle) { this.handle = handle; } @Override public Island getIsland() { return this.handle.getIsland(); } @Override public String getName() { return this.handle.getName(); } @Override public void setName(String name) { this.handle.setName(name); } @Override public List getWarps() { return this.handle.getWarps(); } @Override public int getSlot() { return this.handle.getSlot(); } @Override public void setSlot(int slot) { this.handle.setSlot(slot); } @Override public ItemStack getRawIcon() { return this.handle.getRawIcon(); } @Override public ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer) { return this.handle.getIcon(superiorPlayer); } @Override public void setIcon(@Nullable ItemStack icon) { this.handle.setIcon(icon); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java ================================================ package com.bgsoftware.superiorskyblock.api.island.warps; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; public interface IslandWarp { /** * Get the island of this warp. */ Island getIsland(); /** * Get the name of the warp. */ String getName(); /** * Set the name of the warp. * Do not call this method - use Island#renameWarp instead! * * @param name The new name to set. */ void setName(String name); /** * Get the location of the warp. */ Location getLocation(); /** * Get the location of the warp. * * @param location Location object to re-use. */ @Nullable Location getLocation(@Nullable Location location); /** * Set the location of the warp. * * @param location The new location to set. */ void setLocation(Location location); /** * Get the position of the warp. */ WorldPosition getPosition(); /** * Get the dimension of the position of the warp. */ Dimension getPositionDimension(); /** * Set the position of the warp. * * @param dimension The dimension of the new position to set. * @param worldPosition The new position to set. */ void setPosition(Dimension dimension, WorldPosition worldPosition); /** * Check if the warp is private or public to visitors. */ boolean hasPrivateFlag(); /** * Set the private flag of the island warp. * * @param privateFlag The flag to set. */ void setPrivateFlag(boolean privateFlag); /** * Get the icon of the warp. * May be null if the warp has no special icon. */ @Nullable ItemStack getRawIcon(); /** * Get the icon of the warp after all placeholders are parsed. * May be null if the warp has no special icon. * * @param superiorPlayer The player to parse the placeholders for */ @Nullable ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer); /** * Set the icon of the warp. * May be null if the warp should have no special icon. * * @param icon The icon to set. */ void setIcon(@Nullable ItemStack icon); /** * Get the category of the warp. */ WarpCategory getCategory(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/WarpCategory.java ================================================ package com.bgsoftware.superiorskyblock.api.island.warps; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.inventory.ItemStack; import java.util.List; public interface WarpCategory { /** * Get the island of this category. */ Island getIsland(); /** * Get the name of the warp category. */ String getName(); /** * Set a new name to the category. * Do not call this method - use Island#renameCategory instead! * * @param name The new name to set. */ void setName(String name); /** * Get all the warps of this category. */ List getWarps(); /** * Get the slot of the category. */ int getSlot(); /** * Set the slot of the category. * * @param slot The slot to set. */ void setSlot(int slot); /** * Get the icon of the category. */ ItemStack getRawIcon(); /** * Get the icon of the category after all placeholders are parsed. * * @param superiorPlayer The player to parse the placeholders for */ ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer); /** * Set the icon of the category. * * @param icon The icon to set. If null, default icon will be set. */ void setIcon(@Nullable ItemStack icon); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/key/CustomKeyParser.java ================================================ package com.bgsoftware.superiorskyblock.api.key; import com.bgsoftware.common.annotations.Nullable; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; public interface CustomKeyParser { /** * Get a custom key for a block. * Please note: this method should support async calls. * * @param location The location of the block. */ @Nullable default Key getCustomKey(Location location) { return null; } /** * Get a custom key for an entity. * Please note: this method should support async calls. * * @param entity The entity to check. */ @Nullable default Key getCustomKey(Entity entity) { return null; } /** * Get a custom key for an item-stack. * Please note: this method should support async calls. * * @param itemStack The item-stack to parse. * @param def The original key of the item. */ default Key getCustomKey(ItemStack itemStack, Key def) { return def; } /** * Check if a key was created by this parser. * * @param key The key to check. */ boolean isCustomKey(Key key); /** * Get the custom item of the custom key. * The provided key is guaranteed to pass the {@link #isCustomKey(Key)} check. * * @param key The key to get the custom item for. * @return The item stack for that custom key, or null for using the default one. */ @Nullable default ItemStack getCustomKeyItem(Key key) { return null; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/key/Key.java ================================================ package com.bgsoftware.superiorskyblock.api.key; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; /** * Used as a wrapper for objects into material & data object. */ public interface Key extends Comparable { /** * Get the key of an entity type. * * @param entityType The entity type to create key for. */ static Key of(EntityType entityType) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(entityType); } /** * Get the key of an entity type. * * @param entityTypeName The name of the entity type to create key for. */ static Key ofEntityType(String entityTypeName) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getEntityTypeKey(entityTypeName); } /** * Get the key of an entity. * * @param entity The entity to check. */ static Key of(Entity entity) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(entity); } /** * Get the key of a block. * * @param block The block to create key for. */ static Key of(Block block) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(block); } /** * Get the key of a block-state. * * @param blockState The block-state to create key for. */ static Key of(BlockState blockState) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(blockState); } /** * Get the key of an item-stack. * * @param itemStack The item-stack to create key for. */ static Key of(ItemStack itemStack) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(itemStack); } /** * Get the key of a material and data. * * @param material The material to create key for. * @param data The data to create key for. */ static Key of(Material material, short data) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(material, data); } /** * Get the key of a material. * * @param material The material to create key for. */ static Key of(Material material) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(material); } /** * Get the key of a material and data. * * @param type The combined material-data pair to create key for. */ static Key ofMaterialAndData(String type) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getMaterialAndDataKey(type); } /** * Get the key of a spawner block with specific entity type. * * @param entityType The entity type of the spawner to create key for. */ static Key ofSpawner(EntityType entityType) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getSpawnerKey(entityType); } /** * Get the key of a spawner block with specific entity type. * * @param entityTypeName The name of the entity type of the spawner to create key for. */ static Key ofSpawner(String entityTypeName) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getSpawnerKey(entityTypeName); } /** * Get the key of a global-key and a sub-key. * It is recommended to use the other Key#of methods whenever possible, and only use this one * for custom keys that has no Key#of methods. * * @param globalKey The global key * @param subKey The sub key */ static Key of(String globalKey, String subKey) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(globalKey, subKey); } /** * Get the key of a string. * It is recommended to use the other Key#of methods whenever possible, and only use this one * for custom keys that has no Key#of methods. * * @param key The string to check. */ static Key of(String key) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().getKey(key); } /** * Get the global key of this key instance. */ String getGlobalKey(); /** * Get the sub key of this key instance. */ String getSubKey(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/key/KeyMap.java ================================================ package com.bgsoftware.superiorskyblock.api.key; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collector; import java.util.stream.Collectors; /** * {@link Map} implementation for handling keys. * The difference between this map and a regular {@link Map} is that this map handles checks for * global keys as well as individual ones. *

* For example, if this map has "STONE" as a key inside it, the {@link #get(Object)} method will return the value * of that key when "STONE" is provided, as well as any other key with a different sub-key ("STONE:0", for example). *

* However, if this set has "STONE:0" as a key, as well as the global key inside it, the {@link #get(Object)} method * will return the value of the exact same key and not its global key (Therefore, the value of "STONE:0" will be * returned if "STONE:0" is provided, and the value of "STONE" will be provided if "STONE:1" is provided) */ public interface KeyMap extends Map { /** * Create a new empty {@link KeyMap} instance. * * @param mapCreator The map creator for the inner-map of the new {@link KeyMap} */ static KeyMap createKeyMap(Supplier> mapCreator) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeyMap(mapCreator); } /** * Create a new empty {@link KeyMap} instance based on {@link HashMap}. */ static KeyMap createKeyMap() { return createKeyMap(() -> new HashMap<>()); } /** * Create a new {@link KeyMap} instance from the given map based on {@link HashMap}. * If the provided map is also a {@link KeyMap}, the exact same instance of that map is returned. * Otherwise, the returned {@link KeyMap} is a copy of that map. * * @param map The map to create {@link KeySet} from. */ static KeyMap createKeyMap(Map map) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeyMap(() -> new HashMap<>(), map); } /** * Create a new empty {@link KeyMap} instance based on {@link ConcurrentHashMap}. */ static KeyMap createConcurrentKeyMap() { return createKeyMap(() -> new ConcurrentHashMap<>()); } /** * Create a new {@link KeyMap} instance from the given map based on {@link ConcurrentHashMap}. * If the provided map is also a {@link KeyMap}, the exact same instance of that map is returned. * Otherwise, the returned {@link KeyMap} is a copy of that map. * * @param map The map to create {@link KeySet} from. */ static KeyMap createConcurrentKeyMap(Map map) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeyMap(() -> new ConcurrentHashMap<>(), map); } /** * Create a collector for {@link KeyMap} that can be used in streams. * * @param keyMapper The key mapper to apply. * @param valueMapper The values mapper to apply. * @param mapCreator The map creator for the inner-map of the new {@link KeyMap} */ static Collector> getCollector(Function keyMapper, Function valueMapper, Supplier> mapCreator) { return Collectors.toMap(keyMapper, valueMapper, (v1, v2) -> { throw new IllegalStateException(String.format("Duplicate key %s", v1)); }, () -> createKeyMap(mapCreator)); } /** * Create a collector for {@link KeyMap} based on {@link HashMap} that can be used in streams * * @param keyMapper The key mapper to apply. * @param valueMapper The values mapper to apply. */ static Collector> getCollector(Function keyMapper, Function valueMapper) { return Collectors.toMap(keyMapper, valueMapper, (v1, v2) -> { throw new IllegalStateException(String.format("Duplicate key %s", v1)); }, KeyMap::createKeyMap); } /** * Get the key that is similar to the provided key. * For example, if {@param original} is "STONE:0", and the map contains only "STONE", "STONE" will be returned. * However, if the map contains "STONE" as well as "STONE:0", "STONE:0" will be returned. * If the key is not inside the map, null will be returned. * * @param original The original key. */ @Nullable Key getKey(Key original); /** * Get the key that is similar to the provided key. * For example, if {@param original} is "STONE:0", and the map contains only "STONE", "STONE" will be returned. * However, if the map contains "STONE" as well as "STONE:0", "STONE:0" will be returned. * If the key is not inside the map, {@param def} will be returned. * * @param original The original key. * @param def Default key to be returned if {@param original} is not in the map. */ Key getKey(Key original, @Nullable Key def); /** * Get a value from the key without checking for global keys or other similar keys. * This means that if the map doesn't contain {@param key}, {@param def} will be returned. * This is a similar behavior to a regular {@link Map} * * @param key The key to check * @param def The default value to return. */ V getRaw(Key key, V def); /** * See {@link java.util.Collection#removeIf(Predicate)} */ boolean removeIf(Predicate predicate); /** * Return a regular {@link java.util.HashMap} with the keys and values of this map. */ Map asMap(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/key/KeySet.java ================================================ package com.bgsoftware.superiorskyblock.api.key; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.function.Supplier; /** * {@link Set} implementation for handling keys. * The difference between this set and a regular {@link Set} is that this set handles checks for * global keys as well as individual ones. *

* For example, if this set has "STONE" as a key inside it, the {@link #contains(Object)} method will return true * if "STONE" is provided, as well as any other key with a different sub-key ("STONE:0", for example). *

* However, if this set only has "STONE:0" as a key inside it, the {@link #contains(Object)} method will only return * true for the exact same keys (Therefore, "STONE" will return false alongside of any other key with a different * sub-key) */ public interface KeySet extends Set { /** * Create a new empty {@link KeySet} instance. * * @param setCreator The set creator for the inner-set of the new {@link KeySet} */ static KeySet createKeySet(Supplier> setCreator) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeySet(setCreator); } /** * Create a new empty {@link KeySet} instance based on {@link HashSet} */ static KeySet createKeySet() { return createKeySet(HashSet::new); } /** * Create a new {@link KeySet} instance from the given collection based on {@link HashSet}. * If the provided collection is also a {@link KeySet}, the exact same instance of that set is returned. * Otherwise, the returned {@link KeySet} is a copy of that collection. * * @param collection The collection to create {@link KeySet} from. */ static KeySet createKeySet(Collection collection) { return SuperiorSkyblockAPI.getSuperiorSkyblock().getKeys().createKeySet(HashSet::new, collection); } /** * Get the key that is similar to the provided key. * For example, if {@param original} is "STONE:0", and the set contains only "STONE", "STONE" will be returned. * However, if the set contains "STONE" as well as "STONE:0", "STONE:0" will be returned. * If the key is not inside the map, null will be returned. * * @param original The original key. */ @Nullable Key getKey(Key original); /** * Get the key that is similar to the provided key. * For example, if {@param original} is "STONE:0", and the set contains only "STONE", "STONE" will be returned. * However, if the set contains "STONE" as well as "STONE:0", "STONE:0" will be returned. * If the key is not inside the map, {@param def} will be returned. * * @param original The original key. * @param def Default key to be returned if {@param original} is not in the map. */ Key getKey(Key original, Key def); /** * Return a regular {@link java.util.HashSet} with the keys of this set. */ Set asSet(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/BaseMenu.java ================================================ package com.bgsoftware.superiorskyblock.api.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Predicate; /** * Basic implementation of a menu for easily creating new ones with the API. * If you want a {@link PagedMenu}, extend this class and implement the {@link PagedMenu} interface. * Make sure you use {@link #addView(MenuView)} and {@link #removeView(MenuView)} when creating and deleting views. */ public abstract class BaseMenu, A extends ViewArgs> implements Menu { protected final List openedMenuViews = new LinkedList<>(); protected final String identifier; protected final MenuLayout menuLayout; @Nullable protected final GameSound openingSound; protected final boolean isPreviousMoveAllowed; protected final boolean isSkipOneItem; protected BaseMenu(String identifier, MenuLayout menuLayout, @Nullable GameSound openingSound, boolean isPreviousMoveAllowed, boolean isSkipOneItem) { Preconditions.checkNotNull(identifier, "identifier parameter cannot be null."); Preconditions.checkNotNull(menuLayout, "menuLayout parameter cannot be null."); this.identifier = identifier; this.menuLayout = menuLayout; this.openingSound = openingSound; this.isPreviousMoveAllowed = isPreviousMoveAllowed; this.isSkipOneItem = isSkipOneItem; } @Override public String getIdentifier() { return this.identifier; } @Override public MenuLayout getLayout() { return this.menuLayout; } @Override @Nullable public GameSound getOpeningSound() { return this.openingSound; } @Override public boolean isPreviousMoveAllowed() { return this.isPreviousMoveAllowed; } @Override public boolean isSkipOneItem() { return this.isSkipOneItem || SuperiorSkyblockAPI.getSettings().isSkipOneItemMenus(); } @Override public CompletableFuture createView(SuperiorPlayer superiorPlayer, A args) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(args, "args parameter cannot be null."); Preconditions.checkState(superiorPlayer.isOnline(), "Cannot create view for offline player: " + superiorPlayer.getName()); return this.createView(superiorPlayer, args, superiorPlayer.getOpenedView()); } @Override public abstract CompletableFuture createView(SuperiorPlayer superiorPlayer, A args, @Nullable MenuView previousMenu); @Override public void refreshViews() { synchronized (openedMenuViews) { openedMenuViews.forEach(V::refreshView); } } @Override public void refreshViews(Predicate viewFilter) { filterViews(viewFilter, V::refreshView); } @Override public void closeViews() { synchronized (openedMenuViews) { openedMenuViews.forEach(V::closeView); } } @Override public void closeViews(Predicate viewFilter) { filterViews(viewFilter, V::closeView); } public void addView(V view) { synchronized (openedMenuViews) { openedMenuViews.add(view); } } public void removeView(V view) { synchronized (openedMenuViews) { openedMenuViews.remove(view); } } protected final void filterViews(Predicate viewFilter, Consumer onMatch) { synchronized (openedMenuViews) { openedMenuViews.forEach(view -> { if (viewFilter.test(view)) onMatch.accept(view); }); } } @Override public void onClick(InventoryClickEvent clickEvent, V menuView) { if (clickEvent.getCurrentItem() == null) return; Preconditions.checkNotNull(this.menuLayout, "menu wasn't initialized properly."); MenuViewButton menuButton = this.menuLayout.getButton(clickEvent.getRawSlot()).createViewButton(menuView); String requiredPermission = menuButton.getTemplate().getRequiredPermission(); if (requiredPermission != null && !menuView.getInventoryViewer().hasPermission(requiredPermission)) { onButtonClickLackPermission(menuButton, clickEvent); return; } Player player = (Player) clickEvent.getWhoClicked(); GameSound clickSound = menuButton.getTemplate().getClickSound(); if (clickSound != null) player.playSound(player.getLocation(), clickSound.getSound(), clickSound.getVolume(), clickSound.getPitch()); menuButton.getTemplate().getClickCommands().forEach(command -> MenuCommands.getInstance().runCommand(menuView, command, clickEvent)); if (onPreButtonClick(menuButton, clickEvent)) menuButton.onButtonClick(clickEvent); } @Override public final void onClose(InventoryCloseEvent closeEvent, V menuView) { removeView(menuView); this.onCloseInternal(closeEvent, menuView); } protected abstract boolean onPreButtonClick(MenuViewButton menuButton, InventoryClickEvent clickEvent); protected abstract void onButtonClickLackPermission(MenuViewButton menuButton, InventoryClickEvent clickEvent); protected abstract void onCloseInternal(InventoryCloseEvent closeEvent, V menuView); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/ISuperiorMenu.java ================================================ package com.bgsoftware.superiorskyblock.api.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; /** * @deprecated See {@link MenuView} */ @Deprecated public interface ISuperiorMenu extends MenuView { /** * Clone and open this menu to the {@link #getInventoryViewer()} * * @param previousMenu The previous menu to set. */ void cloneAndOpen(@Nullable ISuperiorMenu previousMenu); /** * Get the previous menu of this menu. */ @Nullable ISuperiorMenu getPreviousMenu(); /** * Helper method to cast the new {@link MenuView} object to the old {@link ISuperiorMenu} object. */ @Deprecated static ISuperiorMenu convertFromView(MenuView menuView) { return SuperiorSkyblockAPI.getMenus().getOldMenuFromView(menuView); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/Menu.java ================================================ package com.bgsoftware.superiorskyblock.api.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.handlers.MenusManager; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; /** * Represents a menu of the plugin. * You can get an instance of a menu by its identifier using {@link MenusManager#getMenu(String)} * The instances of the menus are singleton, and there will be only one instance of each menu per session. */ public interface Menu, A extends ViewArgs> { /** * Get the identifier of the menu. */ String getIdentifier(); /** * Get the layout of the menu. */ MenuLayout getLayout(); /** * Get the sound to play when opening the menu. */ @Nullable GameSound getOpeningSound(); /** * Get whether it is possible to open the previous opened menu after closing this one. */ boolean isPreviousMoveAllowed(); /** * Get whether this menu should be skipped when it only contains one item. * This is only useful for menus that have their buttons open other menus. */ boolean isSkipOneItem(); /** * Create a new menu view for a player. * If the player already has a view opened, make sure you call {@link MenuView#setPreviousMove(boolean)} on * the opened view and pass 'false' as an argument, otherwise unexpected behavior may occur. * * @param superiorPlayer The player to open the menu for. * @param args The arguments for the linked {@link V} menu view. */ CompletableFuture createView(SuperiorPlayer superiorPlayer, A args); /** * Create a new menu view for a player. * If the player already has a view opened, make sure you call {@link MenuView#setPreviousMove(boolean)} on * the opened view and pass 'false' as an argument, otherwise unexpected behavior may occur. * * @param superiorPlayer The player to open the menu for. * @param args The arguments for the linked {@link V} menu view. * @param previousMenu The previous menu to use. In most cases, this will be null. */ CompletableFuture createView(SuperiorPlayer superiorPlayer, A args, @Nullable MenuView previousMenu); void refreshViews(); void refreshViews(Predicate viewFilter); void closeViews(); void closeViews(Predicate viewFilter); /** * Callback method for when a player clicks on a button in a view of this menu. * This method should do necessary checks, and finally call {@link MenuViewButton#onButtonClick(InventoryClickEvent)} * on the button that was clicked (can be retrieved by using {@link InventoryClickEvent#getRawSlot()} as a slot * passed to {@link MenuLayout#getButton(int)}) * * @param clickEvent The event associated with the click. * @param menuView The menu view that was clicked. */ void onClick(InventoryClickEvent clickEvent, V menuView); /** * Callback method for when a player closes a view of this menu. * The method has no limits on what can be done inside it, and it depends on your custom {@link V} implementation * of what to do inside it. * * @param closeEvent The associated event. * @param menuView The menu view that was closed. */ void onClose(InventoryCloseEvent closeEvent, V menuView); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/MenuCommands.java ================================================ package com.bgsoftware.superiorskyblock.api.menu; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import org.bukkit.event.inventory.InventoryClickEvent; /** * Singleton class used to parse and execute commands from menus. * You can get the instance of this executor by calling {@link #getInstance()} */ public interface MenuCommands { void runCommand(MenuView menuView, String command, InventoryClickEvent clickEvent); static MenuCommands getInstance() { return SuperiorSkyblockAPI.getMenus().getMenuCommands(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/MenuIslandCreationConfig.java ================================================ package com.bgsoftware.superiorskyblock.api.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import org.bukkit.block.Biome; import java.math.BigDecimal; import java.util.Collection; /** * Configuration for creation of new islands. * The values from this configuration are used in {@link GridManager#createIsland} */ public interface MenuIslandCreationConfig { /** * Get the schematic that will be used to create the island. */ Schematic getSchematic(); /** * Get the sound to play when the island is successfully created. */ @Nullable GameSound getSound(); /** * Get the commands to execute when island is successfully created. */ Collection getCommands(); /** * Get whether the island-values (worth & level) should be offset to 0 when the island is created. */ boolean shouldOffsetIslandValue(); /** * Custom worth bonus when the island is created. */ BigDecimal getBonusWorth(); /** * Custom level bonus when the island is created. */ BigDecimal getBonusLevel(); /** * Get the spawn offset of the island's home location from where the schematic was placed. */ @Nullable BlockOffset getSpawnOffset(); /** * Get the biome to set to the new island. */ Biome getBiome(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/PagedMenu.java ================================================ package com.bgsoftware.superiorskyblock.api.menu; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; /** * Similar to {@link Menu}, but used for describing page-based menus. * See {@link Menu} */ public interface PagedMenu, A extends ViewArgs, E> extends Menu { } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/MenuTemplateButton.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.button; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import org.bukkit.inventory.ItemStack; import java.util.List; /** * The template button class is used to store data about the button. * For example, the item to display, the sounds and other data of the button, etc. */ public interface MenuTemplateButton> { /** * Get the item to display in the menu. * The returned item has no changes to it (placeholders are unparsed, for example). * This item is later used in {@link MenuViewButton#createViewItem()} */ @Nullable ItemStack getButtonItem(); /** * Get the sound to play when clicking the button. */ @Nullable GameSound getClickSound(); /** * Get the commands to run when clicking the button. */ List getClickCommands(); /** * Get the required permission for clicking the button. */ @Nullable String getRequiredPermission(); /** * Get the sound to play when clicking the button without having {@link #getRequiredPermission()} permission. */ @Nullable GameSound getLackPermissionSound(); /** * Get the class type of view buttons created using {@link #createViewButton(MenuView)} */ Class getViewButtonType(); /** * Create a view-button object to be used by the provided menu view. * Unlike the template button, the view button handles the logic for buttons within the view. * * @param menuView The view to create the button for. */ MenuViewButton createViewButton(V menuView); /** * Create a new {@link Builder} object for a new {@link MenuTemplateButton}. * * @param viewButtonCreator The creator used to create a view-button by the builder. * You will probably want to implement your own {@link MenuViewButton} which will be * returned by this creator. */ static > Builder newBuilder(Class viewButtonType, MenuViewButtonCreator viewButtonCreator) { return SuperiorSkyblockAPI.getMenus().createButtonBuilder(viewButtonType, viewButtonCreator); } interface Builder> { /** * Set the item to display in the menu. * * @param buttonItem The item. */ Builder setButtonItem(@Nullable ItemStack buttonItem); /** * Set the sound to play when clicking the button. * * @param clickSound The sound to play. */ Builder setClickSound(@Nullable GameSound clickSound); /** * Set the commands to run when clicking the button. * * @param commands The commands to run. */ Builder setClickCommands(@Nullable List commands); /** * Set the required permission for clicking the button. * * @param requiredPermission The required permission for using the button. */ Builder setRequiredPermission(@Nullable String requiredPermission); /** * Set the sound to play when clicking the button without having {@link #getRequiredPermission()} permission. * * @param lackPermissionSound The sound to play. */ Builder setLackPermissionsSound(@Nullable GameSound lackPermissionSound); /** * Get the {@link MenuTemplateButton} from this builder. */ MenuTemplateButton build(); } interface MenuViewButtonCreator> { /** * Create a new {@link MenuViewButton}. * You will probably want to implement your own {@link MenuViewButton} which will be * returned by this creator. */ MenuViewButton create(MenuTemplateButton templateButton, V menuView); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/MenuViewButton.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.button; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton.MenuViewButtonCreator; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; /** * The {@link MenuViewButton} is used to run custom logic for buttons inside menu views. * You will want to implement this interface with your own custom logic, and then later use your custom * view button with the {@link MenuViewButtonCreator}. */ public interface MenuViewButton> { /** * Get the template that was used to create this view button. */ MenuTemplateButton getTemplate(); /** * Get the view that this button is used in. */ V getView(); /** * Create a new view item for this button. * This should use {@link MenuTemplateButton#getButtonItem()} */ ItemStack createViewItem(); /** * Method callback when clicking this button. * The event passed as an argument is already cancelled. * * @param clickEvent The click event. */ void onButtonClick(InventoryClickEvent clickEvent); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/PagedMenuTemplateButton.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.button; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import org.bukkit.inventory.ItemStack; /** * Similar to {@link MenuTemplateButton}, but used for buttons in page-based menus. * See {@link MenuTemplateButton} */ public interface PagedMenuTemplateButton, E> extends MenuTemplateButton { /** * Get the item to display inside the menu for items that don't have a valid paged-object. * For example, inside the top-islands menu, this will return the question-mark head (by default). * In most cases, this will return null. */ @Nullable ItemStack getNullItem(); /** * Get the index within the menu of this paged object button. */ int getButtonIndex(); /** * Sets the index within the menu of this paged object button. * * @param buttonIndex The new index to set. */ void setButtonIndex(int buttonIndex); /** * Create a view-button object to be used by the provided menu view. * Unlike the template button, the view button handles the logic for buttons within the view. * * @param menuView The view to create the button for. */ @Override PagedMenuViewButton createViewButton(V menuView); /** * Create a new {@link Builder} object for a new {@link PagedMenuTemplateButton}. * * @param viewButtonCreator The creator used to create a view-button by the builder. * You will probably want to implement your own {@link PagedMenuViewButton} which will be * returned by this creator. */ static , E> Builder newBuilder(Class viewButtonType, PagedMenuViewButtonCreator viewButtonCreator) { return SuperiorSkyblockAPI.getMenus().createPagedButtonBuilder(viewButtonType, viewButtonCreator); } interface Builder, E> extends MenuTemplateButton.Builder { /** * Set the item to display inside the menu for items that don't have a valid paged-object. * * @param nullItem The item to set. */ Builder setNullItem(ItemStack nullItem); /** * Get the {@link PagedMenuTemplateButton} from this builder. */ PagedMenuTemplateButton build(); } interface PagedMenuViewButtonCreator, E> { /** * Create a new {@link PagedMenuViewButton}. * You will probably want to implement your own {@link PagedMenuViewButton} which will be * returned by this creator. */ PagedMenuViewButton create(PagedMenuTemplateButton templateButton, V menuView); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/PagedMenuViewButton.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.button; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import org.bukkit.inventory.ItemStack; public interface PagedMenuViewButton, E> extends MenuViewButton { /** * Set the paged object for this view button. * * @param pagedObject The object to set. */ void updateObject(E pagedObject); /** * Get the paged object for this view button. */ E getPagedObject(); /** * Modify the button item for this view button. * This is used for parsing additional placeholders for the {@link #getPagedObject()}. * * @param buttonItem The original item, created by {@link PagedMenuTemplateButton#createViewButton(MenuView)} */ ItemStack modifyViewItem(ItemStack buttonItem); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/layout/MenuLayout.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.layout; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import java.util.Collection; import java.util.List; /** * The layout class is used to describe the layout of buttons for a menu. * It is later used by the plugin to create a new inventory for the menu. */ public interface MenuLayout> { /** * Get a button by a slot. * * @param slot The slot to get a button from. * @return The button in this slot. * If no button was explicitly set by the builder, a dummy button will be return. */ MenuTemplateButton getButton(int slot); /** * Get all the buttons in the layout. */ Collection> getButtons(); /** * Get the amount of rows for the layout. */ int getRowsCount(); /** * Create a new inventory from this layout. * * @param menuView The view to create the inventory for. */ Inventory buildInventory(V menuView); /** * Create a new {@link Builder} object for a new {@link MenuLayout}. */ static > Builder newBuilder() { return SuperiorSkyblockAPI.getMenus().createPatternBuilder(); } interface Builder> { /** * Set a title for menu views created by this layout. * * @param title The title to set. */ Builder setTitle(String title); /** * Set the inventory type for menu views created by this layout. * * @param inventoryType The inventory type to set. */ Builder setInventoryType(InventoryType inventoryType); /** * Set the rows count for menu views created by this layout. * * @param rowsCount The amount of rows to set. */ Builder setRowsCount(int rowsCount); /** * Set a button in a slot for this layout. * * @param slot The slot to set the button. * @param button The button to set. */ Builder setButton(int slot, MenuTemplateButton button); /** * Fill this layout with the given buttons. * * @param buttons The buttons to fill this layout with. */ Builder setButtons(MenuTemplateButton[] buttons); /** * Set a button in slots for this layout. * * @param slots The slot to set the button. * @param buttonBuilder The builder of the button to set. */ Builder setButtons(List slots, MenuTemplateButton buttonBuilder); /** * Map the button in the given slot to the provided button builder. * This will set the slot with the provided button type with the data of the current button. * If no button exists for this slot, this will be the same as {@link #setButton(int, MenuTemplateButton)} * * @param slot The slot to set the button. * @param buttonBuilder The builder of the button to map. */ Builder mapButton(int slot, MenuTemplateButton.Builder buttonBuilder); /** * Map the button in the given slots to the provided button builder. * This will set the slots with the provided button type with the data of the current buttons. * If no buttons exist for the slots, this will be the same as {@link #setButtons(List, MenuTemplateButton)} * * @param slots The slots to set the button. * @param buttonBuilder The builder of the button to map. */ Builder mapButtons(List slots, MenuTemplateButton.Builder buttonBuilder); /** * Get the {@link MenuLayout} from this builder. */ MenuLayout build(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/layout/PagedMenuLayout.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.layout; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import java.util.List; /** * Similar to {@link MenuLayout}, but used for layout of page-based menus. * See {@link MenuLayout} */ public interface PagedMenuLayout> extends MenuLayout { /** * Get the amount of paged objects in the layout. */ int getObjectsPerPageCount(); /** * Create a new {@link Builder} object for a new {@link PagedMenuLayout}. */ static , E> Builder newBuilder() { return SuperiorSkyblockAPI.getMenus().createPagedPatternBuilder(); } interface Builder, E> extends MenuLayout.Builder { /** * Set the previous-page button slots for this layout. * * @param slots The slots to set. */ Builder setPreviousPageSlots(List slots); /** * Set the next-page button slots for this layout. * * @param slots The slots to set. */ Builder setNextPageSlots(List slots); /** * Set the current-page display button slots for this layout. * * @param slots The slots to set. */ Builder setCurrentPageSlots(List slots); /** * Set the page-object button slots for this layout. * * @param slots The slots to set. * @param buttonBuilder The builder used for the paged-object. */ Builder setPagedObjectSlots(List slots, PagedMenuTemplateButton.Builder buttonBuilder); /** * Set a custom order for the paged objects for this layout. * * @param slotsOrder The correct order of the slots */ Builder setCustomLayoutOrder(List slotsOrder); /** * Get the {@link PagedMenuLayout} from this builder. */ @Override PagedMenuLayout build(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/parser/MenuParseException.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.parser; import org.bukkit.configuration.file.YamlConfiguration; /** * In case when calling {@link MenuParser#parseMenu(YamlConfiguration)} and it failed to parse the menu, * this exception will be thrown with an appropriate message. */ public class MenuParseException extends Exception { public MenuParseException(String message) { super(message); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/parser/MenuParser.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.parser; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import org.bukkit.configuration.file.YamlConfiguration; import java.util.List; /** * Singleton class used to parse menus out of files. * You can get the instance of this parser by calling {@link #getInstance()} */ public interface MenuParser { /** * Parse a menu out of the provided config file. * * @param callerName The caller's name. * Used to log warnings when parsing the menu that were not critical. * @param config The config to load the menu from. * @throws MenuParseException In case an error occurred while parsing the menu. */ > ParseResult parseMenu(String callerName, YamlConfiguration config) throws MenuParseException; /** * Parse a paged menu out of the provided config file. * * @param callerName The caller's name. * Used to log warnings when parsing the menu that were not critical. * @param config The config to load the menu from. * @param pagedButtonBuilder The builder to use to build the paged objects for the menu. * @throws MenuParseException In case an error occurred while parsing the menu. */ , E> ParseResult parseMenu( String callerName, YamlConfiguration config, PagedMenuTemplateButton.Builder pagedButtonBuilder) throws MenuParseException; /** * Get the instance of the parser. */ static MenuParser getInstance() { return SuperiorSkyblockAPI.getMenus().getParser(); } /** * Represents the result of the parsing. */ interface ParseResult> { /** * Get the layout builder used by the parser. */ MenuLayout.Builder getLayoutBuilder(); /** * Get the opening sound to play. */ @Nullable GameSound getOpeningSound(); /** * Get whether it is possible to open the previous opened menu after closing the current one. */ boolean isPreviousMoveAllowed(); /** * Get whether this menu should be skipped when it only contains one item. * This is only useful for menus that have their buttons open other menus. */ boolean isSkipOneItem(); /** * Get the slots in the layout for a char. * * @param ch The char to get slots for. */ List getSlotsForChar(char ch); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/BaseMenuView.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.inventory.Inventory; public abstract class BaseMenuView, A extends ViewArgs> implements MenuView { protected final SuperiorPlayer inventoryViewer; protected final Menu menu; @Nullable protected MenuView previousMenuView; protected boolean previousMove = true; protected BaseMenuView(SuperiorPlayer inventoryViewer, Menu menu, @Nullable MenuView previousMenuView) { this.inventoryViewer = inventoryViewer; this.menu = menu; this.previousMenuView = previousMenuView; } @Override public SuperiorPlayer getInventoryViewer() { return this.inventoryViewer; } @Override public Menu getMenu() { return this.menu; } @Nullable @Override public MenuView getPreviousMenuView() { return this.previousMenuView; } @Override public void setPreviousMenuView(@Nullable MenuView previousMenuView, boolean keepOlderViews) { MenuView oldPreviousMenuView = this.previousMenuView; this.previousMenuView = previousMenuView; if (keepOlderViews && oldPreviousMenuView != null && previousMenuView != null) previousMenuView.setPreviousMenuView(oldPreviousMenuView.getPreviousMenuView(), false); } @Override public void setPreviousMove(boolean previousMove) { this.previousMove = previousMove; } @Override public boolean isPreviousMenu() { return this.previousMove; } @Override public abstract void refreshView(); @Override public abstract void closeView(); @Override public abstract Inventory getInventory(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/BasePagedMenuView.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import java.util.List; public abstract class BasePagedMenuView, A extends ViewArgs, E> extends BaseMenuView implements PagedMenuView { protected int currentPage = 1; protected BasePagedMenuView(SuperiorPlayer inventoryViewer, Menu menu, @Nullable MenuView previousMenuView) { super(inventoryViewer, menu, previousMenuView); } @Override public void setCurrentPage(int currentPage) { Preconditions.checkArgument(currentPage >= 1, "invalid page " + currentPage); if (this.currentPage == currentPage) return; this.currentPage = currentPage; setPreviousMove(false); refreshView(); } @Override public int getCurrentPage() { return this.currentPage; } @Override public abstract List getPagedObjects(); @Override public abstract void updatePagedObjects(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/MenuView.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.inventory.InventoryHolder; /** * The menu view represents an opened menu for a player. * While {@link Menu} is used to describe the info about the menu, the view is the actual inventory * that is opened for the player. */ public interface MenuView, A extends ViewArgs> extends InventoryHolder { /** * Get the player currently viewing the menu. */ SuperiorPlayer getInventoryViewer(); /** * Get the menu of this view. */ Menu getMenu(); /** * Get the previous menu that was opened for the player. */ @Nullable MenuView getPreviousMenuView(); /** * Set the previous menu to be opened after closing this view. * * @param previousMenuView The menu to open after that. * @param keepOlderViews If previousMenuView is not null and set to true, older views will be kept. * In other words, it will only replace the last previous view. * If false, the previous views will be the ones of previousMenuView. */ void setPreviousMenuView(@Nullable MenuView previousMenuView, boolean keepOlderViews); /** * Set whether closing the menu should open the previous menu. */ void setPreviousMove(boolean previousMove); /** * Get whether closing the menu should open the previous menu. */ boolean isPreviousMenu(); /** * Refresh this view for the player. * This will re-build the inventory from scratch and update it for the player viewing it. */ void refreshView(); /** * Close the view for the player. * The view can later be reopened using {@link #refreshView()} or by creating a new one from {@link Menu} */ void closeView(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/PagedMenuView.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.view; import java.util.List; /** * Similar to {@link MenuView}, but used for views of page-based menus. * See {@link MenuView} */ public interface PagedMenuView, A extends ViewArgs, E> extends MenuView { /** * Set the current page index for the paged menu. * If the page was changed by this method, the view will be updated, similar to a call to {@link #refreshView()} * * @param currentPage The new page to show. */ void setCurrentPage(int currentPage); /** * Get the current page index of the paged menu. */ int getCurrentPage(); /** * Get all the paged objects of the menu. */ List getPagedObjects(); /** * Update the paged objects for the menu. * This does not update the actual view. To do that, call {@link #refreshView()} */ void updatePagedObjects(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/view/ViewArgs.java ================================================ package com.bgsoftware.superiorskyblock.api.menu.view; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; /** * An empty interface used to describe arguments for a {@link MenuView} * This argument is later used to create a new view from {@link Menu#createView(SuperiorPlayer, ViewArgs, MenuView)} */ public interface ViewArgs { } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/IMissionsHolder.java ================================================ package com.bgsoftware.superiorskyblock.api.missions; import java.util.List; import java.util.Map; public interface IMissionsHolder { /** * Complete a mission. * * @param mission The mission to complete. */ void completeMission(Mission mission); /** * Reset a mission. * * @param mission The mission to reset. */ void resetMission(Mission mission); /** * Check whether the island has completed the mission before. * * @param mission The mission to check. */ boolean hasCompletedMission(Mission mission); /** * Check whether the island can complete a mission again. * * @param mission The mission to check. */ boolean canCompleteMissionAgain(Mission mission); /** * Get the amount of times mission was completed. * * @param mission The mission to check. */ int getAmountMissionCompleted(Mission mission); /** * Set the amount of times mission was completed. * * @param mission The mission to set. * @param finishCount The amount of times the mission was completed. */ void setAmountMissionCompleted(Mission mission, int finishCount); /** * Get the list of the completed missions of the player. */ List> getCompletedMissions(); /** * Get all the completed missions with the amount of times they were completed. */ Map, Integer> getCompletedMissionsWithAmounts(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java ================================================ package com.bgsoftware.superiorskyblock.api.missions; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Function; public abstract class Mission { private final List requiredMissions = new LinkedList<>(); private final List requiredChecks = new LinkedList<>(); private final Map missionData = new ConcurrentHashMap<>(); private String name = null; private MissionCategory missionCategory = null; private Consumer clearMethod = null; private boolean onlyShowIfRequiredCompleted = false; private boolean islandMission = false; /** * Get the name of the mission. */ public String getName() { return name; } /** * Set the name of the mission. * * @param name The name to set. */ public void setName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); if (this.name == null) this.name = name; } /** * Get the category of the mission. */ public MissionCategory getMissionCategory() { return missionCategory; } /** * Set the category of the mission. * * @param missionCategory The category to set. */ public void setMissionCategory(MissionCategory missionCategory) { Preconditions.checkNotNull(missionCategory, "missionCategory parameter cannot be null."); Preconditions.checkArgument(missionCategory.getMissions().contains(this), "The mission is not inside the given category."); if (this.missionCategory == null) this.missionCategory = missionCategory; } /** * Get the island-mission of the mission. */ public boolean getIslandMission() { return islandMission; } /** * Set whether or not this mission is an island mission or not. * * @param islandMission The island-mission status. */ public void setIslandMission(boolean islandMission) { this.islandMission = islandMission; } /** * Set the clear method for the data object. */ public void setClearMethod(@Nullable Consumer clearMethod) { this.clearMethod = clearMethod; } /** * Add required missions for completing this mission. * * @param missions The array of required missions. */ public void addRequiredMission(String... missions) { Preconditions.checkNotNull(missions, "missions parameter cannot be null."); requiredMissions.addAll(Arrays.asList(missions)); } /** * Add required check for completing this mission. * These checks have placeholders support. * * @param checks The array of required missions. */ public void addRequiredCheck(String... checks) { Preconditions.checkNotNull(checks, "checks parameter cannot be null."); requiredChecks.addAll(Arrays.asList(checks)); } /** * Get the required missions for completing this mission. */ public List getRequiredMissions() { return Collections.unmodifiableList(requiredMissions); } /** * Get the required checks for completing this mission. */ public List getRequiredChecks() { return Collections.unmodifiableList(requiredChecks); } /** * Toggle the onlyShowIfRequiredCompleted flag. */ public void toggleOnlyShowIfRequiredCompleted() { onlyShowIfRequiredCompleted = !onlyShowIfRequiredCompleted; } /** * Check whether or not the item in the gui should be shown only * if all required missions are completed. */ public boolean isOnlyShowIfRequiredCompleted() { return onlyShowIfRequiredCompleted; } /** * The load function of the mission. * * @param plugin The plugin that loaded the mission (The SuperiorSkyblock's JavaPlugin class) * @param missionSection The configuration section of the mission from the config * @throws MissionLoadException if load was not success. */ public abstract void load(JavaPlugin plugin, ConfigurationSection missionSection) throws MissionLoadException; /** * Unloads this mission. *

* There is no need to handle data-saving, this is done automatically by the plugin. */ public void unload() { } /** * Get the progress of a specific player. * Method should return a value between 0.0 and 1.0 * * @param superiorPlayer The player to check. */ public abstract double getProgress(SuperiorPlayer superiorPlayer); /** * Get the progress value of a specific player. * For example: amount of broken cobblestone, amount of kills, etc. * * @param superiorPlayer The player to check. */ public int getProgressValue(SuperiorPlayer superiorPlayer) { return 0; } /** * Check whether or not a player can complete the mission. * * @param superiorPlayer The player to check. */ public boolean canComplete(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return getProgress(superiorPlayer) >= 1.0; } /** * Save mission's progress. * * @param section The mission's section in the config. */ public void saveProgress(ConfigurationSection section) { // Should be overridden by missions. } /** * Load mission's progress. * * @param section The mission's section in the config. */ public void loadProgress(ConfigurationSection section) { // Should be overridden by missions. } /** * A function that is called when a player is completing the mission. * * @param superiorPlayer The player that completed the mission. */ public abstract void onComplete(SuperiorPlayer superiorPlayer); /** * A function that is called when a player cannot complete the mission. * * @param superiorPlayer The player that tried to complete the mission. */ public abstract void onCompleteFail(SuperiorPlayer superiorPlayer); /** * A function that is called in order to clear progress of a player. * * @param superiorPlayer The player to clear the data of. */ public void clearData(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); SuperiorPlayer dataKey = getDataKey(superiorPlayer); if (dataKey != null) { V data = missionData.remove(dataKey); if (data != null && clearMethod != null) clearMethod.accept(data); } } /** * A function that is called when islands are transferred. * * @param oldPlayer The old owner of the player. * @param newPlayer The new owner of the player. */ public void transferData(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) { Preconditions.checkNotNull(oldPlayer, "oldPlayer parameter cannot be null."); Preconditions.checkNotNull(newPlayer, "newPlayer parameter cannot be null."); V data = missionData.remove(oldPlayer); if (data != null) missionData.put(newPlayer, data); } /** * Get they data-key for the provided player. * * @param superiorPlayer The player to check. */ @Nullable protected SuperiorPlayer getDataKey(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return islandMission ? superiorPlayer.getIsland() == null ? null : superiorPlayer.getIsland().getOwner() : superiorPlayer; } /** * Insert data to the mission data. * * @param superiorPlayer The player to change it's data. * @param value The data to insert. */ public void insertData(SuperiorPlayer superiorPlayer, V value) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(value, "value parameter cannot be null."); SuperiorPlayer dataKey = getDataKey(superiorPlayer); if (dataKey != null) missionData.put(dataKey, value); } /** * Get or create data for a player. * * @param superiorPlayer The player to get data from. * @param createFunction The function that will be run when data doesn't exist yet. */ @Nullable public V getOrCreate(SuperiorPlayer superiorPlayer, Function createFunction) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(createFunction, "createFunction parameter cannot be null."); SuperiorPlayer dataKey = getDataKey(superiorPlayer); if (dataKey == null) return null; return missionData.computeIfAbsent(dataKey, createFunction); } /** * Get data for a player. * * @param superiorPlayer The player to get data from. */ @Nullable public V get(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); SuperiorPlayer dataKey = getDataKey(superiorPlayer); if (dataKey == null) return null; return missionData.get(dataKey); } /** * Get the entry set of the data map. */ protected Set> entrySet() { return missionData.entrySet(); } /** * A function that is called on every item of the menu. * This is used to inject custom placeholders into items. * The method is called async. * * @param superiorPlayer The player that opens the menu. * @param itemStack The item of the mission. */ public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { // Should be overridden by missions. } @Override public int hashCode() { return Objects.hash(name); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Mission mission = (Mission) o; return Objects.equals(name, mission.name); } @Override public String toString() { return name; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/MissionCategory.java ================================================ package com.bgsoftware.superiorskyblock.api.missions; import java.util.List; public interface MissionCategory { /** * Get the name of the category. */ String getName(); /** * Get the slot of the category in the missions menu. */ int getSlot(); /** * Get all the missions in the category. */ List> getMissions(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/MissionLoadException.java ================================================ package com.bgsoftware.superiorskyblock.api.missions; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.plugin.java.JavaPlugin; /** * This exception is used inside {@link Mission#load(JavaPlugin, ConfigurationSection)} * when a faulty configuration is used for the mission. */ public class MissionLoadException extends Exception { public MissionLoadException(String error) { super(error); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleInitializeData.java ================================================ package com.bgsoftware.superiorskyblock.api.modules; import java.io.File; /** * All the data needed for a {@link PluginModule} to be initialized correctly. */ public interface ModuleInitializeData { /** * The data folder of the module. * Should return plugins/SuperiorSkyblock2/datastore/modules/{module-name} */ File getDataFolder(); /** * The folder of the module. * Should return plugins/SuperiorSkyblock2/modules/{module-name} */ File getModuleFolder(); /** * The logger of the module. */ ModuleLogger getLogger(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLoadTime.java ================================================ package com.bgsoftware.superiorskyblock.api.modules; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; public enum ModuleLoadTime { /** * When used, the module will be loaded before the plugin is initialized. * This makes it possible to listen to the PluginInitializeEvent and alter it. */ PLUGIN_INITIALIZE, /** * When used, the module will be enabled before the plugin loads the worlds for the islands. */ BEFORE_WORLD_CREATION, /** * When used, the module will be enabled after the worlds are loaded into the game. * Please note that all the managers of the plugin are not loaded at this time, and you cannot use them * inside your {@link PluginModule#onEnable(SuperiorSkyblock)} method. Furthermore, the data of your module * was not yet loaded at this time. If you want to use your data in the {@link PluginModule#onEnable(SuperiorSkyblock)} * method, check out {@link #AFTER_MODULE_DATA_LOAD}. */ NORMAL, /** * When used, the module will be enabled after its data was loaded by calling the * {@link PluginModule#loadData(SuperiorSkyblock)} method. Please note that not all the managers of the plugin * are loaded at this time, and using them inside your {@link PluginModule#onEnable(SuperiorSkyblock)} may * lead to undefined behavior; access them at your own risk. */ AFTER_MODULE_DATA_LOAD, /** * When used, the module will be enabled after all the managers were completely loaded. */ AFTER_HANDLERS_LOADING } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java ================================================ package com.bgsoftware.superiorskyblock.api.modules; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import java.io.PrintWriter; import java.io.StringWriter; import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; /** * Simple implementation of a custom logger for modules. */ public class ModuleLogger extends Logger { private boolean debugMode = false; /** * Constructor for the logger. * * @param pluginModule The module that uses the logger. */ public ModuleLogger(PluginModule pluginModule) { super("SuperiorSkyblock2-" + pluginModule.getName(), null); this.setParent(SuperiorSkyblockAPI.getSuperiorSkyblock().getLogger()); this.setLevel(Level.ALL); } public void setDebugMode(boolean debugMode) { this.debugMode = debugMode; } public void i(String message) { super.info(message); } public void w(String message) { super.warning(message); } public void e(String message) { super.severe(message); } public void e(String message, Throwable error) { super.severe(message); logError(error); } public void d(String message) { if (this.debugMode) { this.info(message); } else { LogRecord logRecord = new LogRecord(Level.INFO, message); for (Handler handler : getHandlers()) { if (handler instanceof ModuleFileHandler) { handler.publish(logRecord); } } } } private void logError(Throwable error) { StringWriter buffer = new StringWriter(); PrintWriter pw = new PrintWriter(buffer); error.printStackTrace(pw); super.severe(buffer.toString()); } /** * Custom interface to distinguish between logger handlers and the module's custom file handler. */ public interface ModuleFileHandler { } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleResources.java ================================================ package com.bgsoftware.superiorskyblock.api.modules; import com.google.common.base.Preconditions; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; /** * Class to handle resources for a module. */ public class ModuleResources { private final File moduleFile; private final File moduleFolder; private final ClassLoader classLoader; /** * Constructor for the class. * * @param moduleFile The file of the module. * @param moduleFolder The data folder of the module. * @param classLoader The class loader of the module. */ public ModuleResources(File moduleFile, File moduleFolder, ClassLoader classLoader) { this.moduleFile = moduleFile; this.moduleFolder = moduleFolder; this.classLoader = classLoader; } /** * Saves the raw contents of an embedded resource within the module. * * @param resourcePath Path to the resource to save. */ public void saveResource(String resourcePath) { Preconditions.checkNotNull(resourcePath, "resourcePath cannot be null."); Preconditions.checkArgument(!resourcePath.isEmpty(), "resourcePath cannot be empty."); resourcePath = resourcePath.replace('\\', '/'); try (InputStream resourceInput = getResource(resourcePath)) { File outFile = new File(this.moduleFolder, resourcePath); int lastIndex = resourcePath.lastIndexOf(47); File outDir = new File(this.moduleFolder, resourcePath.substring(0, Math.max(lastIndex, 0))); if (!outDir.exists()) { outDir.mkdirs(); } try (OutputStream out = new FileOutputStream(outFile)) { byte[] buf = new byte[1024]; int len; while ((len = resourceInput.read(buf)) > 0) { out.write(buf, 0, len); } } } catch (IOException ex) { throw new RuntimeException("Could not save " + resourcePath, ex); } } /** * Get the raw contents of an embedded resource within the module. * * @param fileName The name of the resource to get contents of. */ public InputStream getResource(String fileName) { Preconditions.checkNotNull(fileName, "fileName cannot be null."); try { URL url = this.classLoader.getResource(fileName); if (url != null) { URLConnection connection = url.openConnection(); connection.setUseCaches(false); return connection.getInputStream(); } } catch (IOException ignored) { } throw new IllegalArgumentException("The embedded resource '" + fileName + "' cannot be found in " + this.moduleFile); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java ================================================ package com.bgsoftware.superiorskyblock.api.modules; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import org.bukkit.event.Listener; import java.io.File; import java.io.InputStream; import java.util.logging.Logger; /** * Plugin modules are similar to plugins. The difference between them and regular plugins is that the modules are * designed to work only with SuperiorSkyblock, and they are loaded by SuperiorSkyblock and not by the server. * The advantages of using modules over plugins is the ability to manage them through the plugin's commands, without * needing to restart the server. Moreover, SuperiorSkyblock handles listeners and commands for you - it will register * them when needed, unregister them and will do all of that work for you. */ public abstract class PluginModule { private final String moduleName; private final String authorName; private File dataFolder; private File moduleFile; private File moduleFolder; private ClassLoader classLoader; private ModuleLogger logger; private ModuleResources moduleResources; private boolean initialized = false; /** * Constructor for a module. * * @param moduleName The name of the module. * @param authorName The name of the author of the module. */ protected PluginModule(String moduleName, String authorName) { this.moduleName = moduleName; this.authorName = authorName; } /** * Called when the module is enabled. * * @param plugin Instance of the plugin. */ public abstract void onEnable(SuperiorSkyblock plugin); /** * Called when the module is reloaded. * * @param plugin Instance of the plugin. */ public abstract void onReload(SuperiorSkyblock plugin); /** * Called when the module is disabled. * * @param plugin Instance of the plugin. */ public abstract void onDisable(SuperiorSkyblock plugin); /** * Called when the module can load data about players. * It's called after the plugin's data is loaded. *

* This is similar to load data when {@link com.bgsoftware.superiorskyblock.api.events.PluginInitializedEvent} * is fired. * * @param plugin Instance of the plugin. */ public void loadData(SuperiorSkyblock plugin) { } /** * Called when the module initialized for the first time. * * @param plugin Instance of the plugin. */ protected void onPluginInit(SuperiorSkyblock plugin) { // Can be overridden by custom modules. } /** * List of listeners to register for the module. * The plugin will handle the registers for the module - register them when the module is enabled, * and unregister them when it is disabled. * * @param plugin Instance of the plugin. * @return Array of listeners for the module. May be null for no listeners. */ @Nullable public abstract Listener[] getModuleListeners(SuperiorSkyblock plugin); /** * List of player commands to register for the module. * The plugin will handle the commands for the module - register them when the module is enabled, * and unregister them when it is disabled. * * @param plugin Instance of the plugin. * @return Array of player commands for the module. May be null for no commands. */ @Nullable public abstract SuperiorCommand[] getSuperiorCommands(SuperiorSkyblock plugin); /** * List of admin commands to register for the module. * The plugin will handle the commands for the module - register them when the module is enabled, * and unregister them when it is disabled. * * @param plugin Instance of the plugin. * @return Array of player commands for the module. May be null for no commands. */ @Nullable public abstract SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblock plugin); /** * Get when the module should be enabled. * There are 3 loading stages for modules: * {@link ModuleLoadTime#AFTER_HANDLERS_LOADING} - modules that should be loaded before the worlds are created. * Should be used if the module needs to override the WorldsProvider. * {@link ModuleLoadTime#NORMAL} - modules that should be loaded without any specifications. * Default for all the modules. * {@link ModuleLoadTime#AFTER_HANDLERS_LOADING} - modules that should be loaded after all the plugin handlers. * Should be used if the module is interacting with the built-in handlers on its {@link #onEnable} method. */ public ModuleLoadTime getLoadTime() { return ModuleLoadTime.NORMAL; } /** * Get the name of the module. */ public final String getName() { return moduleName; } /** * Get the author of the module. */ public final String getAuthor() { return authorName; } /** * Get the data folder of the module. * The path for the folder is always plugins/SuperiorSkyblock2/modules/{module-name}/ * * @deprecated Misleading name; check out {@link #getModuleFolder()} */ @Deprecated public final File getDataFolder() { return this.getModuleFolder(); } /** * Get the folder of the module. * The path for the folder is always plugins/SuperiorSkyblock2/modules/{module-name}/ */ public final File getModuleFolder() { return this.moduleFolder; } /** * Get the jar file of the module. * May be null if the module was registered without calling {@link #initModuleLoader(File, ClassLoader)} * This is not an expected behavior, and the plugin will never initialize the module with a null file! */ @Nullable public final File getModuleFile() { return moduleFile; } /** * Get the folder where data of the module can be stored at. * The path for the folder is always plugins/SuperiorSkyblock2/datastore/modules/{module-name}/ */ public final File getDataStoreFolder() { return this.dataFolder; } /** * Get the class loader of the module. * May be null if the module was registered without calling {@link #initModuleLoader(File, ClassLoader)} * This is not an expected behavior, and the plugin will never initialize the module with a null class loader! */ @Nullable public final ClassLoader getClassLoader() { return classLoader; } /** * Get the logger of the module {@link ModuleLogger} */ public final Logger getLogger() { return logger; } /** * Check whether the module was initialized or not. * Modules will be initialized after calling to {@link #initModule(SuperiorSkyblock, File, File)} */ public final boolean isInitialized() { return initialized; } /** * Saves the raw contents of an embedded resource within the module. * * @param resourceName The name of the resource to save. */ public final void saveResource(String resourceName) { if (this.moduleResources == null) throw new IllegalArgumentException("Cannot save resources for an uninitialized module."); moduleResources.saveResource(resourceName); } /** * Get the raw contents of an embedded resource within the module. * * @param resourceName The name of the resource to get contents of. */ public final InputStream getResource(String resourceName) { if (this.moduleResources == null) throw new IllegalArgumentException("Cannot get resources for an uninitialized module."); return moduleResources.getResource(resourceName); } /** * Initialize the module. * This method cannot be called twice - do not call it unless you know what you are doing. * * @param plugin An instance to the plugin. * @param dataFolder The database folder of the module. */ @Deprecated public final void initModule(SuperiorSkyblock plugin, File dataFolder) { this.initModule(plugin, new File(moduleFile.getParentFile(), moduleName), dataFolder); } /** * Initialize the module. * This method cannot be called twice - do not call it unless you know what you are doing. * * @param plugin An instance to the plugin. * @param dataFolder The database folder of the module. * @param moduleFolder The folder of the module. */ @Deprecated public final void initModule(SuperiorSkyblock plugin, File moduleFolder, File dataFolder) { ModuleLogger moduleLogger = new ModuleLogger(this); this.initModule(plugin, new ModuleInitializeData() { @Override public File getDataFolder() { return dataFolder; } @Override public File getModuleFolder() { return moduleFolder; } @Override public ModuleLogger getLogger() { return moduleLogger; } }); } /** * Initialize the module. * This method cannot be called twice - do not call it unless you know what you are doing. * * @param plugin An instance to the plugin. * @param context The initialize context. */ public final void initModule(SuperiorSkyblock plugin, ModuleInitializeData context) { if (this.initialized) throw new RuntimeException("The module " + this.moduleName + " was already initialized."); this.initialized = true; File moduleFolder = context.getModuleFolder(); if (!moduleFolder.exists() && !moduleFolder.mkdirs()) throw new RuntimeException("Cannot create module folder for " + this.moduleName + "."); this.dataFolder = context.getDataFolder(); this.moduleFolder = moduleFolder; this.logger = context.getLogger(); if (this.moduleFile != null && this.classLoader != null) this.moduleResources = new ModuleResources(this.moduleFile, this.moduleFolder, this.classLoader); onPluginInit(plugin); } /** * Initialize the module's loaders settings. * * @param moduleFile The file of the module jar. * @param classLoader The class loader used to load the module. */ public final void initModuleLoader(File moduleFile, ClassLoader classLoader) { if (initialized) throw new RuntimeException("The module " + moduleName + " was already initialized."); this.moduleFile = moduleFile; this.classLoader = classLoader; } /** * Disable the module. */ public final void disableModule() { initialized = false; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/objects/Enumerable.java ================================================ package com.bgsoftware.superiorskyblock.api.objects; /** * This class is used in internal data structures for a more optimized way of doing data lookups. * This is mainly used for lookups for {@link com.bgsoftware.superiorskyblock.api.island.IslandPrivilege} and * {@link com.bgsoftware.superiorskyblock.api.island.IslandFlag}. */ public interface Enumerable { /** * The ordinal of this enumeration constant. */ int ordinal(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/objects/Pair.java ================================================ package com.bgsoftware.superiorskyblock.api.objects; import java.util.Map; /** * This class represents a pair of elements. * * @param First element of this pair. * @param Second element of this pair. */ public class Pair { private E1 firstElement; private E2 secondElement; /** * Create a new pair out of a {@link Map.Entry} object. * * @param entry The entry to create the pair from. */ public Pair(Map.Entry entry) { this(entry.getKey(), entry.getValue()); } /** * Create a new pair out of two elements. * * @param firstElement The first element of this pair. * @param secondElement The second element of this pair. */ public Pair(E1 firstElement, E2 secondElement) { this.firstElement = firstElement; this.secondElement = secondElement; } /** * Get the first element of this pair. */ public E1 getKey() { return this.firstElement; } /** * Set the first element of this pair. * * @param element The new element to set. */ public void setKey(E1 element) { this.firstElement = element; } /** * Get the second element of this pair. */ public E2 getValue() { return this.secondElement; } /** * Set the second element of this pair. * * @param element The new element to set. */ public void setValue(E2 element) { this.secondElement = element; } @Override public String toString() { return "{" + this.firstElement + "=" + this.secondElement + "}"; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/DelegatePersistentDataContainer.java ================================================ package com.bgsoftware.superiorskyblock.api.persistence; import com.bgsoftware.common.annotations.Nullable; import java.util.function.BiConsumer; public class DelegatePersistentDataContainer implements PersistentDataContainer { protected final PersistentDataContainer handle; protected DelegatePersistentDataContainer(PersistentDataContainer handle) { this.handle = handle; } @Override public boolean has(String key) { return this.handle.has(key); } @Override public boolean hasKeyOfType(String key, PersistentDataType type) { return this.handle.hasKeyOfType(key, type); } @Nullable @Override public T put(String key, PersistentDataType type, T value) throws IllegalArgumentException, IllegalStateException { return this.handle.put(key, type, value); } @Nullable @Override public R put(String key, PersistentDataType type, T value, PersistentDataType returnType) throws IllegalArgumentException, IllegalStateException { return this.handle.put(key, type, value, returnType); } @Nullable @Override public Object remove(String key) { return this.handle.remove(key); } @Nullable @Override public T removeKeyOfType(String key, PersistentDataType type) { return this.handle.removeKeyOfType(key, type); } @Nullable @Override public T get(String key, PersistentDataType type) throws IllegalArgumentException { return this.handle.get(key, type); } @Nullable @Override public Object get(String key) { return this.handle.get(key); } @Override public T getOrDefault(String key, PersistentDataType type, T def) throws IllegalArgumentException { return this.handle.getOrDefault(key, type, def); } @Override public Object getOrDefault(String key, Object def) { return this.handle.getOrDefault(key, def); } @Override public boolean isEmpty() { return this.handle.isEmpty(); } @Override public int size() { return this.handle.size(); } @Override public void forEach(BiConsumer action) { this.handle.forEach(action); } @Override public byte[] serialize() { return this.handle.serialize(); } @Override public void load(byte[] data) throws IllegalArgumentException { this.handle.load(data); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/IPersistentDataHolder.java ================================================ package com.bgsoftware.superiorskyblock.api.persistence; /** * Represents an object that can store custom persistent data. */ public interface IPersistentDataHolder { /** * Get the container of custom persistent data of this object. */ PersistentDataContainer getPersistentDataContainer(); /** * Check if the persistent data container is empty. */ boolean isPersistentDataContainerEmpty(); /** * When saving data into the container, it's not immediately saved to database. * Call this method to save the persistent data container into database. */ void savePersistentDataContainer(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/PersistentDataContainer.java ================================================ package com.bgsoftware.superiorskyblock.api.persistence; import com.bgsoftware.common.annotations.Nullable; import java.util.function.BiConsumer; public interface PersistentDataContainer { /** * Check if the provided key has a matching metadata value. * * @param key The key to check. */ boolean has(String key); /** * Check if the provided key has a matching metadata value of the provided type. * * @param key The key to check. * @param type The type to check. */ boolean hasKeyOfType(String key, PersistentDataType type); /** * Store a metadata value matching the provided key and type. * * @param key The key to store. * @param type The type of the metadata value. * @param value The metadata value to store. * @return The old metadata value that was stored matching the key, if exists. * @throws IllegalArgumentException If the old metadata value is not of type {@param type}. * @throws IllegalStateException If {@param type} doesn't have a valid serializer available. */ @Nullable T put(String key, PersistentDataType type, T value) throws IllegalArgumentException, IllegalStateException; /** * Store a metadata value matching the provided key and type. * * @param key The key to store. * @param type The type of the metadata. * @param value The metadata value to store. * @param returnType The type of the old metadata value. * @return The old metadata value that was stored matching the key, if exists. * @throws IllegalArgumentException If the old metadata value is not of type {@param returnType}. * @throws IllegalStateException If {@param type} doesn't have a valid serializer available. */ @Nullable R put(String key, PersistentDataType type, T value, PersistentDataType returnType) throws IllegalArgumentException, IllegalStateException; /** * Remove a metadata value matching the provided key. * * @param key The key to remove. * @return The old metadata value that was stored matching the key, if exists. */ @Nullable Object remove(String key); /** * Remove a metadata value matching the provided key and type. * If the metadata value doesn't match the {@param type}, it will not get removed. * * @param key The key to remove. * @param type The type of the metadata value to remove. * @return The old metadata value that was stored matching the key, if exists. * If the metadata value does not match the current type, null will be returned. */ @Nullable T removeKeyOfType(String key, PersistentDataType type); /** * Get a metadata value matching the provided key and type. * * @param key The key to fetch. * @param type The type of the metadata value to fetch. * @return The metadata value that is stored matching the key, if exists. * @throws IllegalArgumentException If the metadata value is not of type {@param type}. */ @Nullable T get(String key, PersistentDataType type) throws IllegalArgumentException; /** * Get a metadata value matching the provided key. * * @param key The key to fetch. * @return The metadata value that is stored matching the key, if exists. */ @Nullable Object get(String key); /** * Get a metadata value matching the provided key and type. * * @param key The key to fetch. * @param type The type of the metadata value to fetch. * @param def Value to return in case there is no metadata value matching the provided key. * @return The metadata value that is stored matching the key, or {@param def} otherwise. * @throws IllegalArgumentException If the metadata value is not of type {@param type}. */ T getOrDefault(String key, PersistentDataType type, T def) throws IllegalArgumentException; /** * Get a metadata value matching the provided key. * * @param key The key to fetch. * @param def Value to return in case there is no metadata value matching the provided key. * @return The metadata value that is stored matching the key, or {@param def} otherwise. */ Object getOrDefault(String key, Object def); /** * Check whether the container is empty. */ boolean isEmpty(); /** * Get the size of the container. */ int size(); /** * Iterate through all the data of the container. * * @param action The action to perform for each key and value pair. */ void forEach(BiConsumer action); /** * Get the serialized contents of the container as a bytes array. * The format of the serialized data may be different depending on the implementation of the container. * The serialized data must be loaded without any errors using {@link #load(byte[])}. */ byte[] serialize(); /** * Load contents from the serialized data into the container. * The format of the serialized data may be different depending on the implementation of the container. * * @param data The serialized data. * @throws IllegalArgumentException If the given data cannot be serialized correctly. */ void load(byte[] data) throws IllegalArgumentException; } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/PersistentDataType.java ================================================ package com.bgsoftware.superiorskyblock.api.persistence; import com.bgsoftware.common.annotations.Nullable; import com.google.common.base.Preconditions; import java.math.BigDecimal; import java.util.UUID; /** * Represents a data type that can be stored inside a {@link PersistentDataContainer}. * * @param The type of the value to store. */ public class PersistentDataType { public static final PersistentDataType BIG_DECIMAL = new PersistentDataType<>(BigDecimal.class); public static final PersistentDataType BYTE_ARRAY = new PersistentDataType<>(byte[].class); public static final PersistentDataType BYTE = new PersistentDataType<>(Byte.class); public static final PersistentDataType DOUBLE = new PersistentDataType<>(Double.class); public static final PersistentDataType FLOAT = new PersistentDataType<>(Float.class); public static final PersistentDataType INT_ARRAY = new PersistentDataType<>(int[].class); public static final PersistentDataType INTEGER = new PersistentDataType<>(Integer.class); public static final PersistentDataType LONG = new PersistentDataType<>(Long.class); public static final PersistentDataType SHORT = new PersistentDataType<>(Short.class); public static final PersistentDataType STRING = new PersistentDataType<>(String.class); public static final PersistentDataType UUID = new PersistentDataType<>(UUID.class); private final Class type; private final PersistentDataTypeContext context; /** * Custom type constructor. * * @param type The type. * @param context The context class used to serialize and deserialize this data type. */ public PersistentDataType(Class type, PersistentDataTypeContext context) { this.type = Preconditions.checkNotNull(type, "type parameter cannot be null"); this.context = Preconditions.checkNotNull(context, "context parameter cannot be null"); } /** * Built-in type constructor. * * @param type The type. */ private PersistentDataType(Class type) { this.type = type; this.context = null; } public Class getType() { return this.type; } @Nullable public PersistentDataTypeContext getContext() { return this.context; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/PersistentDataTypeContext.java ================================================ package com.bgsoftware.superiorskyblock.api.persistence; /** * The context class is used to serialize and deserialize a custom data type. * * @param The type of the data value. */ public interface PersistentDataTypeContext { /** * Serialize the provided value into a bytes buffer. * * @param value The value to serialize. * @return The serialized data. */ byte[] serialize(T value); /** * Deserialize the provided bytes buffer into a valid value. * * @param data The serialized data. * @return The deserialized value. */ T deserialize(byte[] data); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/platform/IEventsDispatcher.java ================================================ package com.bgsoftware.superiorskyblock.api.platform; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; /** * The events dispatcher is used to dispatch events to the plugin. */ public interface IEventsDispatcher { /** * Notify about a new game-event. * * @param event The event that was fired. * @param priority The priority of the event. * @return Whether the event was successfully dispatched. */ boolean notifyEvent(Event event, EventPriority priority); /** * Whether the default executor should be used if {@link #notifyEvent(Event, EventPriority)} fails. */ default boolean shouldFallbackToDefaultExecutorOnFailure() { return true; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java ================================================ package com.bgsoftware.superiorskyblock.api.player; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.HitActionResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; public class DelegateSuperiorPlayer implements SuperiorPlayer { protected final SuperiorPlayer handle; protected DelegateSuperiorPlayer(SuperiorPlayer handle) { this.handle = handle; } @Override public UUID getUniqueId() { return this.handle.getUniqueId(); } @Override public String getName() { return this.handle.getName(); } @Override public PlayerCache getCache() { return this.handle.getCache(); } @Override public String getTextureValue() { return this.handle.getTextureValue(); } @Override public void setTextureValue(String textureValue) { this.handle.setTextureValue(textureValue); } @Override public void updateLastTimeStatus() { this.handle.updateLastTimeStatus(); } @Override public void setLastTimeStatus(long lastTimeStatus) { this.handle.setLastTimeStatus(lastTimeStatus); } @Override public long getLastTimeStatus() { return this.handle.getLastTimeStatus(); } @Override public void updateName() { this.handle.updateName(); } @Override public void setName(String name) { this.handle.setName(name); } @Nullable @Override public Player asPlayer() { return this.handle.asPlayer(); } @Nullable @Override public OfflinePlayer asOfflinePlayer() { return this.handle.asOfflinePlayer(); } @Override public boolean isOnline() { return this.handle.isOnline(); } @Override public void runIfOnline(Consumer toRun) { this.handle.runIfOnline(toRun); } @Override public boolean hasFlyGamemode() { return this.handle.hasFlyGamemode(); } @Nullable @Override public MenuView getOpenedView() { return this.handle.getOpenedView(); } @Override public boolean isAFK() { return this.handle.isAFK(); } @Override public boolean isVanished() { return this.handle.isVanished(); } @Override public boolean isShownAsOnline() { return this.handle.isShownAsOnline(); } @Override public boolean hasPermission(String permission) { return this.handle.hasPermission(permission); } @Override public boolean hasPermissionWithoutOP(String permission) { return this.handle.hasPermissionWithoutOP(permission); } @Override public boolean hasPermission(IslandPrivilege permission) { return this.handle.hasPermission(permission); } @Override public boolean hasBypassPermission(IslandPrivilege permission) { return this.handle.hasBypassPermission(permission); } @Override public HitActionResult canHit(SuperiorPlayer otherPlayer) { return this.handle.canHit(otherPlayer); } @Nullable @Override public World getWorld() { return this.handle.getWorld(); } @Nullable @Override public Location getLocation() { return this.handle.getLocation(); } @Override public Location getLocation(Location location) { return this.handle.getLocation(location); } @Override public void teleport(Location location) { this.handle.teleport(location); } @Override public void teleport(Location location, @Nullable Consumer teleportResult) { this.handle.teleport(location, teleportResult); } @Override public void teleport(Island island) { this.handle.teleport(island); } @Override public void teleport(Island island, @Nullable Consumer teleportResult) { this.handle.teleport(island, teleportResult); } @Override public void teleport(Island island, Dimension dimension) { this.handle.teleport(island, dimension); } @Override public void teleport(Island island, Dimension dimension, Consumer teleportResult) { this.handle.teleport(island, dimension, teleportResult); } @Override public boolean isInsideIsland() { return this.handle.isInsideIsland(); } @Override public SuperiorPlayer getIslandLeader() { return this.handle.getIslandLeader(); } @Override @Deprecated public void setIslandLeader(SuperiorPlayer islandLeader) { this.handle.setIslandLeader(islandLeader); } @Nullable @Override public Island getIsland() { return this.handle.getIsland(); } @Override public void setIsland(Island island) { this.handle.setIsland(island); } @Override public boolean hasIsland() { return this.handle.hasIsland(); } @Override public void addInvite(Island island) { this.handle.addInvite(island); } @Override public void removeInvite(Island island) { this.handle.removeInvite(island); } @Override public List getInvites() { return this.handle.getInvites(); } @Override public void addCoop(Island island) { this.handle.addCoop(island); } @Override public void removeCoop(Island island) { this.handle.removeCoop(island); } @Override public List getCoopIslands() { return this.handle.getCoopIslands(); } @Override public PlayerRole getPlayerRole() { return this.handle.getPlayerRole(); } @Override public void setPlayerRole(PlayerRole playerRole) { this.handle.setPlayerRole(playerRole); } @Override public int getDisbands() { return this.handle.getDisbands(); } @Override public void setDisbands(int disbands) { this.handle.setDisbands(disbands); } @Override public boolean hasDisbands() { return this.handle.hasDisbands(); } @Override public Locale getUserLocale() { return this.handle.getUserLocale(); } @Override public void setUserLocale(Locale locale) { this.handle.setUserLocale(locale); } @Override public boolean hasWorldBorderEnabled() { return this.handle.hasWorldBorderEnabled(); } @Override public void toggleWorldBorder() { this.handle.toggleWorldBorder(); } @Override public void setWorldBorderEnabled(boolean enabled) { this.handle.setWorldBorderEnabled(enabled); } @Override public void updateWorldBorder(@Nullable Island island) { this.handle.updateWorldBorder(island); } @Override public boolean hasBlocksStackerEnabled() { return this.handle.hasBlocksStackerEnabled(); } @Override public void toggleBlocksStacker() { this.handle.toggleBlocksStacker(); } @Override public void setBlocksStacker(boolean enabled) { this.handle.setBlocksStacker(enabled); } @Override public boolean hasSchematicModeEnabled() { return this.handle.hasSchematicModeEnabled(); } @Override public void toggleSchematicMode() { this.handle.toggleSchematicMode(); } @Override public void setSchematicMode(boolean enabled) { this.handle.setSchematicMode(enabled); } @Override public boolean hasTeamChatEnabled() { return this.handle.hasTeamChatEnabled(); } @Override public void toggleTeamChat() { this.handle.toggleTeamChat(); } @Override public void setTeamChat(boolean enabled) { this.handle.setTeamChat(enabled); } @Override public boolean hasBypassModeEnabled() { return this.handle.hasBypassModeEnabled(); } @Override public void toggleBypassMode() { this.handle.toggleBypassMode(); } @Override public void setBypassMode(boolean enabled) { this.handle.setBypassMode(enabled); } @Override public boolean hasToggledPanel() { return this.handle.hasToggledPanel(); } @Override public void setToggledPanel(boolean toggledPanel) { this.handle.setToggledPanel(toggledPanel); } @Override public boolean hasIslandFlyEnabled() { return this.handle.hasIslandFlyEnabled(); } @Override public void toggleIslandFly() { this.handle.toggleIslandFly(); } @Override public void setIslandFly(boolean enabled) { this.handle.setIslandFly(enabled); } @Override public boolean hasAdminSpyEnabled() { return this.handle.hasAdminSpyEnabled(); } @Override public void toggleAdminSpy() { this.handle.toggleAdminSpy(); } @Override public void setAdminSpy(boolean enabled) { this.handle.setAdminSpy(enabled); } @Override public BorderColor getBorderColor() { return this.handle.getBorderColor(); } @Override public void setBorderColor(BorderColor borderColor) { this.handle.setBorderColor(borderColor); } @Override public BlockPosition getSchematicPos1() { return this.handle.getSchematicPos1(); } @Override public void setSchematicPos1(@Nullable Block block) { this.handle.setSchematicPos1(block); } @Override public BlockPosition getSchematicPos2() { return this.handle.getSchematicPos2(); } @Override public void setSchematicPos2(@Nullable Block block) { this.handle.setSchematicPos2(block); } @Override @Deprecated public boolean isImmunedToPvP() { return this.handle.isImmunedToPvP(); } @Override @Deprecated public void setImmunedToPvP(boolean immunedToPvP) { this.handle.setImmunedToPvP(immunedToPvP); } @Override @Deprecated public boolean isLeavingFlag() { return this.handle.isLeavingFlag(); } @Override @Deprecated public void setLeavingFlag(boolean leavingFlag) { this.handle.setLeavingFlag(leavingFlag); } @Override @Deprecated public boolean isImmunedToPortals() { return this.handle.isImmunedToPortals(); } @Override @Deprecated public void setImmunedToPortals(boolean immuneToPortals) { this.handle.setImmunedToPortals(immuneToPortals); } @Nullable @Override public BukkitTask getTeleportTask() { return this.handle.getTeleportTask(); } @Override public void setTeleportTask(@Nullable BukkitTask teleportTask) { this.handle.setTeleportTask(teleportTask); } @Override @Deprecated public PlayerStatus getPlayerStatus() { return this.handle.getPlayerStatus(); } @Override public void setPlayerStatus(PlayerStatus playerStatus) { this.handle.setPlayerStatus(playerStatus); } @Override public void removePlayerStatus(PlayerStatus playerStatus) { this.handle.removePlayerStatus(playerStatus); } @Override public boolean hasPlayerStatus(PlayerStatus playerStatus) { return this.handle.hasPlayerStatus(playerStatus); } @Override public void merge(SuperiorPlayer otherPlayer) { this.handle.merge(otherPlayer); } @Override public void completeMission(Mission mission) { this.handle.completeMission(mission); } @Override public void resetMission(Mission mission) { this.handle.resetMission(mission); } @Override public boolean hasCompletedMission(Mission mission) { return this.handle.hasCompletedMission(mission); } @Override public boolean canCompleteMissionAgain(Mission mission) { return this.handle.canCompleteMissionAgain(mission); } @Override public int getAmountMissionCompleted(Mission mission) { return this.handle.getAmountMissionCompleted(mission); } @Override public void setAmountMissionCompleted(Mission mission, int finishCount) { this.handle.setAmountMissionCompleted(mission, finishCount); } @Override public List> getCompletedMissions() { return this.handle.getCompletedMissions(); } @Override public Map, Integer> getCompletedMissionsWithAmounts() { return this.handle.getCompletedMissionsWithAmounts(); } @Override public DatabaseBridge getDatabaseBridge() { return this.handle.getDatabaseBridge(); } @Override public PersistentDataContainer getPersistentDataContainer() { return this.handle.getPersistentDataContainer(); } @Override public boolean isPersistentDataContainerEmpty() { return this.handle.isPersistentDataContainerEmpty(); } @Override public void savePersistentDataContainer() { this.handle.savePersistentDataContainer(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/PlayerStatus.java ================================================ package com.bgsoftware.superiorskyblock.api.player; public enum PlayerStatus { /** * The player is immuned to PvP and cannot be damaged by other players. */ PVP_IMMUNED, /** * The player cannot be teleported by portals. */ PORTALS_IMMUNED, /** * The player cannot take damage from fall damage. */ FALL_DAMAGE_IMMUNED, /** * The player recently left an island. */ LEAVING_ISLAND, /** * The player is being teleported by void-teleport. */ VOID_TELEPORT, /** * The player has no special status. */ @Deprecated NONE } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.player.algorithm; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.Location; import org.bukkit.entity.Player; import java.util.concurrent.CompletableFuture; public class DelegatePlayerTeleportAlgorithm implements PlayerTeleportAlgorithm { protected final PlayerTeleportAlgorithm handle; protected DelegatePlayerTeleportAlgorithm(PlayerTeleportAlgorithm handle) { this.handle = handle; } @Override public CompletableFuture teleport(Player player, Location location) { return this.handle.teleport(player, location); } @Override public CompletableFuture teleport(Player player, Island island) { return this.handle.teleport(player, island); } @Override public CompletableFuture teleport(Player player, Island island, Dimension dimension) { return this.handle.teleport(player, island, dimension); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/PlayerTeleportAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.player.algorithm; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.Location; import org.bukkit.entity.Player; import java.util.concurrent.CompletableFuture; public interface PlayerTeleportAlgorithm { /** * Teleport a player to another location. * * @param player The player to teleport. * @param location The location to teleport the player to. * @return CompletableFuture with boolean that indicates whether the teleportation was successful. */ CompletableFuture teleport(Player player, Location location); /** * Teleport a player to an island. * * @param player The player to teleport. * @param island The island to teleport the player to. * @return CompletableFuture with boolean that indicates whether the teleportation was successful. */ CompletableFuture teleport(Player player, Island island); /** * Teleport a player to an island in a specific dimension. * * @param player The player to teleport. * @param island The island to teleport the player to. * @param dimension The dimension to teleport the player to. * @return CompletableFuture with boolean that indicates whether the teleportation was successful. */ CompletableFuture teleport(Player player, Island island, Dimension dimension); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCache.java ================================================ package com.bgsoftware.superiorskyblock.api.player.cache; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.function.Function; /** * Player caches can be used by other plugins to store temporary data for a player, retrieve it, etc. * The cache is not persistent between server sessions. For persistent data solution, see {@link SuperiorPlayer#getPersistentDataContainer()} * Data can be stored and retrieved by registering custom {@link PlayerCacheKey} for your plugin. * The cache is thread-safe and can be accessed from multiple threads. */ public interface PlayerCache { /** * Get the player this cache is for. */ SuperiorPlayer getPlayer(); /** * Store data in this cache. * * @param key The key to store. * @param value The value to store. * @return The old value that was stored in the cache, or null if not data was cached. */ @Nullable T store(PlayerCacheKey key, T value); /** * Remove data from this cache. * * @param key The cache key. * @return The old value that was stored in the cache, or null if not data was cached. */ @Nullable T remove(PlayerCacheKey key); /** * Get data that was stored. * * @param key The cache key * @return The value stored for the provided key, or null if no data was cached. */ @Nullable T get(PlayerCacheKey key); /** * Get data that was stored. * * @param key The cache key * @param def The value to return in case the cache did not contain the provided key * @return The value stored for the provided key. */ T getOrDefault(PlayerCacheKey key, T def); /** * Get data that was stored. * * @param key The cache key * @param mappingFunction The value to store in case the cache did not contain the provided key * @return The value stored for the provided key. */ T computeIfAbsent(PlayerCacheKey key, Function, T> mappingFunction); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCacheKey.java ================================================ package com.bgsoftware.superiorskyblock.api.player.cache; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class PlayerCacheKey implements Enumerable { private static final Map> playerCacheKeys = new HashMap<>(); private static int ordinalCounter = 0; private final String name; private final Class valueType; private final int ordinal; private PlayerCacheKey(String name, Class valueType) { this.name = name.toUpperCase(Locale.ENGLISH); this.valueType = valueType; this.ordinal = ordinalCounter++; } /** * Get the name of the player cache key. */ public String getName() { return name; } /** * Get the type of the value for this cache-key. */ public Class getValueType() { return valueType; } @Override public int ordinal() { return this.ordinal; } @Override public String toString() { return "PlayerCacheKey{name=" + name + "}"; } /** * Get all the player cache keys. */ public static Collection> values() { return playerCacheKeys.values(); } /** * Get an player cache key by its name. * * @param name The name to check. */ public static PlayerCacheKey getByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); PlayerCacheKey playerCacheKey = playerCacheKeys.get(name.toUpperCase(Locale.ENGLISH)); Preconditions.checkNotNull(playerCacheKey, "Couldn't find an PlayerCacheKey with the name " + name + "."); return playerCacheKey; } /** * Register a new player cache key. * * @param name The name for the player cache key. */ public static void register(String name, Class valueType) { Preconditions.checkNotNull(name, "name parameter cannot be null."); name = name.toUpperCase(Locale.ENGLISH); Preconditions.checkState(!playerCacheKeys.containsKey(name), "PlayerCacheKey with the name " + name + " already exists."); playerCacheKeys.put(name, new PlayerCacheKey<>(name, valueType)); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/container/DelegatePlayersContainer.java ================================================ package com.bgsoftware.superiorskyblock.api.player.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.List; import java.util.UUID; public class DelegatePlayersContainer implements PlayersContainer { protected final PlayersContainer handle; protected DelegatePlayersContainer(PlayersContainer handle) { this.handle = handle; } @Nullable @Override public SuperiorPlayer getSuperiorPlayer(String name) { return this.handle.getSuperiorPlayer(name); } @Nullable @Override public SuperiorPlayer getSuperiorPlayer(UUID uuid) { return this.handle.getSuperiorPlayer(uuid); } @Override public List getAllPlayers() { return this.handle.getAllPlayers(); } @Override public void addPlayer(SuperiorPlayer superiorPlayer) { this.handle.addPlayer(superiorPlayer); } @Override public void removePlayer(SuperiorPlayer superiorPlayer) { this.handle.removePlayer(superiorPlayer); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/container/PlayersContainer.java ================================================ package com.bgsoftware.superiorskyblock.api.player.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.List; import java.util.UUID; public interface PlayersContainer { /** * Get a player by its name. * * @param name The name of the player. */ @Nullable SuperiorPlayer getSuperiorPlayer(String name); /** * Get a player by its uuid. * * @param uuid The uuid of the player. */ @Nullable SuperiorPlayer getSuperiorPlayer(UUID uuid); /** * Get all the players. */ List getAllPlayers(); /** * Add a player to the container. * * @param superiorPlayer The player to add. */ void addPlayer(SuperiorPlayer superiorPlayer); /** * Remove a player from the container. * * @param superiorPlayer The player to remove. */ void removePlayer(SuperiorPlayer superiorPlayer); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/inventory/ClearAction.java ================================================ package com.bgsoftware.superiorskyblock.api.player.inventory; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import org.bukkit.entity.Player; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public abstract class ClearAction implements Enumerable { private static final Map clearActions = new HashMap<>(); private static int ordinalCounter = 0; private final String name; private final int ordinal; protected ClearAction(String name) { Preconditions.checkArgument(!clearActions.containsKey(name), "name already exists."); this.name = name.toUpperCase(Locale.ENGLISH); this.ordinal = ordinalCounter++; } @Override public final int ordinal() { return this.ordinal; } /** * Get the name of the clear action. */ public final String getName() { return name; } /** * Execute this {@link ClearAction} on the player {@param player}; * * @param player The player to run the clear action on. * The player instance might be fake for offline players. * Do not save it elsewhere, only run actions that change its data. */ public abstract void doClear(Player player); @Override public String toString() { return "ClearAction{name=" + name + "}"; } /** * Get all the clear actions. */ public static Collection values() { return clearActions.values(); } /** * Get a clear action by its name. * * @param name The name to check. */ public static ClearAction getByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); ClearAction clearAction = clearActions.get(name.toUpperCase(Locale.ENGLISH)); Preconditions.checkNotNull(clearAction, "Couldn't find an ClearAction with the name " + name + "."); return clearAction; } /** * Register a new clear action. * * @param clearAction The clear action to register. */ public static void register(ClearAction clearAction) { Preconditions.checkNotNull(clearAction, "clearAction parameter cannot be null."); String name = clearAction.getName().toUpperCase(Locale.ENGLISH); Preconditions.checkState(!clearActions.containsKey(name), "ClearAction with the name " + name + " already exists."); clearActions.put(name, clearAction); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/player/respawn/RespawnAction.java ================================================ package com.bgsoftware.superiorskyblock.api.player.respawn; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import org.bukkit.event.player.PlayerRespawnEvent; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public abstract class RespawnAction implements Enumerable { private static final Map respawnActions = new HashMap<>(); private static int ordinalCounter = 0; private final String name; private final int ordinal; protected RespawnAction(String name) { Preconditions.checkArgument(!respawnActions.containsKey(name), "name already exists."); this.name = name.toUpperCase(Locale.ENGLISH); this.ordinal = ordinalCounter++; } @Override public final int ordinal() { return this.ordinal; } /** * Get the name of the respawn action. */ public final String getName() { return name; } @Override public String toString() { return "RespawnAction{name=" + name + "}"; } public abstract boolean canPerform(PlayerRespawnEvent event); public abstract void perform(PlayerRespawnEvent event); /** * Get all the respawn actions. */ public static Collection values() { return respawnActions.values(); } /** * Get a respawn action by its name. * * @param name The name to check. */ public static RespawnAction getByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); RespawnAction respawnAction = respawnActions.get(name.toUpperCase(Locale.ENGLISH)); Preconditions.checkNotNull(respawnAction, "Couldn't find an RespawnAction with the name " + name + "."); return respawnAction; } /** * Register a new respawn action. * * @param respawnAction The respawn action to register. */ public static void register(RespawnAction respawnAction) { Preconditions.checkNotNull(respawnAction, "respawnAction parameter cannot be null."); String name = respawnAction.getName().toUpperCase(Locale.ENGLISH); Preconditions.checkState(!respawnActions.containsKey(name), "RespawnAction with the name " + name + " already exists."); respawnActions.put(name, respawnAction); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/Schematic.java ================================================ package com.bgsoftware.superiorskyblock.api.schematic; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import org.bukkit.Location; import java.util.Map; import java.util.function.Consumer; public interface Schematic { /** * Get the name of the schematic. */ String getName(); /** * Paste te schematic in a specific location. * * @param island The island of the schematic. * @param location The location to paste the schematic at. * @param callback A callback runnable that runs when the process finishes */ void pasteSchematic(Island island, Location location, Runnable callback); /** * Paste te schematic in a specific location. * * @param island The island of the schematic. * @param location The location to paste the schematic at. * @param callback A callback runnable that runs when the process finishes * @param onFailure A consumer that will be ran if the creation fails. */ void pasteSchematic(Island island, Location location, Runnable callback, @Nullable Consumer onFailure); /** * Adjust schematic's rotations to the given location. * * @param location The location to adjust. * @return The exact same object given as a parameter. */ Location adjustRotation(Location location); /** * Get the block counts of the schematic. */ Map getBlockCounts(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/SchematicOptions.java ================================================ package com.bgsoftware.superiorskyblock.api.schematic; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; /** * This class represents options for creating schematics. */ public interface SchematicOptions { /** * Get the name of the schematic. */ String getSchematicName(); /** * Get the offset in the x-axis of the schematic. */ int getOffsetX(); /** * Get the offset in the y-axis of the schematic. */ int getOffsetY(); /** * Get the offset in the z-axis of the schematic. */ int getOffsetZ(); /** * Get the yaw of the schematic. */ float getYaw(); /** * Get the pitch of the schematic. */ float getPitch(); /** * Get whether the schematic should save air blocks. */ boolean shouldSaveAir(); /** * Create a new builder for a {@link SchematicOptions} object. * * @param schematicName The name of the schematic to create. */ static Builder newBuilder(String schematicName) { return SuperiorSkyblockAPI.getFactory().createSchematicOptionsBuilder(schematicName); } interface Builder { default Builder setOffsetX(int offsetX) { return setOffset(offsetX, 0, 0); } default Builder setOffsetY(int offsetY) { return setOffset(0, offsetY, 0); } default Builder setOffsetZ(int offsetZ) { return setOffset(0, 0, offsetZ); } Builder setOffset(int offsetX, int offsetY, int offsetZ); default Builder setYaw(float yaw) { return setDirection(yaw, 0f); } default Builder setPitch(float pitch) { return setDirection(0f, pitch); } Builder setDirection(float yaw, float pitch); Builder setSaveAir(boolean saveAir); SchematicOptions build(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/parser/SchematicParseException.java ================================================ package com.bgsoftware.superiorskyblock.api.schematic.parser; import java.io.DataInputStream; /** * This exception is used inside {@link SchematicParser#parseSchematic(DataInputStream, String)} * when a faulty stream is given to the parser. */ public class SchematicParseException extends Exception { public SchematicParseException(String error) { super(error); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/parser/SchematicParser.java ================================================ package com.bgsoftware.superiorskyblock.api.schematic.parser; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import java.io.DataInputStream; public interface SchematicParser { /** * Parse a schematic from a stream. * * @param inputStream The stream to parse the schematic from. * @param schematicName The name of the schematic. * @return A new {@link Schematic} object from the stream. * @throws SchematicParseException If the stream doesn't meet the format of this parser. */ Schematic parseSchematic(DataInputStream inputStream, String schematicName) throws SchematicParseException; } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/scripts/IScriptEngine.java ================================================ package com.bgsoftware.superiorskyblock.api.scripts; import javax.script.Bindings; import javax.script.ScriptException; public interface IScriptEngine { /** * Evaluate an expression. * * @param expression The expression to evaluate. * @return The result of the expression. * @throws ScriptException If the format of the expression is invalid. */ Object eval(String expression) throws ScriptException; /** * Evaluate an expression. * * @param expression The expression to evaluate. * @param bindings A bindings map for the expression. * @return The result of the expression. * @throws ScriptException If the format of the expression is invalid. */ Object eval(String expression, Bindings bindings) throws ScriptException; } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/bossbar/BossBar.java ================================================ package com.bgsoftware.superiorskyblock.api.service.bossbar; import org.bukkit.entity.Player; public interface BossBar { /** * Display this boss-bar to a player. * * @param player The player to display the boss-bar to. */ void addPlayer(Player player); /** * Stop displaying this boss-bar to all the players. */ void removeAll(); /** * Set the progress bar of this boss-bar. * * @param progress The progress to set. */ void setProgress(double progress); /** * Get the progress bar of this boss-bar. */ double getProgress(); enum Color { PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/bossbar/BossBarsService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.bossbar; import org.bukkit.entity.Player; public interface BossBarsService { /** * Create a new boss-bar. * * @param player The player to create the boss-bar for. * @param message The message to display in the boss-bar. * @param color The color of the boss-bar. * @param ticksToRun The time to run the boss-bar. * If set to 0 or below, it will stay forever. */ BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/dragon/DragonBattleResetResult.java ================================================ package com.bgsoftware.superiorskyblock.api.service.dragon; public enum DragonBattleResetResult { /** * The dragon battle could not be reset because they are disabled on the server. */ DRAGON_BATTLES_DISABLED, /** * The dragon battle could not be reset because the world was never generated before. */ WORLD_NOT_GENERATED, /** * The dragon battle could not be reset because the world is not unlocked for the island. */ WORLD_NOT_UNLOCKED, /** * The dragon battle was successfully been reset. */ SUCCESS } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/dragon/DragonBattleService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.World; import org.bukkit.entity.EnderDragon; public interface DragonBattleService { /** * Prepare an end world for dragon fights. * * @param world The world to prepare. */ void prepareEndWorld(World world); /** * Get the current active ender dragon of an island. * If there is no active fight, null is returned. * * @param island The island to get the dragon for. */ @Nullable EnderDragon getEnderDragon(Island island, Dimension dimension); /** * Stop the dragon battle fight for an island. * The dragon will be killed and {@link #getEnderDragon(Island, Dimension)} will return null. */ void stopEnderDragonBattle(Island island, Dimension dimension); /** * Reset the dragon battle fight for an island. * * @param island The island to reset the fight for. */ DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension dimension); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/hologram/Hologram.java ================================================ package com.bgsoftware.superiorskyblock.api.service.hologram; import org.bukkit.entity.ArmorStand; public interface Hologram { /** * Set the name to be displayed for this hologram. * * @param name The new name to set. */ void setHologramName(String name); /** * Remove the hologram from existence. */ void removeHologram(); /** * Get the actual armor stand entity for this hologram. * This is a custom armor stand for the hologram, and therefore it may not function * similar to Bukkit's regular entities. */ ArmorStand getHandle(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/hologram/HologramsService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.hologram; import org.bukkit.Location; import org.bukkit.entity.Entity; public interface HologramsService { /** * Create a new hologram. * * @param location The location of the new hologram. * @return The new created hologram. */ Hologram createHologram(Location location); /** * Checks whether an entity is a hologram. * * @param entity The entity to check. */ boolean isHologram(Entity entity); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/message/IMessageComponent.java ================================================ package com.bgsoftware.superiorskyblock.api.service.message; import org.bukkit.command.CommandSender; public interface IMessageComponent { /** * Get the type of this component. */ Type getType(); /** * Get the raw message of this component. * * @deprecated See {@link #getMessage(Object...)} */ @Deprecated String getMessage(); /** * Get the raw message of this component. */ default String getMessage(Object... args) { return getMessage(); } /** * Send this message to a {@link CommandSender}. * * @param sender The {@link CommandSender} to send the message to. * @param args The arguments of the message. */ void sendMessage(CommandSender sender, Object... args); enum Type { /** * The component represents an action bar. */ ACTION_BAR, /** * The component represents a boss bar. */ BOSS_BAR, /** * The component represents a complex message. * Complex messages are raw text that can be sent to players, however they have extra functionalities, * such as clickable messages, hover messages, etc. */ COMPLEX_MESSAGE, /** * The component represents an empty message. * This type of component is used when the message of the component is empty or invalid. */ EMPTY, /** * The component represents multiple components. * This type of component is a container for different other components inside it. This gives the ability * to combine different component types for the same message - for example, sending a message while playing * a sound. Therefore, by calling {@link #sendMessage(CommandSender, Object...)} on it, all the components it contains * will be sent at the same time. */ MULTIPLE, /** * The component represents a raw text message. */ RAW_MESSAGE, /** * The component represents a sound. * When sending this component, a sound will be played instead of a message to be sent. */ SOUND, /** * The component represents a title. * Titles are the big text that can be shown in the middle of the screen of a player. */ TITLE } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/message/MessagesService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.message; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Sound; import org.bukkit.configuration.file.YamlConfiguration; import java.util.Locale; public interface MessagesService { /** * Parse a message from config file into a message component. * * @param config The configuration file. * @param path The path of the message. * @return the parsed component message. */ IMessageComponent parseComponent(YamlConfiguration config, String path); /** * Get a component of a built-in message of the plugin. * * @param message The name of the message, similar to its name in the lang file of the plugin. * @param locale The locale to retrieve the message for. * For player's locale, use {@link SuperiorPlayer#getUserLocale()} */ @Nullable IMessageComponent getComponent(String message, Locale locale); /** * Create a new builder for message components. */ Builder newBuilder(); /** * Builder class for creating {@link IMessageComponent}s */ interface Builder { /** * Add an action bar text to the message component. * * @param message The action bar text. * @return true if the action bar was successfully added. */ boolean addActionBar(@Nullable String message); /** * Add boss bar to the message component. * * @param message The text to be displayed in the boss bar * @param color The color of the boss bar * @param ticks The duration of the boss bar, in ticks. * @return true if the boss bar was successfully added. */ boolean addBossBar(@Nullable String message, BossBar.Color color, int ticks); /** * Add a complex message to the message component. * * @param textComponent The text component. * @return true if the complex message was successfully added. */ boolean addComplexMessage(@Nullable TextComponent textComponent); /** * Add a complex message to the message component. * * @param baseComponents The base components of the message. * @return true if the complex message was successfully added. */ boolean addComplexMessage(@Nullable BaseComponent[] baseComponents); /** * Add a raw message to the message component. * * @param message The raw text. * @return true if the raw message was successfully added. */ boolean addRawMessage(@Nullable String message); /** * Add a sound to the message component. * * @param sound The sound to be played. * @param volume The volume of the sound. * @param pitch The pitch of the sound. * @return true if the sound was successfully added. */ boolean addSound(Sound sound, float volume, float pitch); /** * Add a title to the message component. * * @param titleMessage The first line of the title. * @param subtitleMessage The second line of the title. * @param fadeIn The duration of the fade in animation, in ticks. * @param duration The duration of the title to last, in ticks. * @param fadeOut The duration of the fade out animation, in ticks. * @return true if the title was successfully added. */ boolean addTitle(@Nullable String titleMessage, @Nullable String subtitleMessage, int fadeIn, int duration, int fadeOut); /** * Add another message component to the message component. * * @param messageComponent The other message component to add. * @return true if the message component was successfully added. */ boolean addMessageComponent(IMessageComponent messageComponent); /** * Build a new message component from the given builder. */ IMessageComponent build(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/placeholders/IslandPlaceholderParser.java ================================================ package com.bgsoftware.superiorskyblock.api.service.placeholders; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.function.BiFunction; /** * This class represents an island placeholder parser. * It should give an output of the parsed value for an island. */ public interface IslandPlaceholderParser extends BiFunction { /** * Get the result of this placeholder for the given island. * * @param island The island to parse. * @param superiorPlayer The player that requested the placeholder. * @return The parsed result. */ @Override @Nullable String apply(@Nullable Island island, SuperiorPlayer superiorPlayer); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/placeholders/PlaceholdersService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.placeholders; import org.bukkit.OfflinePlayer; public interface PlaceholdersService { /** * Parse placeholders in a given string. * * @param offlinePlayer The player to parse placeholders to. * @param value The string to parse. * @return The same string with the placeholders after they were parsed. */ String parsePlaceholders(OfflinePlayer offlinePlayer, String value); /** * Register a new placeholder. * * @param placeholderName The name of the placeholder. * The name is the part in the placeholder after the prefix (`superior_`) * @param placeholderFunction The parser to run when the placeholder is evaluated. * It is recommended to cache all values return by the placeholder for best performance. */ void registerPlaceholder(String placeholderName, IslandPlaceholderParser placeholderFunction); /** * Register a new placeholder. * * @param placeholderName The name of the placeholder. * The name is the part in the placeholder after the prefix (`superior_`) * @param placeholderFunction The parser to run when the placeholder is evaluated. * It is recommended to cache all values return by the placeholder for best performance. */ void registerPlaceholder(String placeholderName, PlayerPlaceholderParser placeholderFunction); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/placeholders/PlayerPlaceholderParser.java ================================================ package com.bgsoftware.superiorskyblock.api.service.placeholders; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.function.Function; /** * This class represents a player placeholder parser. * It should give an output of the parsed value for a player. */ public interface PlayerPlaceholderParser extends Function { /** * Get the result of this placeholder for the given player. * * @param superiorPlayer The player that requested the placeholder. * @return The parsed result. */ @Nullable @Override String apply(SuperiorPlayer superiorPlayer); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/portals/EntityPortalResult.java ================================================ package com.bgsoftware.superiorskyblock.api.service.portals; import com.bgsoftware.superiorskyblock.api.events.IslandEnterPortalEvent; public enum EntityPortalResult { /** * The player is immuned to portal teleports. */ PLAYER_IMMUNED_TO_PORTAL, /** * The portal is not inside an island. */ PORTAL_NOT_IN_ISLAND, /** * The player cannot enter the island the portal leads to. */ DESTINATION_ISLAND_NOT_PERMITTED, /** * The world the portal leads to is not an islands world. */ DESTINATION_NOT_ISLAND_WORLD, /** * The world the portal leads to is disabled. */ DESTINATION_WORLD_DISABLED, /** * The world the portal leads to is not unlocked for the island. */ WORLD_NOT_UNLOCKED, /** * The schematic for the destination world is being generated. */ SCHEMATIC_GENERATING_COOLDOWN, /** * The {@link IslandEnterPortalEvent} event that had been fired was cancelled. */ PORTAL_EVENT_CANCELLED, /** * There is no valid schematic for the destination world. */ INVALID_SCHEMATIC, /** * The entity went through the portal successfully. */ SUCCEED } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/portals/PortalsManagerService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.portals; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.entity.Entity; public interface PortalsManagerService { /** * Handle a player going through a portal. * * @param superiorPlayer The player that entered the portal. * @param portalLocation The location of the portal. * @param portalType The type of the portal. * @param destinationLocation The location that the player should be teleported to. * @param checkImmunedPortalsStatus Whether to check if the player is immuned to portal teleports. * @return The result of going through the portal. */ EntityPortalResult handlePlayerPortal(SuperiorPlayer superiorPlayer, Location portalLocation, PortalType portalType, Location destinationLocation, boolean checkImmunedPortalsStatus); /** * Handle an entity going through a portal. * * @param entity The entity that entered the portal. * @param portalLocation The location of the portal. * @param portalType The type of the portal. * @param destinationLocation The location that the player should be teleported to. * @return The result of going through the portal. */ EntityPortalResult handleEntityPortal(Entity entity, Location portalLocation, PortalType portalType, Location destinationLocation); /** * Handle a player going through a portal on an island. * * @param superiorPlayer The player that entered the portal. * @param island The island the portal is inside. * @param portalLocation The location of the portal. * @param portalType The type of the portal. * @param checkImmunedPortalsStatus Whether to check if the player is immuned to portal teleports. * @return The result of going through the portal. */ EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island, Location portalLocation, PortalType portalType, boolean checkImmunedPortalsStatus); /** * Handle a player going through a portal on an island. * * @param superiorPlayer The player that entered the portal. * @param island The island the portal is inside. * @param portalLocation The location of the portal. * @param portalType The type of the portal. * @param checkImmunedPortalsStatus Whether to check if the player is immuned to portal teleports. * @param destinationLocation The location that the player should be teleported to. * @return The result of going through the portal. */ EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island, Location portalLocation, PortalType portalType, Location destinationLocation, boolean checkImmunedPortalsStatus); /** * Handle an entity going through a portal on an island. * * @param entity The entity that entered the portal. * @param island The island the portal is inside. * @param portalLocation The location of the portal. * @param portalType The type of the portal. * @return The result of going through the portal. */ EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, PortalType portalType); /** * Handle an entity going through a portal on an island. * * @param entity The entity that entered the portal. * @param island The island the portal is inside. * @param portalLocation The location of the portal. * @param portalType The type of the portal. * @param destinationLocation The location that the player should be teleported to. * @return The result of going through the portal. */ EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, PortalType portalType, Location destinationLocation); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/InteractionResult.java ================================================ package com.bgsoftware.superiorskyblock.api.service.region; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; public enum InteractionResult { /** * The interaction was made outside an island. */ OUTSIDE_ISLAND, /** * The player is missing an {@link IslandPrivilege} for doing the interaction. */ MISSING_PRIVILEGE, /** * The interaction that was made cannot be done while the island is being recalculated. */ ISLAND_RECALCULATE, /** * The interaction can be done. */ SUCCESS } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/MoveResult.java ================================================ package com.bgsoftware.superiorskyblock.api.service.region; import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; public enum MoveResult { /** * The player cannot do the movement as he is banned from the island. */ BANNED_FROM_ISLAND, /** * The player cannot do the movement as the island is locked to the public. */ ISLAND_LOCKED, /** * The {@link IslandEnterEvent} event was cancelled. */ ENTER_EVENT_CANCELLED, /** * The player cannot move out of an island into the wilderness. */ LEAVE_ISLAND_TO_OUTSIDE, /** * The player was moved too far away while being in island-preview mode. */ ISLAND_PREVIEW_MOVED_TOO_FAR, /** * The player was teleported due to void-teleport. */ VOID_TELEPORT, /** * The player can do the movement. */ SUCCESS } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/RegionManagerService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.region; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.inventory.ItemStack; public interface RegionManagerService { /** * Handle a block being placed. * * @param superiorPlayer The player that placed the block. * @param block The block that was placed. * @return The result of the interaction. */ InteractionResult handleBlockPlace(SuperiorPlayer superiorPlayer, Block block); /** * Handle a block being broken. * * @param superiorPlayer The player that broke the block. * @param block The block that was broken. * @return The result of the interaction. */ InteractionResult handleBlockBreak(SuperiorPlayer superiorPlayer, Block block); /** * Handle a player interacting with a block. * * @param superiorPlayer The player that made the interaction. * @param block The block that the player interacted with. * @param action The action that the player did. * @param usedItem The item that was used to interact. * @return The result of the interaction. */ InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Block block, Action action, @Nullable ItemStack usedItem); /** * Handle a player fertilizing a block. * * @param superiorPlayer The player that fertilized the block. * @param block The block that was fertilized by the player. * @return The result of the interaction. */ InteractionResult handleBlockFertilize(SuperiorPlayer superiorPlayer, Block block); /** * Handle a player interacting with an entity. * * @param superiorPlayer The player that made the interaction. * @param entity The entity that the player interacted with. * @param usedItem The item that was used to interact. * @return The result of the interaction. */ InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Entity entity, @Nullable ItemStack usedItem); /** * Handle a player shearing an entity. * * @param superiorPlayer The player that sheared the entity. * @param entity The entity that was sheared. * @return The result of the interaction. */ InteractionResult handleEntityShear(SuperiorPlayer superiorPlayer, Entity entity); /** * Handle a player leashing an entity. * * @param superiorPlayer The player that leashed the entity. * @param entity The entity that was leashed. * @return The result of the interaction. */ InteractionResult handleEntityLeash(SuperiorPlayer superiorPlayer, Entity entity); /** * Handle a player picking up an item. * * @param superiorPlayer The player that picked up the item. * @param item The item that was picked up. * @return The result of the interaction. */ InteractionResult handlePlayerPickupItem(SuperiorPlayer superiorPlayer, Item item); /** * Handle a player dropping an item. * * @param superiorPlayer The player that dropped the item. * @param item The item that was dropped. * @return The result of the interaction. */ InteractionResult handlePlayerDropItem(SuperiorPlayer superiorPlayer, Item item); /** * Handle a player using an ender pearl. * * @param superiorPlayer The player that used the ender pearl. * @param destination The location of the teleportation of the ender pearl. * @return The result of the interaction. */ InteractionResult handlePlayerEnderPearl(SuperiorPlayer superiorPlayer, Location destination); /** * Handle a player consuming a Chorus Fruit. * * @param superiorPlayer The player that consumed the Chorus Fruit. * @param location The location of the player. * @return The result of the interaction. */ InteractionResult handlePlayerConsumeChorusFruit(SuperiorPlayer superiorPlayer, Location location); /** * Handle a player using a wind charge. * * @param superiorPlayer The player that used the wind charge. * @param location The location of the player. * @return The result of the interaction. */ InteractionResult handlePlayerUseWindCharge(SuperiorPlayer superiorPlayer, Location location); /** * Handle an entity damaging another entity. * * @param damager The entity that dealt the damage. * @param entity The entity that was damaged. * @return The result of the interaction. */ InteractionResult handleEntityDamage(Entity damager, Entity entity); /** * Handle a player riding an entity. * * @param superiorPlayer The player that rides the entity. * @param vehicle The entity that is ridden. * @return The result of the interaction. */ InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity vehicle); /** * Handle a custom interaction of a player. * * @param superiorPlayer The player that made the interaction. * @param location The location of the interaction. * @param islandPrivilege The privilege required for doing the interaction. * @return The result of the interaction. */ InteractionResult handleCustomInteraction(SuperiorPlayer superiorPlayer, Location location, IslandPrivilege islandPrivilege); /** * Handle a player movement. * * @param superiorPlayer The player that made the movement. * @param from The location of the player. * @param to The new location of the player after the movement. * @return The result of the movement. */ MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Location to); /** * Handle a player teleportation. * * @param superiorPlayer The player that made the teleportation. * @param from The location of the player. * @param to The new location of the player after the teleportation. * @return The result of the teleportation. */ MoveResult handlePlayerTeleport(SuperiorPlayer superiorPlayer, Location from, Location to); /** * Handle a player teleportation by a portal. * * @param superiorPlayer The player that made the teleportation. * @param portalLocation The location of the portal. * @param teleportLocation The new location of the player after the teleportation. * @return The result of the teleportation. */ MoveResult handlePlayerTeleportByPortal(SuperiorPlayer superiorPlayer, Location portalLocation, Location teleportLocation); /** * Handle a player joining the server. * * @param superiorPlayer The player that joined the server. * @param location The location of the player. * @return The result of joining the server. */ MoveResult handlePlayerJoin(SuperiorPlayer superiorPlayer, Location location); /** * Handle a player leaving the server. * * @param superiorPlayer The player that left the server. * @param location The location of the player. * @return The result of leaving the server. */ MoveResult handlePlayerQuit(SuperiorPlayer superiorPlayer, Location location); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/stackedblocks/InteractionResult.java ================================================ package com.bgsoftware.superiorskyblock.api.service.stackedblocks; import com.bgsoftware.superiorskyblock.api.events.BlockStackEvent; import com.bgsoftware.superiorskyblock.api.events.BlockUnstackEvent; public enum InteractionResult { /** * The stacked-blocks system is disabled. */ STACKED_BLOCKS_DISABLED, /** * The world that the player tries to stack blocks in is disabled for stacking blocks. */ DISABLED_WORLD, /** * The player has toggled off his ability to stack blocks. */ PLAYER_STACKED_BLOCKS_DISABLED, /** * The used item to stack the block has a name or a lore, and cannot be used to stack blocks. */ CUSTOMIZED_ITEM, /** * The item used by the player to stack blocks is different from the block. */ PLAYER_HOLDING_DIFFERENT_ITEM, /** * The player does not have the permission to stack this type of block. */ PLAYER_MISSING_PERMISSION, /** * The block cannot be stacked as it is not whitelisted. */ STACKED_BLOCK_NOT_WHITELISTED, /** * The player does not have enough items in his inventory in order to stack the blocks. */ NOT_ENOUGH_BLOCKS, /** * The event that had been fired ({@link BlockStackEvent}, {@link BlockUnstackEvent}) was cancelled. */ EVENT_CANCELLED, /** * An unexpected behavior occurred and the plugin prevented the block from being stacked. */ GLITCHED_STACKED_BLOCK, /** * The block that was being unstacked is not an actual stacked block. */ NOT_STACKED_BLOCK, /** * The block is protected by another island. */ STACKED_BLOCK_PROTECTED, /** * The block was successfully stacked or unstacked. */ SUCCESS } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/stackedblocks/StackedBlocksInteractionService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.stackedblocks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; public interface StackedBlocksInteractionService { /** * Handle a stacked block being placed. * * @param superiorPlayer The player that stacked the block. * @param block The block to stack into. * @param usedHand The hand that was used when placing the block. * @return The result of stacking the block. */ InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, Block block, EquipmentSlot usedHand); /** * Handle a stacked block being placed. * * @param superiorPlayer The player that stacked the block. * @param block The block to stack into. * @param amountToDeposit The amount of blocks that were stacked. * @param itemRemovalCallback Callback to remove items from the inventory of the player. * @return The result of stacking the block. */ InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, Block block, int amountToDeposit, OnItemRemovalCallback itemRemovalCallback); /** * Check if a block can be stacked. * * @param superiorPlayer The player that stacked the block. * @param block The block to stack into. * @param itemStack The item that is used to stack into the block. * @return The result of stacking the block. */ InteractionResult checkStackedBlockInteraction(SuperiorPlayer superiorPlayer, Block block, ItemStack itemStack); /** * Handle a stacked block being broken. * * @param block The block to unstack from. * @param superiorPlayer The player that unstacked the block, if exists. * @return The result of unstacking the block. */ InteractionResult handleStackedBlockBreak(Block block, @Nullable SuperiorPlayer superiorPlayer); /** * Callback for removing items from the inventory when stacking blocks. * Used in {@link #handleStackedBlockPlace(SuperiorPlayer, Block, int, OnItemRemovalCallback)} */ interface OnItemRemovalCallback { void accept(int amount); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/world/RecordResult.java ================================================ package com.bgsoftware.superiorskyblock.api.service.world; public enum RecordResult { /** * The action was not done inside an island. */ NOT_IN_ISLAND, /** * The entity cannot be tracked. */ ENTITY_CANNOT_BE_TRACKED, /** * The action was successfully recorded. */ SUCCESS } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/world/WorldRecordFlags.java ================================================ package com.bgsoftware.superiorskyblock.api.service.world; import com.bgsoftware.common.annotations.IntType; /** * The integer value element annotated with {@link WorldRecordFlags} represents flags related to what to do * when block change is recorded. It is mainly used within the {@link WorldRecordService} interface and its methods. */ @IntType({WorldRecordFlags.SAVE_BLOCK_COUNT, WorldRecordFlags.DIRTY_CHUNKS, WorldRecordFlags.HANDLE_NEARBY_BLOCKS}) public @interface WorldRecordFlags { /** * Save the new block count after the block change. */ int SAVE_BLOCK_COUNT = 1 << 0; /** * Mark dirty chunks status for changes in chunks. */ int DIRTY_CHUNKS = 1 << 1; /** * Check for nearby block changes. * Only handled when breaking blocks to check for nearby block changes that * were affected by the breaking of the block. */ int HANDLE_NEARBY_BLOCKS = 1 << 2; } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/service/world/WorldRecordService.java ================================================ package com.bgsoftware.superiorskyblock.api.service.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; public interface WorldRecordService { /** * Record a block place. * * @param block The block that was placed. * @param blockCount The amount of blocks that were placed. * @param oldBlockState The state of the block before placing the new one. * @param flags See {@link WorldRecordFlags} * @return The result of recording the block placement. */ RecordResult recordBlockPlace(Block block, int blockCount, @Nullable BlockState oldBlockState, @WorldRecordFlags int flags); /** * Record a block place. * * @param blockKey The key of the block that was placed. * @param blockLocation The location of the block. * @param blockCount The amount of blocks that were placed. * @param oldBlockState The state of the block before placing the new one. * @param flags See {@link WorldRecordFlags} * @return The result of recording the block placement. */ RecordResult recordBlockPlace(Key blockKey, Location blockLocation, int blockCount, @Nullable BlockState oldBlockState, @WorldRecordFlags int flags); /** * Record multiple block placements. * * @param blockCounts KeyMap containing the counts of the blocks that were placed. * @param location The location of where the blocks were placed at. * @param flags See {@link WorldRecordFlags} * @return The result of recording the block placements. */ RecordResult recordMultiBlocksPlace(KeyMap blockCounts, Location location, @WorldRecordFlags int flags); /** * Record a block break. * * @param block The block that was broken * @param flags See {@link WorldRecordFlags} * @return The result of recording the block break. */ RecordResult recordBlockBreak(Block block, @WorldRecordFlags int flags); /** * Record a block break. * * @param block The block that was broken. * @param blockCount The amount of blocks that were broken. * @param flags See {@link WorldRecordFlags} * @return The result of recording the block break. */ RecordResult recordBlockBreak(Block block, int blockCount, @WorldRecordFlags int flags); /** * Record a block break. * * @param blockKey The key of the block that was broken. * @param blockLocation The location of the block. * @param blockCount The amount of blocks that were broken. * @param flags See {@link WorldRecordFlags} * @return The result of recording the block break. */ RecordResult recordBlockBreak(Key blockKey, Location blockLocation, int blockCount, @WorldRecordFlags int flags); /** * Record multiple block breaks. * * @param blockCounts KeyMap containing the counts of the blocks that were broken. * @param location The location of where the blocks were broken at. * @param flags See {@link WorldRecordFlags} * @return The result of recording the block breaks. */ RecordResult recordMultiBlocksBreak(KeyMap blockCounts, Location location, @WorldRecordFlags int flags); /** * Record an entity spawning into the world. * * @param entity The entity that spawned. * @return The result of recording the entity spawn. */ RecordResult recordEntitySpawn(Entity entity); /** * Record an entity spawning into the world. * * @param entityType The type of the entity that spawned. * @param location The location of where the entity was spawned. * @return The result of recording the entity spawn. */ RecordResult recordEntitySpawn(EntityType entityType, Location location); /** * Record an entity despawning from the world. * * @param entity The entity that despawned. * @return The result of recording the entity despawn. */ RecordResult recordEntityDespawn(Entity entity); /** * Record an entity despawning from the world. * * @param entityType The type of the entity that despawned. * @param location The location of where the entity was despawned. * @return The result of recording the entity despawn. */ RecordResult recordEntityDespawn(EntityType entityType, Location location); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/Upgrade.java ================================================ package com.bgsoftware.superiorskyblock.api.upgrades; import com.bgsoftware.common.annotations.Nullable; import java.util.List; public interface Upgrade { /** * Get the name of the upgrade. */ String getName(); /** * Get the upgrade-level object from a level. * If it doesn't exist, an update level with level 0 will be returned. * * @param level The level to get the object from. */ UpgradeLevel getUpgradeLevel(int level); /** * Get the maximum level that exists for the upgrade. */ int getMaxUpgradeLevel(); /** * Get the slot the upgrade is in the upgrades menu. */ @Deprecated int getSlot(); /** * Get the slots the upgrade is in the upgrades menu. */ List getSlots(); /** * Check whether the upgrade is in the given slot in the upgrades menu. * * @param slot The slot to check. */ boolean isSlot(int slot); /** * Set the slot the upgrade is in the upgrades menu. * * @param slot The slot to set the upgrade item in. */ @Deprecated void setSlot(int slot); /** * Set the slots the upgrade is in the upgrades menu. * * @param slots The slots to set the upgrade item in. */ void setSlots(@Nullable List slots); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java ================================================ package com.bgsoftware.superiorskyblock.api.upgrades; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.World; import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.util.List; import java.util.Map; public interface UpgradeLevel { /** * Get the level of the current upgrade-level. */ int getLevel(); /** * Get the price required to upgrade to the next level. * * @deprecated See getCost() */ @Deprecated double getPrice(); /** * Get the price required to upgrade to the next level. */ UpgradeCost getCost(); /** * Get all commands that will be executed when upgrading to the next level. */ List getCommands(); /** * Get the permission required to upgrade to this level. */ String getPermission(); /** * Check all the custom requirements of the upgrade. * * @param superiorPlayer The player to check the requirements on. * @return The error message for the failed requirements. * If all the requirements were passed, an empty string will be returned. */ String checkRequirements(SuperiorPlayer superiorPlayer); /** * Checks if this level has a custom crop growth multiplier. */ boolean hasCropGrowth(); /** * Get the crop growth multiplier of this level. */ double getCropGrowth(); /** * Checks if this level has a custom spawner rates multiplier. */ boolean hasSpawnerRates(); /** * Get the spawner rates multiplier of this level. */ double getSpawnerRates(); /** * Checks if this level has a custom mob drops multiplier. */ boolean hasMobDrops(); /** * Get the mob drops multiplier of this level. */ double getMobDrops(); /** * Get the limit of a block for this level. * * @param key The block to check. */ int getBlockLimit(Key key); /** * Get the exact limit of a block for this level. * * @param key The block to check. */ int getExactBlockLimit(Key key); /** * Get all the block limits for this level. */ Map getBlockLimits(); /** * Get the limit of an entity for this level. * * @param entityType The entity's type to check. */ int getEntityLimit(EntityType entityType); /** * Get the limit of an entity for this level. * * @param key The key of the entity to check. */ int getEntityLimit(Key key); /** * Get all the entity limits for this level. */ Map getEntityLimitsAsKeys(); /** * Checks if this level has a custom team limit. */ boolean hasTeamLimit(); /** * Get the team limit of this level. */ int getTeamLimit(); /** * Checks if this level has a custom warps limit. */ boolean hasWarpsLimit(); /** * Get the warps limit of this level. */ int getWarpsLimit(); /** * Checks if this level has a custom coop limit. */ boolean hasCoopLimit(); /** * Get the coop players limit of this level. */ int getCoopLimit(); /** * Checks if this level has a custom border size. */ boolean hasBorderSize(); /** * Get the border size of this level. */ int getBorderSize(); /** * Get the generator rate of a block for this level in a specific world. * * @param key The block to check. * @param dimension The world dimension. */ int getGeneratorAmount(Key key, Dimension dimension); /** * Get all the generator rates for this level in a specific world. * * @param dimension The world dimension */ Map getGeneratorAmounts(Dimension dimension); /** * Get the potion effect for this level. * * @param potionEffectType The potion effect to check. */ int getPotionEffect(PotionEffectType potionEffectType); /** * Get all the potion effects for this level. */ Map getPotionEffects(); /** * Checks if this level has a custom bank limit. */ boolean hasBankLimit(); /** * Get the bank limit of this level. */ BigDecimal getBankLimit(); /** * Get a limit of a role for this level. * * @param playerRole The role to check. */ int getRoleLimit(PlayerRole playerRole); /** * Get the role limits of this level. */ Map getRoleLimits(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/cost/UpgradeCost.java ================================================ package com.bgsoftware.superiorskyblock.api.upgrades.cost; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.math.BigDecimal; public interface UpgradeCost { /** * Get the id of this upgrade cost. */ String getId(); /** * Get the cost value. */ BigDecimal getCost(); /** * Check whether or not the player has enough money in his bank. * * @param superiorPlayer The player to check. */ boolean hasEnoughBalance(SuperiorPlayer superiorPlayer); /** * Withdraw the cost value from the player. * * @param superiorPlayer The player to withdraw from. */ void withdrawCost(SuperiorPlayer superiorPlayer); /** * Clone this cost with a new cost value. * * @param cost The new cost value */ UpgradeCost clone(BigDecimal cost); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/cost/UpgradeCostLoadException.java ================================================ package com.bgsoftware.superiorskyblock.api.upgrades.cost; import org.bukkit.configuration.ConfigurationSection; /** * This exception is used inside {@link UpgradeCostLoader#loadCost(ConfigurationSection)} * when a faulty configuration is given for the loader. */ public class UpgradeCostLoadException extends Exception { public UpgradeCostLoadException(String message) { super(message); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/cost/UpgradeCostLoader.java ================================================ package com.bgsoftware.superiorskyblock.api.upgrades.cost; import org.bukkit.configuration.ConfigurationSection; public interface UpgradeCostLoader { /** * Load a cost from a configuration section. * * @param upgradeSection The section to load the cost from. * @throws UpgradeCostLoadException when an issue occurred when loading the cost. */ UpgradeCost loadCost(ConfigurationSection upgradeSection) throws UpgradeCostLoadException; } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/world/Dimension.java ================================================ package com.bgsoftware.superiorskyblock.api.world; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import org.bukkit.World; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class Dimension implements Enumerable { private static final Map dimensions = new HashMap<>(); private static int ordinalCounter = 0; private final String name; private final World.Environment environment; private final int ordinal; private Dimension(String name, World.Environment environment) { this.name = name.toUpperCase(Locale.ENGLISH); this.environment = environment; this.ordinal = ordinalCounter++; } @Override public int ordinal() { return this.ordinal; } /** * Get the environment of the world. */ public World.Environment getEnvironment() { return environment; } /** * Get all the dimensions.. */ public static Collection values() { return dimensions.values(); } /** * Get a dimension by its name. * * @param name The name to check. */ public static Dimension getByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Dimension dimension = dimensions.get(name.toUpperCase(Locale.ENGLISH)); Preconditions.checkNotNull(dimension, "Couldn't find a Dimension with the name " + name + "."); return dimension; } /** * Register a new dimension. * * @param name The name for the dimension. * @param environment The environment of the world this dimension refers to. */ public static void register(String name, World.Environment environment) { Preconditions.checkNotNull(name, "name parameter cannot be null."); name = name.toUpperCase(Locale.ENGLISH); Preconditions.checkState(!dimensions.containsKey(name), "Dimension with the name " + name + " already exists."); dimensions.put(name, new Dimension(name, environment)); } /** * Get the name of the dimension. */ public String getName() { return name; } @Override public String toString() { return "Dimension{name=" + name + ",environment=" + environment + "}"; } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/world/GameSound.java ================================================ package com.bgsoftware.superiorskyblock.api.world; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.google.common.base.Preconditions; import org.bukkit.Sound; public interface GameSound { Sound getSound(); float getVolume(); float getPitch(); static GameSound of(Sound sound, float volume, float pitch) { Preconditions.checkNotNull(sound, "sound parameter cannot be null"); return SuperiorSkyblockAPI.getFactory().createGameSound(sound, volume, pitch); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/world/WorldInfo.java ================================================ package com.bgsoftware.superiorskyblock.api.world; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.google.common.base.Preconditions; import org.bukkit.World; public interface WorldInfo { /** * Get the name of this world. */ String getName(); /** * Get the environment of this world. */ @Deprecated World.Environment getEnvironment(); /** * Get the environment of this world. */ Dimension getDimension(); /** * Create a new world info. * * @param world The world. */ static WorldInfo of(World world) { Preconditions.checkNotNull(world, "world parameter cannot be null"); Dimension dimension = SuperiorSkyblockAPI.getProviders().getWorldsProvider().getIslandsWorldDimension(world); if (dimension == null) dimension = Dimension.getByName(world.getEnvironment().name()); return of(world.getName(), dimension); } /** * Create a new world info. * * @param worldName The name of the world. * @param dimension The dimension of the world. */ static WorldInfo of(String worldName, Dimension dimension) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null"); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); return SuperiorSkyblockAPI.getFactory().createWorldInfo(worldName, dimension); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/world/algorithm/DelegateIslandCreationAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.world.algorithm; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.UUID; import java.util.concurrent.CompletableFuture; public class DelegateIslandCreationAlgorithm implements IslandCreationAlgorithm { protected final IslandCreationAlgorithm handle; protected DelegateIslandCreationAlgorithm(IslandCreationAlgorithm handle) { this.handle = handle; } @Override @Deprecated public CompletableFuture createIsland(UUID islandUUID, SuperiorPlayer owner, BlockPosition lastIsland, String islandName, Schematic schematic) { return this.handle.createIsland(islandUUID, owner, lastIsland, islandName, schematic); } @Override public CompletableFuture createIsland(Island.Builder builder, BlockPosition lastIsland) { return this.handle.createIsland(builder, lastIsland); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/world/algorithm/IslandCreationAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.api.world.algorithm; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.Location; import java.util.UUID; import java.util.concurrent.CompletableFuture; public interface IslandCreationAlgorithm { /** * Create a new island on the server. * This method should not only create the Island object itself, but also paste a schematic. * Teleportation and island initialization will be handled by the plugin. * * @param islandUUID The uuid of the island. * @param owner The owner of the island. * @param lastIsland The location of the last generated island. * @param islandName The name of the island. * @param schematic The schematic used to create the island. */ CompletableFuture createIsland(UUID islandUUID, SuperiorPlayer owner, BlockPosition lastIsland, String islandName, Schematic schematic); /** * Create a new island on the server. * This method should not only create the Island object itself, but also paste a schematic. * Teleportation and island initialization will be handled by the plugin. * * @param builder The builder of the island. * @param lastIsland The location of the last generated island. */ CompletableFuture createIsland(Island.Builder builder, BlockPosition lastIsland); /** * Class representing result of a creation process. */ class IslandCreationResult { private final Status status; private final Island island; private final Location islandLocation; private final boolean shouldTeleportPlayer; /** * Constructor of the result. * * @param island The created island. * @param islandLocation The location of the island. * @param shouldTeleportPlayer Whether to teleport the player to his island or not. * @deprecated See {@link #IslandCreationResult(Status, Island, Location, boolean)} */ @Deprecated public IslandCreationResult(Island island, Location islandLocation, boolean shouldTeleportPlayer) { this(Status.SUCCESS, island, islandLocation, shouldTeleportPlayer); } /** * Constructor of the result. * * @param status The status of the creation result. * In case of failure, the rest of the parameters are undefined. * @param island The created island. * @param islandLocation The location of the island. * @param shouldTeleportPlayer Whether to teleport the player to his island or not. */ public IslandCreationResult(Status status, Island island, Location islandLocation, boolean shouldTeleportPlayer) { this.status = status; this.island = island; this.islandLocation = islandLocation; this.shouldTeleportPlayer = shouldTeleportPlayer; } /** * Get the status of the creation task. */ public Status getStatus() { return status; } /** * Get the created island object. */ public Island getIsland() { Preconditions.checkState(this.getStatus() == Status.SUCCESS, "Result is not successful."); return island; } /** * Get the location of the new island. */ public Location getIslandLocation() { Preconditions.checkState(this.getStatus() == Status.SUCCESS, "Result is not successful."); return islandLocation; } /** * Get whether the player that created the island should be teleported to it. */ public boolean shouldTeleportPlayer() { Preconditions.checkState(this.getStatus() == Status.SUCCESS, "Result is not successful."); return shouldTeleportPlayer; } public enum Status { NAME_OCCUPIED, EVENT_CANCELLED, SUCCESS } } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/BlockOffset.java ================================================ package com.bgsoftware.superiorskyblock.api.wrappers; import org.bukkit.Location; /** * This object represents an offset from a block. * You can create a new instance of this class by using {@link com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager} */ public interface BlockOffset { /** * Get the x-coords offset. */ int getOffsetX(); /** * Get the y-coords offset. */ int getOffsetY(); /** * Get the z-coords offset. */ int getOffsetZ(); /** * Get a copy of this offset with negated offsets, which this.equals(this.negate().negate()) is true. */ BlockOffset negate(); /** * Apply this block-offset to a location. * * @param location The location to apply the offset to. * @return A new copy of the location with the offset applied to it. */ Location applyToLocation(Location location); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/BlockPosition.java ================================================ package com.bgsoftware.superiorskyblock.api.wrappers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import org.bukkit.Location; import org.bukkit.World; /** * This object represents a position of a block in the world. * You can create a new instance of this class by using {@link FactoriesManager} */ public interface BlockPosition { /** * Get the x value of the position. */ int getX(); /** * Get the y value of the position. */ int getY(); /** * Get the z value of the position. */ int getZ(); /** * Get a new position by an offset from this position. * * @param x The x-axis offset. * @param y The y-axis offset. * @param z The z-axis offset. */ BlockPosition offset(int x, int y, int z); /** * Get the bukkit representation of this block position in the provided world. * * @param world The world for this block position. */ Location toLocation(@Nullable World world); /** * Get the bukkit representation of this block position in the provided world. * * @param world The world for this block position. * @param location The location to write the output to. If null, null will be returned as well. */ @Nullable Location toLocation(@Nullable World world, @Nullable Location location); /** * Get the bukkit representation of this block position in the provided world. * If the world is unloaded, the location's getWorld will return null. * * @param worldInfo The world information for this world position. */ Location toLocation(WorldInfo worldInfo); /** * Get the bukkit representation of this block position in the provided world. * If the world is unloaded, the location's getWorld will return null. * * @param worldInfo The world information for this world position. * @param location The location to write the output to. If null, null will be returned as well. */ @Nullable Location toLocation(WorldInfo worldInfo, @Nullable Location location); /** * Get the world position representation of this block position. */ WorldPosition toWorldPosition(); } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java ================================================ package com.bgsoftware.superiorskyblock.api.wrappers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.HitActionResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.persistence.IPersistentDataHolder; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; public interface SuperiorPlayer extends IMissionsHolder, IPersistentDataHolder, IDatabaseBridgeHolder { /* * General Methods */ /** * Get the UUID of the player. */ UUID getUniqueId(); /** * Get the last known name of the player. */ String getName(); /** * Get the player cache. */ PlayerCache getCache(); /** * Get the last known skin-texture value of the player. */ String getTextureValue(); /** * Set the skin-texture value for the player. * * @param textureValue The skin texture. */ void setTextureValue(String textureValue); /** * Update the last time player joined or left the server. */ void updateLastTimeStatus(); /** * Set the last time player joined or left the server. * * @param lastTimeStatus The time to set. */ void setLastTimeStatus(long lastTimeStatus); /** * Get the last time player joined or left the server. */ long getLastTimeStatus(); /** * Update the cached name with the current player's name. * When the player is offline, nothing will happen. */ void updateName(); /** * Set the cached name with the given name. * When the player will join the server, it will be synced again with his correct name. */ void setName(String name); /** * Get the player object. */ @Nullable Player asPlayer(); /** * Get the offline-player object. * This can return null if the player is invalid, for example - npcs. */ @Nullable OfflinePlayer asOfflinePlayer(); /** * Check whether or not the player is online. */ boolean isOnline(); /** * Execute code only if the player is online. */ void runIfOnline(Consumer toRun); /** * Check whether or not this player is in a gamemode with fly mode enabled. * When the player is offline, false will be returned. */ boolean hasFlyGamemode(); /** * Get the opened view for the player. * When the player is offline or no view is opened, null will be returned. */ @Nullable MenuView getOpenedView(); /** * Check whether or not the player is AFK. * When the player is offline, false will be returned. */ boolean isAFK(); /** * Check whether or not the player is vanished. * When the player is offline, false will be returned. */ boolean isVanished(); /** * Checks whether the player is shown as online. * * @return false if vanished, in spectator mode or offline. */ boolean isShownAsOnline(); /** * Check whether the player has a permission. * * @param permission The permission to check. * @return When the player is offline, false will be returned. */ boolean hasPermission(String permission); /** * Check whether the player has a permission without having op. * * @param permission The permission to check. * @return When the player is offline, false may be returned. */ boolean hasPermissionWithoutOP(String permission); /** * Check whether the player has a permission on his island. * * @param permission The {@link IslandPrivilege} to check. * @return Whether the player has the permission on his island. * When the player doesn't have an island, false will be returned. */ boolean hasPermission(IslandPrivilege permission); /** * Check whether the player has the bypass permission for the provided {@link IslandPrivilege}. * * @param permission The {@link IslandPrivilege} to check. * @return Whether the player has the bypass permission. If the player is offline, false may be returned. */ boolean hasBypassPermission(IslandPrivilege permission); /** * Check whether or not this player can hit another player. *

* Players cannot hit each other if one of the followings is true: * 1) They are inside an island that has pvp disabled. * 2) One of them has pvp warm-up. * 3) They are both in the same island, and they hit each other outside of a pvp world. * 4) One of the players isn't online (duh?) * 5) The target player is inside an island as a visitor and can't take damage. * 6) The target player is inside an island as a coop and can't take damage. * * @param otherPlayer The other player to check. */ HitActionResult canHit(SuperiorPlayer otherPlayer); /* * Location Methods */ /** * Get the world that the player is inside. * When the player is offline, null will be returned. */ @Nullable World getWorld(); /** * Get the location of the player. * When the player is offline, null will be returned. */ @Nullable Location getLocation(); /** * Get the location of the player. * When the player is offline, {@param location} will be returned. * * @param location Location object to re-use. */ @Nullable Location getLocation(@Nullable Location location); /** * Teleport the player to a location. * * @param location The location to teleport the player to. */ void teleport(Location location); /** * Teleport the player to a location. * * @param location The location to teleport the player to. * @param teleportResult The result of the teleportation process. */ void teleport(Location location, @Nullable Consumer teleportResult); /** * Teleport the player to an island. * * @param island The island to teleport the player to. */ void teleport(Island island); /** * Teleport the player to an island. * * @param island The island to teleport the player to. * @param dimension The dimension to teleport the player to. */ void teleport(Island island, Dimension dimension); /** * Teleport the player to an island. * * @param island The island to teleport the player to. * @param teleportResult Consumer that will be ran when task is finished. */ void teleport(Island island, @Nullable Consumer teleportResult); /** * Teleport the player to an island. * * @param island The island to teleport the player to. * @param dimension The dimension to teleport the player to. * @param teleportResult Consumer that will be ran when task is finished. */ void teleport(Island island, Dimension dimension, @Nullable Consumer teleportResult); /** * Check whether or not the player is inside their island. * When the player is offline or he doesn't have an island, false will be returned. */ boolean isInsideIsland(); /* * Island Methods */ /** * Get the island owner of the player's island. */ SuperiorPlayer getIslandLeader(); /** * Set the island owner of the player's island. * !Can cause issues if not used properly! * * @param islandLeader The island owner's player. * @deprecated see {@link #setIsland(Island)} */ @Deprecated void setIslandLeader(SuperiorPlayer islandLeader); /** * Get the island of the player. */ @Nullable Island getIsland(); /** * Set the island of the player. * !Can cause issues if not used properly! * * @param island The island to set the player to. * @throws IllegalArgumentException if island doesn't contain player as a member. */ void setIsland(Island island); /** * Check if this player is a member of an island. */ boolean hasIsland(); /** * Add an invitation to an island for the player. * Do not call use this method directly unless you know what you're doing. * Instead, use {@link Island#inviteMember(SuperiorPlayer)} * * @param island The island that invited the player. */ void addInvite(Island island); /** * Remove an invitation from an island for the player. * Do not call use this method directly unless you know what you're doing. * Instead, use {@link Island#revokeInvite(SuperiorPlayer)} (SuperiorPlayer)} * * @param island The island to remove the invitation from. */ void removeInvite(Island island); /** * Get all pending invites of the player. * * @return Pending invites, in the same order they were sent. */ List getInvites(); /** * Mark player as a coop of an island. * !Can cause issues if not used properly! * * @param island The island to mark the player as coop. * @throws IllegalArgumentException if island doesn't contain player as a coop. */ void addCoop(Island island); /** * Remove mark of the player as a coop of an island. * !Can cause issues if not used properly! * * @param island The island to remove the mark of the player as coop. */ void removeCoop(Island island); /** * Get all islands that the player is coop of. */ List getCoopIslands(); /** * Get the role of the player. */ PlayerRole getPlayerRole(); /** * Set the role of the player. * * @param playerRole The role to give the player. */ void setPlayerRole(PlayerRole playerRole); /** * Get the amount of left disbands. */ int getDisbands(); /** * Check whether or not the player has a permission. */ void setDisbands(int disbands); /** * Check whether or not the player has more disbands. */ boolean hasDisbands(); /* * Preferences Methods */ /** * Get the locale of the player. */ Locale getUserLocale(); /** * Set the locale of the player. * * @param locale The locale to set. */ void setUserLocale(Locale locale); /** * Check whether the world border is enabled for the player. */ boolean hasWorldBorderEnabled(); /** * Toggle the world border for the player. */ void toggleWorldBorder(); /** * Set whether the world border is enabled for the player. * * @param enabled true to enable borders. */ void setWorldBorderEnabled(boolean enabled); /** * Update world border for this player. * * @param island The island the player should see the border of. */ void updateWorldBorder(@Nullable Island island); /** * Check whether the blocks-stacker mode is enabled for the player. */ boolean hasBlocksStackerEnabled(); /** * Toggle the blocks-stacker for the player. */ void toggleBlocksStacker(); /** * Set whether the blocks-stacker mode is enabled for the player. * * @param enabled true to enable blocks-stacker mode. */ void setBlocksStacker(boolean enabled); /** * Check whether the schematic mode is enabled for the player. */ boolean hasSchematicModeEnabled(); /** * Toggle the schematic mode for the player. */ void toggleSchematicMode(); /** * Set whether the schematic mode is enabled for the player. * * @param enabled true to enable schematic mode. */ void setSchematicMode(boolean enabled); /** * Check whether the team chat is enabled for the player. */ boolean hasTeamChatEnabled(); /** * Toggle the team chat for the player. */ void toggleTeamChat(); /** * Set whether the schematic mode is enabled for the player. * * @param enabled true to enable schematic mode. */ void setTeamChat(boolean enabled); /** * Check whether the bypass mode is enabled for the player. */ boolean hasBypassModeEnabled(); /** * Toggle the bypass mode for the player. */ void toggleBypassMode(); /** * Set whether the bypass mode is enabled for the player. * * @param enabled true to enable bypass mode. */ void setBypassMode(boolean enabled); /** * Check whether or not the player has their panel toggled. */ boolean hasToggledPanel(); /** * Set whether or not the player has their panel toggled. */ void setToggledPanel(boolean toggledPanel); /** * Set whether the player has flying enabled. */ boolean hasIslandFlyEnabled(); /** * Toggle flying mode. */ void toggleIslandFly(); /** * Set whether the player has flying enabled. * * @param enabled true to enable flying. */ void setIslandFly(boolean enabled); /** * Check whether the player has admin spy mode enabled. */ boolean hasAdminSpyEnabled(); /** * Toggle admin spy mode. */ void toggleAdminSpy(); /** * Set whether the player has admin spy mode enabled. * * @param enabled true to enable admin spy mode. */ void setAdminSpy(boolean enabled); /** * Get the border color of the player. */ BorderColor getBorderColor(); /** * Set the border color for the player. * * @param borderColor The color to set. */ void setBorderColor(BorderColor borderColor); /* * Schematics Methods */ /** * Get the first schematic position of the player. May be null. */ BlockPosition getSchematicPos1(); /** * Set the first schematic position of the player. * * @param block The block to change the position to. */ void setSchematicPos1(@Nullable Block block); /** * Get the second schematic position of the player. May be null. */ BlockPosition getSchematicPos2(); /** * Set the second schematic position of the player. * * @param block The block to change the position to. */ void setSchematicPos2(@Nullable Block block); /* * Data Methods */ /** * Whether the player is immuned to PvP or not. */ @Deprecated boolean isImmunedToPvP(); /** * Set immunity to PvP for this player. * * @param immunedToPvP Whether or not the player should be immuned to PvP. */ @Deprecated void setImmunedToPvP(boolean immunedToPvP); /** * Whether the player has just left an island's area or not. */ @Deprecated boolean isLeavingFlag(); /** * Set whether or not the player has just left an island's area. * If set to true, the player will not be able to escape islands. * * @param leavingFlag Whether or not the island has left an island's area. */ @Deprecated void setLeavingFlag(boolean leavingFlag); /** * Whether the player is immuned to portals or not. */ @Deprecated boolean isImmunedToPortals(); /** * Set whether or not the player is immuned to portals. * If set to true, players will not be able to get teleported through portals. * * @param immuneToPortals Whether the player should be immuned or not. */ @Deprecated void setImmunedToPortals(boolean immuneToPortals); /** * Get the current active teleport task of the player. */ @Nullable BukkitTask getTeleportTask(); /** * Set a teleportation task for the player. * This is used for warmpups, etc. * * @param teleportTask The teleport task to set. */ void setTeleportTask(@Nullable BukkitTask teleportTask); /** * Get the status of the player. * * @deprecated See {@link #hasPlayerStatus(PlayerStatus)} */ @Deprecated PlayerStatus getPlayerStatus(); /** * Set the status of the player. * * @param playerStatus The new status of the player. */ void setPlayerStatus(PlayerStatus playerStatus); /** * Remove a status of the player. * * @param playerStatus The status to remove. */ void removePlayerStatus(PlayerStatus playerStatus); /** * Check if player is in status. * * @param playerStatus The status to check. */ boolean hasPlayerStatus(PlayerStatus playerStatus); /** * Merge another player into this object. */ void merge(SuperiorPlayer otherPlayer); /** * Create a new builder for a {@link SuperiorPlayer} object. */ static Builder newBuilder() { return SuperiorSkyblockAPI.getFactory().createPlayerBuilder(); } /** * The {@link Builder} interface is used to create {@link SuperiorPlayer} objects with predefined values. * All of its methods are setters for all the values possible to create a player with. * Use {@link Builder#build()} to create the new {@link SuperiorPlayer} object. You must set * {@link Builder#setUniqueId(UUID)} before creating a new {@link SuperiorPlayer} */ interface Builder { Builder setUniqueId(UUID uuid); UUID getUniqueId(); Builder setName(String name); String getName(); Builder setPlayerRole(PlayerRole playerRole); PlayerRole getPlayerRole(); Builder setDisbands(int disbands); int getDisbands(); Builder setLocale(Locale locale); Locale getLocale(); Builder setTextureValue(String textureValue); String getTextureValue(); Builder setLastTimeUpdated(long lastTimeUpdated); long getLastTimeUpdated(); Builder setToggledPanel(boolean toggledPanel); boolean hasToggledPanel(); Builder setIslandFly(boolean islandFly); boolean hasIslandFly(); Builder setBorderColor(BorderColor borderColor); BorderColor getBorderColor(); Builder setWorldBorderEnabled(boolean worldBorderEnabled); boolean hasWorldBorderEnabled(); Builder setCompletedMission(Mission mission, int finishCount); Map, Integer> getCompletedMissions(); Builder setPersistentData(byte[] persistentData); byte[] getPersistentData(); SuperiorPlayer build(); } } ================================================ FILE: API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/WorldPosition.java ================================================ package com.bgsoftware.superiorskyblock.api.wrappers; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import org.bukkit.Location; import org.bukkit.World; /** * This object represents a position of an entity in the world. * You can create a new instance of this class by using {@link FactoriesManager} */ public interface WorldPosition { /** * Get the x value of the position. */ double getX(); /** * Get the y value of the position. */ double getY(); /** * Get the z value of the position. */ double getZ(); /** * Get the yaw value of the position. */ float getYaw(); /** * Get the pitch value of the position. */ float getPitch(); /** * Get a new position by an offset from this position. * * @param x The x-axis offset. * @param y The y-axis offset. * @param z The z-axis offset. */ WorldPosition offset(double x, double y, double z); /** * Get a new position by rotating this position. * * @param yaw The y-axis rotation. * @param pitch The z-axis rotation. */ WorldPosition rotate(float yaw, float pitch); /** * Get a new position by an offset from this position. * * @param x The x-axis offset. * @param y The y-axis offset. * @param z The z-axis offset. * @param yaw The y-axis rotation. * @param pitch The z-axis rotation. */ WorldPosition offset(double x, double y, double z, float yaw, float pitch); /** * Get the bukkit representation of this world position in the provided world. * * @param world The world for this world position. */ Location toLocation(@Nullable World world); /** * Get the bukkit representation of this world position in the provided world. * * @param world The world for this world position. * @param location The location to write the output to. If null, null will be returned as well. */ @Nullable Location toLocation(@Nullable World world, @Nullable Location location); /** * Get the bukkit representation of this world position in the provided world info. * If the world is unloaded, the location's getWorld will return null. * * @param worldInfo The world information for this world position. */ Location toLocation(WorldInfo worldInfo); /** * Get the bukkit representation of this world position in the provided world info. * If the world is unloaded, the location's getWorld will return null. * * @param worldInfo The world information for this world position. * @param location The location to write the output to. If null, null will be returned as well. */ @Nullable Location toLocation(WorldInfo worldInfo, @Nullable Location location); /** * Get the block position representation of this world position. */ BlockPosition toBlockPosition(); } ================================================ FILE: Hooks/AdvancedSlimePaper/build.gradle ================================================ group 'AdvancedSlimePaper' java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } dependencies { compileOnly 'com.infernalsuite:AdvancedSlimePaper:1.19.4-R0.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_slimeworldmanager') && !Boolean.valueOf(project.findProperty("hook.compile_slimeworldmanager").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/AdvancedSlimePaper/src/main/java/com/bgsoftware/superiorskyblock/external/AdvancedSlimePaperHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.infernalsuite.aswm.api.SlimePlugin; import com.infernalsuite.aswm.api.loaders.SlimeLoader; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; @SuppressWarnings("unused") public class AdvancedSlimePaperHook { private static final String[] LOADERS = new String[]{"api", "mysql", "mongodb", "file"}; private static Plugin slimeWorldPlugin = null; public static boolean isCompatible() { try { Class.forName("com.infernalsuite.aswm.api.loaders.SlimeLoader"); } catch (ClassNotFoundException error) { return false; } // We don't support API v3 try { Class.forName("com.infernalsuite.aswm.api.AdvancedSlimePaperAPI"); return false; } catch (ClassNotFoundException error) { return true; } } public static void register(SuperiorSkyblockPlugin plugin) { slimeWorldPlugin = Bukkit.getPluginManager().getPlugin("SlimeWorldManager"); plugin.getProviders().registerWorldsListener(AdvancedSlimePaperHook::loadWorld); } private static void loadWorld(String worldName) { SlimePlugin slimePlugin = (SlimePlugin) slimeWorldPlugin; for (String loaderName : LOADERS) { try { SlimeLoader slimeLoader = slimePlugin.getLoader(loaderName); if (slimeLoader != null && slimeLoader.worldExists(worldName)) { slimeLoader.loadWorld(worldName); break; } } catch (Exception ignored) { } } } } ================================================ FILE: Hooks/AdvancedSpawners/build.gradle ================================================ group 'Hooks:AdvancedSpawners' dependencies { compileOnly 'gcspawners:AdvancedSpawners:2.2.14' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_advancedspawners') && !Boolean.valueOf(project.findProperty("hook.compile_advancedspawners").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import gcspawners.ASAPI; import gcspawners.AdvancedSpawnerPlaceEvent; import gcspawners.AdvancedSpawnersBreakEvent; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import java.util.Locale; public class SpawnersProvider_AdvancedSpawners implements SpawnersProvider_AutoDetect { private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_AdvancedSpawners(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new SpawnersProvider_AdvancedSpawners.StackerListener(), plugin); Log.info("Using AdvancedSpawners as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); return !Bukkit.isPrimaryThread() ? new Pair<>(-1, null) : new Pair<>(ASAPI.getSpawnerAmount(location), ASAPI.getSpawnerType(location).toUpperCase(Locale.ENGLISH)); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); return ASAPI.getSpawnerType(itemStack).toUpperCase(Locale.ENGLISH); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerStack(AdvancedSpawnerPlaceEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); } if (island != null) { island.handleBlockPlace(Keys.ofSpawner(e.getEntityType()), e.getCountPlaced()); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(AdvancedSpawnersBreakEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); } if (island != null) island.handleBlockBreak(Keys.ofSpawner(e.getEntityType()), e.getCountBroken()); } } } ================================================ FILE: Hooks/CMI/build.gradle ================================================ group 'Hooks:CMI' dependencies { compileOnly 'com.Zrips:CMI:8.5.1.4' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_cmi') && !Boolean.valueOf(project.findProperty("hook.compile_cmi").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/CMI/src/main/java/com/bgsoftware/superiorskyblock/external/afk/AFKProvider_CMI.java ================================================ package com.bgsoftware.superiorskyblock.external.afk; import com.Zrips.CMI.CMI; import com.bgsoftware.superiorskyblock.api.hooks.AFKProvider; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import org.bukkit.entity.Player; public class AFKProvider_CMI implements AFKProvider { public AFKProvider_CMI() { Log.info("Hooked into CMI for support of afk status of players."); } @Override public boolean isAFK(Player player) { Preconditions.checkNotNull(player, "player parameter cannot be null."); return CMI.getInstance().getPlayerManager().getUser(player).isAfk(); } } ================================================ FILE: Hooks/CMI/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_CMI.java ================================================ package com.bgsoftware.superiorskyblock.external.vanish; import com.Zrips.CMI.CMI; import com.Zrips.CMI.events.CMIPlayerUnVanishEvent; import com.Zrips.CMI.events.CMIPlayerVanishEvent; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; public class VanishProvider_CMI implements VanishProvider, Listener { private final SuperiorSkyblockPlugin plugin; public VanishProvider_CMI(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(this, plugin); Log.info("Hooked into CMI for support of vanish status of players."); } @Override public boolean isVanished(Player player) { return CMI.getInstance().getVanishManager().getAllVanished().contains(player.getUniqueId()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerVanish(CMIPlayerVanishEvent e) { IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(e.getPlayer())); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerUnvanish(CMIPlayerUnVanishEvent e) { IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(e.getPlayer())); } } ================================================ FILE: Hooks/CandcSilkSpawners/build.gradle ================================================ group 'Hooks:CandcSilkSpawners' dependencies { compileOnly 'de.candc:SilkSpawners:1.6' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_candcsilkspawners') && !Boolean.valueOf(project.findProperty("hook.compile_candcsilkspawners").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import de.candc.events.SpawnerBreakEvent; import de.candc.events.SpawnerPlaceEvent; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; public class SpawnersProvider_CandcSilkSpawners implements SpawnersProvider_AutoDetect { private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_CandcSilkSpawners(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using SilkSpawners as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); return new Pair<>(1, null); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); return itemStack.getItemMeta().getLore().get(0).replaceAll("§e", ""); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerPlace(SpawnerPlaceEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); } if (island != null) island.handleBlockPlace(Keys.ofSpawner(e.getSpawnedEntity()), 1); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); } if (island != null) island.handleBlockBreak(Keys.ofSpawner(e.getSpawnedEntity()), 1); } } } ================================================ FILE: Hooks/ChangeSkin/build.gradle ================================================ group 'Hooks:ChangeSkin' dependencies { compileOnly 'com.github.games647:ChangeSkin:3.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_changeskin') && !Boolean.valueOf(project.findProperty("hook.compile_changeskin").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/ChangeSkin/src/main/java/com/bgsoftware/superiorskyblock/external/ChangeSkinHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; public class ChangeSkinHook implements Listener { public static boolean isCompatible() { try { Class.forName("com.github.games647.changeskin.bukkit.events.PlayerChangeSkinEvent"); return true; } catch (ClassNotFoundException error) { return false; } } private ChangeSkinHook() { } public static void register(SuperiorSkyblockPlugin plugin) { Bukkit.getPluginManager().registerEvents(new PlayerChangeSkinListener(plugin), plugin); } private static class PlayerChangeSkinListener implements Listener { private final SuperiorSkyblockPlugin plugin; PlayerChangeSkinListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @EventHandler public void onPlayerChangeSkin(com.github.games647.changeskin.bukkit.events.PlayerChangeSkinEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); superiorPlayer.setTextureValue(e.getSkinModel().getEncodedValue()); } } } ================================================ FILE: Hooks/CoreProtect/build.gradle ================================================ group 'Hooks:CoreProtect' dependencies { compileOnly 'net.coreprotect:CoreProtect:19.0' compileOnly "org.spigotmc:v1_16_R3:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_coreprotect') && !Boolean.valueOf(project.findProperty("hook.compile_coreprotect").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/CoreProtect/src/main/java/com/bgsoftware/superiorskyblock/external/CoreProtectHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import net.coreprotect.CoreProtect; import net.coreprotect.CoreProtectAPI; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.block.Block; import org.bukkit.plugin.Plugin; @SuppressWarnings({"deprecation", "unused"}) public class CoreProtectHook { private static SuperiorSkyblockPlugin plugin; private static Plugin coreProtect; public static void register(SuperiorSkyblockPlugin plugin) { CoreProtectHook.plugin = plugin; coreProtect = Bukkit.getPluginManager().getPlugin("CoreProtect"); plugin.getProviders().registerStackedBlocksListener(CoreProtectHook::recordBlockAction); } private static void recordBlockAction(OfflinePlayer offlinePlayer, Block block, IStackedBlocksListener.Action action) { if (!Bukkit.isPrimaryThread()) { BukkitExecutor.sync(() -> recordBlockAction(offlinePlayer, block, action)); return; } CoreProtectAPI coreProtectAPI = ((CoreProtect) coreProtect).getAPI(); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = block.getLocation(wrapper.getHandle()); if (coreProtectAPI.APIVersion() == 5) { switch (action) { case BLOCK_BREAK: coreProtectAPI.logRemoval(offlinePlayer.getName(), location, block.getType(), block.getData()); break; case BLOCK_PLACE: coreProtectAPI.logPlacement(offlinePlayer.getName(), location, block.getType(), block.getData()); break; } } else if (coreProtectAPI.APIVersion() <= 9) { switch (action) { case BLOCK_BREAK: coreProtectAPI.logRemoval(offlinePlayer.getName(), location, block.getType(), (org.bukkit.block.data.BlockData) plugin.getNMSWorld().getBlockData(block)); break; case BLOCK_PLACE: coreProtectAPI.logPlacement(offlinePlayer.getName(), location, block.getType(), (org.bukkit.block.data.BlockData) plugin.getNMSWorld().getBlockData(block)); break; } } } } } ================================================ FILE: Hooks/CraftEngine/build.gradle ================================================ group 'Hooks:CraftEngine' java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } repositories { maven { url "https://repo.momirealms.net/releases/" } } dependencies { compileOnly "net.momirealms:craft-engine-core:0.0.56" compileOnly "net.momirealms:craft-engine-bukkit:0.0.56" compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_craftengine') && !Boolean.valueOf(project.findProperty("hook.compile_craftengine").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.plugin.CraftEngine; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import java.util.Locale; public class CraftEngineHook { private static final String CRAFTENGINE_PREFIX = "CRAFTENGINE"; private static final KeySet CUSTOM_ITEM_KEYS = collectCustomItemKeys(); private static final KeySet CUSTOM_BLOCK_KEYS = collectCustomBlockKeys(); private static final KeyMap CUSTOM_ITEM_CACHE = collectCustomItemsCache(); private static final KeyMap CUSTOM_ITEM_TO_BLOCK_CACHE = collectCustomItemToBlocksCache(); private static boolean registered = false; public static void register(SuperiorSkyblockPlugin plugin) { plugin.getServer().getPluginManager().registerEvents(new ListenerImpl(), plugin); if (!registered) { registered = true; plugin.getBlockValues().registerKeyParser(new CraftEngineKeyParser(), collectCustomKeys()); } } private static KeySet collectCustomItemKeys() { KeySet customItemKeys = KeySets.createHashSet(KeyIndicator.MATERIAL); for (net.momirealms.craftengine.core.util.Key itemKey : CraftEngine.instance().itemManager().items()) { CustomItem customItem = CraftEngineItems.byId(itemKey); if (customItem != null) { ItemStack itemStack = customItem.buildItemStack(); customItemKeys.add(Keys.of(itemStack.getType())); } } return customItemKeys; } private static KeySet collectCustomBlockKeys() { KeySet customBlockKeys = KeySets.createHashSet(KeyIndicator.MATERIAL); for (CustomBlock customBlock : CraftEngine.instance().blockManager().blocks().values()) { BlockData blockData = CraftEngineBlocks.getBukkitBlockData(customBlock.defaultState()); customBlockKeys.add(Keys.of(blockData.getMaterial())); } return customBlockKeys; } private static KeyMap collectCustomItemsCache() { KeyMap customItemsCache = KeyMaps.createHashMap(KeyIndicator.CUSTOM); for (net.momirealms.craftengine.core.util.Key itemKey : CraftEngine.instance().itemManager().items()) { CustomItem customItem = CraftEngineItems.byId(itemKey); if (customItem != null) { ItemStack itemStack = customItem.buildItemStack(); Key ssbItemKey = Keys.of(CRAFTENGINE_PREFIX, itemKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); customItemsCache.put(ssbItemKey, itemStack); } } return customItemsCache; } private static KeyMap collectCustomItemToBlocksCache() { KeyMap customItemToBlocksCache = KeyMaps.createHashMap(KeyIndicator.CUSTOM); CraftEngine.instance().blockManager().blocks().forEach((blockKey, customBlock) -> { Key ssbBlockKey = Keys.of(CRAFTENGINE_PREFIX, blockKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); customItemToBlocksCache.put(ssbBlockKey, customBlock); }); return customItemToBlocksCache; } private static Key[] collectCustomKeys() { KeySet customKeys = KeySets.createHashSet(KeyIndicator.MATERIAL); customKeys.addAll(CUSTOM_ITEM_KEYS); customKeys.addAll(CUSTOM_BLOCK_KEYS); return customKeys.toArray(new Key[0]); } private static class ListenerImpl implements Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onIslandGenerateBlock(IslandGenerateBlockEvent event) { if (!event.getBlock().getGlobalKey().equals(CRAFTENGINE_PREFIX)) return; CustomBlock customBlock = CUSTOM_ITEM_TO_BLOCK_CACHE.get(event.getBlock()); if (customBlock == null) { event.setCancelled(true); return; } event.setPlaceBlock(false); CraftEngineBlocks.place(event.getLocation(), customBlock.defaultState(), false); } } private static class CraftEngineKeyParser implements CustomKeyParser { @Override public Key getCustomKey(Location location) { Block block = location.getBlock(); ImmutableBlockState customBlockState = CraftEngineBlocks.getCustomBlockState(block); if (customBlockState == null || customBlockState.isEmpty()) return null; net.momirealms.craftengine.core.util.Key blockKey = customBlockState.owner().value().id(); return Keys.of(CRAFTENGINE_PREFIX, blockKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); } @Override public Key getCustomKey(ItemStack itemStack, Key def) { CustomItem customItem = CraftEngineItems.byItemStack(itemStack); if (customItem == null) return def; net.momirealms.craftengine.core.util.Key itemKey = customItem.id(); return Keys.of(CRAFTENGINE_PREFIX, itemKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); } @Override public boolean isCustomKey(Key key) { return key.getGlobalKey().equals(CRAFTENGINE_PREFIX); } @Override @Nullable public ItemStack getCustomKeyItem(Key key) { return key.getGlobalKey().equals(CRAFTENGINE_PREFIX) ? CUSTOM_ITEM_CACHE.get(key) : null; } } } ================================================ FILE: Hooks/EpicSpawners6/build.gradle ================================================ group 'Hooks:EpicSpawners6' dependencies { compileOnly 'com.songoda:EpicSpawners:6.0.6' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_epicspawners6') && !Boolean.valueOf(project.findProperty("hook.compile_epicspawners6").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/EpicSpawners6/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners6.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.google.common.base.Preconditions; import com.songoda.epicspawners.EpicSpawners; import com.songoda.epicspawners.api.events.SpawnerBreakEvent; import com.songoda.epicspawners.api.events.SpawnerChangeEvent; import com.songoda.epicspawners.api.events.SpawnerPlaceEvent; import com.songoda.epicspawners.spawners.spawner.Spawner; import com.songoda.epicspawners.spawners.spawner.SpawnerData; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; public class SpawnersProvider_EpicSpawners6 implements SpawnersProvider_AutoDetect { private final EpicSpawners instance = EpicSpawners.getInstance(); private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_EpicSpawners6(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using EpicSpawners as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; String entityType = null; if (Bukkit.isPrimaryThread()) { Spawner spawner = instance.getSpawnerManager().getSpawnerFromWorld(location); blockCount = spawner.getFirstStack().getStackSize(); entityType = spawner.getIdentifyingName(); } return new Pair<>(blockCount, entityType); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); return instance.getSpawnerManager().getSpawnerData(itemStack).getIdentifyingName(); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSpawnerStack(SpawnerPlaceEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData(); Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); int increaseAmount = e.getSpawner().getFirstStack().getStackSize(); if (spawnerData.isCustom()) { // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered // before removing it. BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L); } else { // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly. increaseAmount--; } if (increaseAmount <= 0) return; if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString())); } else { island.handleBlockPlace(spawnerKey, increaseAmount); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSpawnerStack(SpawnerChangeEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); int increaseAmount = e.getStackSize() - e.getOldStackSize(); if (increaseAmount < 0) { island.handleBlockBreak(blockKey, -increaseAmount); } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize()); } } } ================================================ FILE: Hooks/EpicSpawners7/build.gradle ================================================ group 'Hooks:EpicSpawners7' dependencies { compileOnly 'com.songoda:EpicSpawners:7.0.2' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_epicspawners7') && !Boolean.valueOf(project.findProperty("hook.compile_epicspawners7").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/EpicSpawners7/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners7.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.google.common.base.Preconditions; import com.songoda.epicspawners.EpicSpawners; import com.songoda.epicspawners.api.events.SpawnerBreakEvent; import com.songoda.epicspawners.api.events.SpawnerChangeEvent; import com.songoda.epicspawners.api.events.SpawnerPlaceEvent; import com.songoda.epicspawners.spawners.spawner.SpawnerData; import com.songoda.epicspawners.spawners.spawner.SpawnerStack; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; @SuppressWarnings("unused") public class SpawnersProvider_EpicSpawners7 implements SpawnersProvider { private final EpicSpawners instance = EpicSpawners.getInstance(); private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_EpicSpawners7(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new SpawnersProvider_EpicSpawners7.StackerListener(), plugin); Log.info("Using EpicSpawners as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; String entityType = null; if (Bukkit.isPrimaryThread()) { SpawnerStack spawnerStack = instance.getSpawnerManager().getSpawnerFromWorld(location).getFirstStack(); if (spawnerStack != null) { blockCount = spawnerStack.getStackSize(); entityType = spawnerStack.getCurrentTier().getIdentifyingName(); } } return new Pair<>(blockCount, entityType); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); return instance.getSpawnerManager().getSpawnerTier(itemStack).getSpawnerData().getIdentifyingName(); } private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSpawnerStack(SpawnerPlaceEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData(); Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); int increaseAmount = e.getSpawner().getFirstStack().getStackSize(); if (spawnerData.isCustom()) { // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered // before removing it. BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L); } else { // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly. increaseAmount--; } if (increaseAmount <= 0) return; if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString())); } else { island.handleBlockPlace(spawnerKey, increaseAmount); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSpawnerStack(SpawnerChangeEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); int increaseAmount = e.getStackSize() - e.getOldStackSize(); if (increaseAmount < 0) { island.handleBlockBreak(blockKey, -increaseAmount); } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize()); } } } ================================================ FILE: Hooks/EpicSpawners8/build.gradle ================================================ group 'Hooks:EpicSpawners8' dependencies { compileOnly "com.songoda:EpicSpawners:8.1.0" compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_epicspawners8') && !Boolean.valueOf(project.findProperty("hook.compile_epicspawners8").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/EpicSpawners8/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners8.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.craftaro.epicspawners.api.EpicSpawnersApi; import com.craftaro.epicspawners.api.events.SpawnerBreakEvent; import com.craftaro.epicspawners.api.events.SpawnerChangeEvent; import com.craftaro.epicspawners.api.events.SpawnerPlaceEvent; import com.craftaro.epicspawners.api.spawners.spawner.SpawnerData; import com.craftaro.epicspawners.api.spawners.spawner.SpawnerStack; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; @SuppressWarnings("unused") public class SpawnersProvider_EpicSpawners8 implements SpawnersProvider { private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_EpicSpawners8(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using EpicSpawners as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; String entityType = null; if (Bukkit.isPrimaryThread()) { SpawnerStack spawnerStack = EpicSpawnersApi.getSpawnerManager().getSpawnerFromWorld(location).getFirstStack(); if (spawnerStack != null) { blockCount = spawnerStack.getStackSize(); entityType = spawnerStack.getCurrentTier().getIdentifyingName(); } } return new Pair<>(blockCount, entityType); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); return EpicSpawnersApi.getSpawnerManager().getSpawnerTier(itemStack).getSpawnerData().getIdentifyingName(); } private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSpawnerStack(SpawnerPlaceEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData(); Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); int increaseAmount = e.getSpawner().getFirstStack().getStackSize(); if (spawnerData.isCustom()) { // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered // before removing it. BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L); } else { // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly. increaseAmount--; } if (increaseAmount <= 0) return; if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString())); } else { island.handleBlockPlace(spawnerKey, increaseAmount); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSpawnerStack(SpawnerChangeEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); int increaseAmount = e.getStackSize() - e.getOldStackSize(); if (increaseAmount < 0) { island.handleBlockBreak(blockKey, -increaseAmount); } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize()); } } } ================================================ FILE: Hooks/EpicSpawners9/build.gradle ================================================ group 'Hooks:EpicSpawners8' dependencies { compileOnly "com.songoda:EpicSpawners:9.1.1" compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_epicspawners9') && !Boolean.valueOf(project.findProperty("hook.compile_epicspawners9").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.google.common.base.Preconditions; import com.songoda.epicspawners.api.EpicSpawnersApi; import com.songoda.epicspawners.api.events.SpawnerBreakEvent; import com.songoda.epicspawners.api.events.SpawnerChangeEvent; import com.songoda.epicspawners.api.events.SpawnerPlaceEvent; import com.songoda.epicspawners.api.spawners.spawner.SpawnerData; import com.songoda.epicspawners.api.spawners.spawner.SpawnerStack; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; @SuppressWarnings("unused") public class SpawnersProvider_EpicSpawners9 implements SpawnersProvider { private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_EpicSpawners9(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using EpicSpawners as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; String entityType = null; if (Bukkit.isPrimaryThread()) { SpawnerStack spawnerStack = EpicSpawnersApi.getSpawnerManager().getSpawnerFromWorld(location).getFirstStack(); if (spawnerStack != null) { blockCount = spawnerStack.getStackSize(); entityType = spawnerStack.getCurrentTier().getIdentifyingName(); } } return new Pair<>(blockCount, entityType); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); return EpicSpawnersApi.getSpawnerManager().getSpawnerTier(itemStack).getSpawnerData().getIdentifyingName(); } private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSpawnerStack(SpawnerPlaceEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData(); Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); int increaseAmount = e.getSpawner().getFirstStack().getStackSize(); if (spawnerData.isCustom()) { // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered // before removing it. BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L); } else { // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly. increaseAmount--; } if (increaseAmount <= 0) return; if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString())); } else { island.handleBlockPlace(spawnerKey, increaseAmount); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSpawnerStack(SpawnerChangeEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); int increaseAmount = e.getStackSize() - e.getOldStackSize(); if (increaseAmount < 0) { island.handleBlockBreak(blockKey, -increaseAmount); } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize()); } } } ================================================ FILE: Hooks/Essentials/build.gradle ================================================ group 'Hooks:Essentials' dependencies { compileOnly 'com.earth2me:Essentials:2.16.0.3' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_essentials') && !Boolean.valueOf(project.findProperty("hook.compile_essentials").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/Essentials/src/main/java/com/bgsoftware/superiorskyblock/external/afk/AFKProvider_Essentials.java ================================================ package com.bgsoftware.superiorskyblock.external.afk; import com.bgsoftware.superiorskyblock.api.hooks.AFKProvider; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.earth2me.essentials.Essentials; import com.google.common.base.Preconditions; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; public class AFKProvider_Essentials implements AFKProvider { private final Essentials instance; public AFKProvider_Essentials() { instance = JavaPlugin.getPlugin(Essentials.class); Log.info("Hooked into Essentials for support of afk status of players."); } @Override public boolean isAFK(Player player) { Preconditions.checkNotNull(player, "player parameter cannot be null."); return instance.getUser(player).isAfk(); } } ================================================ FILE: Hooks/Essentials/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Essentials.java ================================================ package com.bgsoftware.superiorskyblock.external.vanish; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications; import com.earth2me.essentials.Essentials; import net.ess3.api.events.VanishStatusChangeEvent; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; public class VanishProvider_Essentials implements VanishProvider, Listener { private final SuperiorSkyblockPlugin plugin; private final Essentials instance; public VanishProvider_Essentials(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; this.instance = JavaPlugin.getPlugin(Essentials.class); Bukkit.getPluginManager().registerEvents(this, plugin); Log.info("Hooked into Essentials for support of vanish status of players."); } @Override public boolean isVanished(Player player) { return instance.getUser(player).isVanished(); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerVanish(VanishStatusChangeEvent e) { Player affectedPlayer = e.getAffected() == null ? e.getController().getBase() : e.getAffected().getBase(); if (e.getValue()) { IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(affectedPlayer)); } else { IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(affectedPlayer)); } } } ================================================ FILE: Hooks/FastAsyncWorldEdit/build.gradle ================================================ group 'Hooks:FastAsyncWorldEdit' dependencies { compileOnly 'com.boydti:FastAsyncWorldEdit:1.13.135' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_fastasyncworldedit') && !Boolean.valueOf(project.findProperty("hook.compile_fastasyncworldedit").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.impl; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic; import com.boydti.fawe.object.clipboard.FaweClipboard; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockState; import org.bukkit.Location; import org.bukkit.Material; import java.util.Collections; import java.util.List; import java.util.function.Consumer; public class WorldEditSchematic extends BaseSchematic implements Schematic { private static ReflectMethod AT; private static ReflectMethod PASTE; private static final ReflectMethod GET_BLOCK_TYPE = new ReflectMethod<>(BaseBlock.class, "getBlockType"); private static final ReflectMethod GET_INTERNAL_ID = new ReflectMethod<>(BaseBlock.class, "getInternalId"); private static final ReflectMethod ADAPT = new ReflectMethod<>( new ClassInfo("com.sk89q.worldedit.bukkit.BukkitAdapter", ClassInfo.PackageType.UNKNOWN), "adapt", new ClassInfo("com.sk89q.worldedit.world.block.BlockTypes", ClassInfo.PackageType.UNKNOWN)); private static final ReflectMethod GET_ID = new ReflectMethod<>(BaseBlock.class, "getId"); private static final ReflectMethod GET_DATA = new ReflectMethod<>(BaseBlock.class, "getData"); private final com.boydti.fawe.object.schematic.Schematic schematic; static { try { Class blockVectorClass = Class.forName("com.sk89q.worldedit.math.BlockVector3"); AT = new ReflectMethod<>(blockVectorClass, "at", int.class, int.class, int.class); PASTE = new ReflectMethod<>(com.boydti.fawe.object.schematic.Schematic.class, "paste", World.class, blockVectorClass, boolean.class, boolean.class, Transform.class); } catch (ClassNotFoundException ignored) { } } public WorldEditSchematic(String name, com.boydti.fawe.object.schematic.Schematic schematic) { super(name); this.schematic = schematic; readBlocks(); } @Override public void pasteSchematic(Island island, Location location, Runnable callback) { pasteSchematic(island, location, callback, null); } @Override public void pasteSchematic(Island island, Location location, Runnable callback, Consumer onFailure) { try { Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location); Object _point = AT.invoke(null, location.getBlockX(), location.getBlockY(), location.getBlockZ()); EditSession editSession = PASTE.invoke(schematic, new BukkitWorld(location.getWorld()), _point, false, true, null); if (editSession == null) { com.sk89q.worldedit.Vector point = new com.sk89q.worldedit.Vector(location.getBlockX(), location.getBlockY(), location.getBlockZ()); editSession = schematic.paste(new BukkitWorld(location.getWorld()), point, true, true, null); } editSession.addNotifyTask(() -> { Log.debugResult(Debug.PASTE_SCHEMATIC, "Task Finished", ""); try { island.handleBlocksPlace(cachedCounts); PluginEventsFactory.callIslandSchematicPasteEvent(island, null, name, location); callback.run(); } catch (Throwable ex) { if (onFailure != null) onFailure.accept(ex); } }); } catch (Throwable ex) { if (onFailure != null) onFailure.accept(ex); } } @Override public Location adjustRotation(Location location) { return location; } @Override public List getAffectedChunks() { return Collections.emptyList(); } @Override public Runnable onTeleportCallback() { return null; } private void readBlocks() { BlockArrayClipboard clipboard = (BlockArrayClipboard) schematic.getClipboard(); assert clipboard != null; try { clipboard.IMP.forEach(new BlockReader() { @Override public void run(int x, int y, int z, BaseBlock block) { readBlock(block); } }, false); } catch (Throwable ex) { clipboard.IMP.forEach(new FaweClipboard.BlockReader() { @Override public void run(int x, int y, int z, BlockState block) { readBlock(block); } }, false); } } private void readBlock(Object baseBlock) { Key key; if (ADAPT.isValid() && GET_BLOCK_TYPE.isValid() && GET_INTERNAL_ID.isValid()) { Material material = ADAPT.invoke(null, GET_BLOCK_TYPE.invoke(baseBlock)); int data = GET_INTERNAL_ID.invokeWithDef(baseBlock, 0); key = Keys.of(material, (byte) data); } else { int id = GET_ID.invoke(baseBlock); int data = GET_DATA.invoke(baseBlock); //noinspection deprecation key = Keys.of(Material.getMaterial(id), (byte) data); } cachedCounts.put(key, cachedCounts.getRaw(key, 0) + 1); } private static abstract class BlockReader extends FaweClipboard.BlockReader { public abstract void run(int x, int y, int z, BaseBlock block); public void run(int x, int y, int z, BlockState block) { // Do nothing. } } } ================================================ FILE: Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/parser/FAWESchematicParser.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.parser; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParseException; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import com.bgsoftware.superiorskyblock.world.schematic.impl.WorldEditSchematic; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import java.io.DataInputStream; import java.io.IOException; public class FAWESchematicParser implements SchematicParser { public FAWESchematicParser() { } @Override public Schematic parseSchematic(DataInputStream inputStream, String schematicName) throws SchematicParseException { try { //noinspection deprecation return new WorldEditSchematic(schematicName, ClipboardFormat.SCHEMATIC.load(inputStream)); } catch (IOException error) { throw new SchematicParseException(schematicName + " is not a FastAsyncWorldEdit schematic."); } } } ================================================ FILE: Hooks/ItemsAdder/build.gradle ================================================ group 'Hooks:ItemsAdder' dependencies { compileOnly 'dev.lone:ItemsAdder:3.5.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_itemsadder') && !Boolean.valueOf(project.findProperty("hook.compile_itemsadder").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import dev.lone.itemsadder.api.CustomBlock; import dev.lone.itemsadder.api.CustomStack; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import java.util.Locale; public class ItemsAdderHook { private static final String ITEMS_ADDER_PREFIX = "ITEMS_ADDER"; private static final Key BLOCK_ITEM_KEY = Keys.of(Material.PAPER); private static final Key BLOCK_KEY = Keys.of(Material.NOTE_BLOCK); private static final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; private static boolean registered = false; private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { ItemsAdderHook.plugin = plugin; plugin.getServer().getPluginManager().registerEvents(new ListenerImpl(), plugin); if (!registered) { registered = true; plugin.getBlockValues().registerKeyParser(new ItemsAdderKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); } } private static class ListenerImpl implements Listener { @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onItemAdderBlockInteract(PlayerInteractEvent e) { switch (e.getAction()) { case RIGHT_CLICK_BLOCK: onBlockPlace(e); break; case LEFT_CLICK_BLOCK: onBlockBreak(e); break; } } private void onBlockPlace(PlayerInteractEvent e) { if (e.getItem() == null) return; CustomBlock customBlock = CustomBlock.byItemStack(e.getItem()); if (customBlock == null) return; CustomBlock clickedBlock = CustomBlock.byAlreadyPlaced(e.getClickedBlock()); if (clickedBlock != null) return; Block placeBlock = e.getClickedBlock().getRelative(e.getBlockFace()); BukkitExecutor.sync(() -> { if (placeBlock.getType() == Material.NOTE_BLOCK) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Key itemKey = Keys.of(ITEMS_ADDER_PREFIX, customBlock.getId().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); worldRecordService.get().recordBlockPlace(itemKey, placeBlock.getLocation(wrapper.getHandle()), 1, null, WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS); } } }, 1L); } private void onBlockBreak(PlayerInteractEvent e) { CustomBlock clickedBlock = CustomBlock.byAlreadyPlaced(e.getClickedBlock()); if (clickedBlock != null) { Key blockKey = Key.of(e.getClickedBlock()); BukkitExecutor.sync(() -> { if (e.getClickedBlock().getType() == Material.AIR) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { worldRecordService.get().recordBlockBreak(blockKey, e.getClickedBlock().getLocation(wrapper.getHandle()), 1, WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS); } } }, 1L); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onIslandGenerateBlock(IslandGenerateBlockEvent event) { if (!event.getBlock().getGlobalKey().equals(ITEMS_ADDER_PREFIX)) return; String itemId = event.getBlock().getSubKey().toLowerCase(Locale.ENGLISH); CustomBlock customBlock = CustomBlock.getInstance(itemId); if (customBlock == null) { event.setCancelled(true); return; } event.setPlaceBlock(false); customBlock.place(event.getLocation()); } } private static class ItemsAdderKeyParser implements CustomKeyParser { @Override public Key getCustomKey(Location location) { Block block = location.getBlock(); CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block); if (customBlock == null) return BLOCK_KEY; return Keys.of(ITEMS_ADDER_PREFIX, customBlock.getId().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); } @Override public Key getCustomKey(ItemStack itemStack, Key def) { CustomStack customStack = CustomStack.byItemStack(itemStack); if (customStack == null) return def; return Keys.of(ITEMS_ADDER_PREFIX, customStack.getId().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); } @Override public boolean isCustomKey(Key key) { return key.getGlobalKey().equals(ITEMS_ADDER_PREFIX); } @Override @Nullable public ItemStack getCustomKeyItem(Key key) { CustomStack customStack = CustomStack.getInstance(key.getSubKey().toLowerCase(Locale.ENGLISH)); if (customStack == null) return null; return customStack.getItemStack(); } } } ================================================ FILE: Hooks/JetsMinions/build.gradle ================================================ group 'Hooks:JetsMinions' dependencies { compileOnly 'me.jet315:JetsMinions:6.9.2' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_jetsminions') && !Boolean.valueOf(project.findProperty("hook.compile_jetsminions").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/JetsMinions/src/main/java/com/bgsoftware/superiorskyblock/external/JetsMinionsHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksServiceHelper; import me.jet315.minions.events.MinerBlockBreakEvent; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; public class JetsMinionsHook implements Listener { @WorldRecordFlags private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; private final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; private final LazyReference stackedBlocksInteractionService = new LazyReference() { @Override protected StackedBlocksInteractionService create() { return plugin.getServices().getService(StackedBlocksInteractionService.class); } }; private final SuperiorSkyblockPlugin plugin; private JetsMinionsHook(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } public static void register(SuperiorSkyblockPlugin plugin) { Bukkit.getPluginManager().registerEvents(new JetsMinionsHook(plugin), plugin); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onMinionBreak(MinerBlockBreakEvent e) { Log.debug(Debug.BLOCK_BREAK, e.getBlock().getType()); InteractionResult interactionResult = this.stackedBlocksInteractionService.get() .handleStackedBlockBreak(e.getBlock(), null); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) { e.setCancelled(true); } else { this.worldRecordService.get().recordBlockBreak(e.getBlock(), REGULAR_RECORD_FLAGS); } } } ================================================ FILE: Hooks/LuckPerms/build.gradle ================================================ group 'Hooks:LuckPerms' dependencies { compileOnly 'net.luckperms:LuckPerms:5.1.15' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_luckperms') && !Boolean.valueOf(project.findProperty("hook.compile_luckperms").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/LuckPerms/src/main/java/com/bgsoftware/superiorskyblock/external/permissions/PermissionsProvider_LuckPerms.java ================================================ package com.bgsoftware.superiorskyblock.external.permissions; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore; import net.luckperms.api.LuckPerms; import net.luckperms.api.cacheddata.CachedDataManager; import net.luckperms.api.event.node.NodeAddEvent; import net.luckperms.api.event.node.NodeRemoveEvent; import net.luckperms.api.model.user.User; import net.luckperms.api.node.Node; import net.luckperms.api.node.types.InheritanceNode; import net.luckperms.api.node.types.PermissionNode; import net.luckperms.api.node.types.RegexPermissionNode; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.util.Locale; import java.util.UUID; @SuppressWarnings("unused") public class PermissionsProvider_LuckPerms implements PermissionsProvider { private final LuckPerms luckPerms; public static boolean isCompatible() { try { CachedDataManager.class.getMethod("getPermissionData"); return true; } catch (Throwable ex) { Log.warn("You are using an outdated version of LuckPerms. It's recommended to update for a more optimized experience (v5.1+)."); return false; } } public PermissionsProvider_LuckPerms(SuperiorSkyblockPlugin plugin) { this.luckPerms = Bukkit.getServicesManager().getRegistration(LuckPerms.class).getProvider(); this.luckPerms.getEventBus().subscribe(plugin, NodeAddEvent.class, this::onPermissionsAdd); this.luckPerms.getEventBus().subscribe(plugin, NodeRemoveEvent.class, this::onPermissionsRemove); Log.info("Using LuckPerms as a permissions provider."); } @Override public boolean hasPermission(Player player, String permission) { User user = this.luckPerms.getUserManager().getUser(player.getUniqueId()); return user != null && user.getCachedData().getPermissionData().getPermissionMap() .getOrDefault(permission.toLowerCase(Locale.ENGLISH), false); } private void onPermissionsAdd(NodeAddEvent e) { if (e.getTarget() instanceof User && isTrackableNode(e.getNode())) notifyPermissionsUpdate(((User) e.getTarget()).getUniqueId()); } private void onPermissionsRemove(NodeRemoveEvent e) { if (e.getTarget() instanceof User && isTrackableNode(e.getNode())) notifyPermissionsUpdate(((User) e.getTarget()).getUniqueId()); } private void notifyPermissionsUpdate(UUID playerUUID) { PlayerPermissionsStore permissionsStore = PlayerPermissionsStore.getPermissionsStore(playerUUID); if (permissionsStore != null) permissionsStore.markDirty(); } private static boolean isTrackableNode(Node node) { if (node instanceof PermissionNode) { return ((PermissionNode) node).getPermission().contains("superior"); } // In the case of RegexPermissionNode - we are not going to try and parse the regex. // In the case of InheritanceNode - we are not going to go through the inherited group and check for permissions. // We will always mark cache as dirty for both of these events. return node instanceof RegexPermissionNode || node instanceof InheritanceNode; } } ================================================ FILE: Hooks/MVdWPlaceholderAPI/build.gradle ================================================ group 'Hooks:MVdWPlaceholderAPI' dependencies { compileOnly 'be.maximvdw:MVdWPlaceholderAPI:3.0.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_mvdwplaceholderapi') && !Boolean.valueOf(project.findProperty("hook.compile_mvdwplaceholderapi").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/MVdWPlaceholderAPI/src/main/java/com/bgsoftware/superiorskyblock/external/placeholders/PlaceholdersProvider_MVdWPlaceholderAPI.java ================================================ package com.bgsoftware.superiorskyblock.external.placeholders; import be.maximvdw.placeholderapi.PlaceholderAPI; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl; import org.bukkit.OfflinePlayer; import java.util.regex.Pattern; @SuppressWarnings("unused") public class PlaceholdersProvider_MVdWPlaceholderAPI implements PlaceholdersProvider { private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); } }; private static final Pattern BUILT_IN_NUMERIC_PLACEHOLDER = Pattern.compile("\\{(\\d)}"); public PlaceholdersProvider_MVdWPlaceholderAPI(SuperiorSkyblockPlugin plugin) { Log.info("Using MVdWPlaceholderAPI for placeholders support."); PlaceholderAPI.registerPlaceholder(plugin, "superior_*", e -> ((PlaceholdersServiceImpl) placeholdersService.get()).handlePluginPlaceholder(e.getOfflinePlayer(), e.getPlaceholder().replace("superior_", ""))); } @Override public String parsePlaceholders(OfflinePlayer offlinePlayer, String value) { return PlaceholderAPI.replacePlaceholders(offlinePlayer, BUILT_IN_NUMERIC_PLACEHOLDER.matcher(value) .replaceAll("{%$1}")).replace("{%", "{"); } } ================================================ FILE: Hooks/MergedSpawner/build.gradle ================================================ group 'Hooks:MergedSpawner' dependencies { compileOnly 'com.vk2gpz:MergedSpawner:13.0.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_mergedspawner') && !Boolean.valueOf(project.findProperty("hook.compile_mergedspawner").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import com.vk2gpz.mergedspawner.api.MergedSpawnerAPI; import com.vk2gpz.mergedspawner.event.MergedSpawnerBreakEvent; import com.vk2gpz.mergedspawner.event.MergedSpawnerPlaceEvent; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; public class SpawnersProvider_MergedSpawner implements SpawnersProvider_AutoDetect { private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_MergedSpawner(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new SpawnersProvider_MergedSpawner.StackerListener(), plugin); Log.info("Using MergedSpawner as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; if (Bukkit.isPrimaryThread()) { MergedSpawnerAPI spawnerAPI = MergedSpawnerAPI.getInstance(); blockCount = spawnerAPI.getCountFor(location.getBlock()); } return new Pair<>(blockCount, null); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); return MergedSpawnerAPI.getInstance().getEntityType(itemStack).name(); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerStack(MergedSpawnerPlaceEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } int increaseAmount = e.getNewCount() - e.getOldCount(); if (island != null) island.handleBlockPlace(e.getBlock(), increaseAmount); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(MergedSpawnerBreakEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } int decreaseAmount = e.getOldCount() - e.getNewCount(); if (island != null) island.handleBlockBreak(Keys.ofSpawner(e.getSpawnerType()), decreaseAmount); } } } ================================================ FILE: Hooks/MiniMessage/build.gradle ================================================ group 'Hooks:MiniMessage' java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } repositories { mavenCentral() } dependencies { compileOnly("net.kyori:adventure-text-minimessage:4.17.0") compileOnly("net.kyori:adventure-text-serializer-plain:4.19.0") compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_minimessage') && !Boolean.valueOf(project.findProperty("hook.compile_minimessage").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.ParsingException; import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.YamlConfiguration; import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MiniMessageHook { private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().tags(StandardTags.defaults()).build(); private static boolean registered = false; private static final MessagesServiceImpl.CustomComponentParser PARSER = new MessagesServiceImpl.CustomComponentParser() { @Override public Optional parse(YamlConfiguration config, String path) { if (!config.isString(path)) return Optional.empty(); String content = config.getString(path); if (Text.isBlank(content)) return Optional.empty(); return parse(content); } @Override public Optional parse(String content) { try { Component component = MINI_MESSAGE.deserialize(Formatters.COLOR_FORMATTER.format(content)); return Optional.of(new MiniMessageComponent(component)); } catch (ParsingException error) { return Optional.empty(); } } }; public static void register(SuperiorSkyblockPlugin plugin) { if (!registered) { MessagesServiceImpl messagesService = (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class); messagesService.registerCustomComponentParser(PARSER); registered = true; } } private static class MiniMessageComponent implements IMessageComponent { private final Component component; private final MessageContent content; MiniMessageComponent(Component component) { this.component = component; this.content = findTextComponentContent(component); } @Override public Type getType() { return Type.COMPLEX_MESSAGE; } @Override public String getMessage() { return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { sender.sendMessage(Translator.translate(this.component, args)); } private static MessageContent findTextComponentContent(Component component) { if (component instanceof TextComponent textComponent) return MessageContent.parse(textComponent.content()); for (Component children : component.children()) { MessageContent childrenContent = findTextComponentContent(children); if (childrenContent != MessageContent.EMPTY) return childrenContent; } return MessageContent.EMPTY; } } private static class Translator { private static final Pattern ARG_PATTERN = Pattern.compile("\\{[0-9]+}"); static Component translate(Component input, Object... args) { Component output = input; if (args.length != 0) { output = output.replaceText(TextReplacementConfig.builder() .match(ARG_PATTERN) .replacement((result, builder) -> doReplacement(result, args)) .build()); output = translateClickEvent(output, args); } return translateChildren(output, args); } private static Component translateChildren(Component input, Object... args) { List children = new LinkedList<>(); for (Component component : input.children()) { Component output = translate(component, args); children.add(translateChildren(output, args)); } return input.children(children); } private static Component translateClickEvent(Component input, Object... args) { ClickEvent event = input.clickEvent(); if (event == null) return input; String value = event.value(); Matcher matcher = ARG_PATTERN.matcher(value); String result = matcher.replaceAll(match -> doTextReplacement(match, args)); return input.clickEvent(ClickEvent.clickEvent(event.action(), result)); } private static Component doReplacement(MatchResult match, Object... args) { String group = match.group(); int index = Integer.parseInt(group.substring(1, group.length() - 1)); return Component.text(index < args.length ? MessageContent.getArgumentString(args[index]) : group); } private static String doTextReplacement(MatchResult match, Object... args) { return PlainTextComponentSerializer.plainText().serialize(doReplacement(match, args)); } } } ================================================ FILE: Hooks/Nexo/build.gradle ================================================ group 'Hooks:Nexo' java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } repositories { mavenCentral() maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } } dependencies { compileOnly "com.nexomc:Nexo:0.9" compileOnly "org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_nexo') && !Boolean.valueOf(project.findProperty("hook.compile_nexo").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider; import com.nexomc.nexo.api.NexoBlocks; import com.nexomc.nexo.api.NexoFurniture; import com.nexomc.nexo.api.NexoItems; import com.nexomc.nexo.api.events.furniture.NexoFurnitureBreakEvent; import com.nexomc.nexo.api.events.furniture.NexoFurniturePlaceEvent; import com.nexomc.nexo.items.ItemBuilder; import com.nexomc.nexo.mechanics.Mechanic; import com.nexomc.nexo.mechanics.MechanicFactory; import com.nexomc.nexo.mechanics.MechanicsManager; import com.nexomc.nexo.mechanics.custom_block.noteblock.NoteBlockMechanicFactory; import com.nexomc.nexo.mechanics.custom_block.stringblock.StringBlockMechanicFactory; import com.nexomc.nexo.mechanics.furniture.FurnitureMechanic; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import java.util.LinkedList; import java.util.List; import java.util.Locale; public class NexoHook { private static final String NEXO_PREFIX = "NEXO"; private static final Key BLOCK_ITEM_KEY = Keys.of(Material.PAPER); private static final Key BLOCK_KEY = Keys.of(Material.NOTE_BLOCK); private static final List AVAILABLE_MECHANICS = new LinkedList<>(); private static final LazyReference worldRecordService = new LazyReference<>() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; private static boolean registered = false; private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { NexoHook.plugin = plugin; plugin.getServer().getPluginManager().registerEvents(new NexoListener(), plugin); if (!registered) { registered = true; plugin.getProviders().registerCustomBlocksProvider(new NexuCustomBlocksProvider()); BukkitExecutor.sync(NexoHook::initializeMechanics, 1L); plugin.getBlockValues().registerKeyParser(new NexoKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); } } private static void initializeMechanics() { MechanicsManager mechanicsManager = MechanicsManager.INSTANCE; AVAILABLE_MECHANICS.add(new MechanicData(mechanicsManager.getMechanicFactory("noteblock"), NoteBlockMechanicFactory.Companion::setBlockModel)); AVAILABLE_MECHANICS.add(new MechanicData(mechanicsManager.getMechanicFactory("stringblock"), StringBlockMechanicFactory.Companion::setBlockModel)); } private static class NexuCustomBlocksProvider implements ICustomBlocksProvider { @Nullable @Override public KeyMap getBlockCountsForChunk(ChunkPosition chunkPosition) { if (!Bukkit.isPrimaryThread()) return null; World world = chunkPosition.getWorld(); if (!world.isChunkLoaded(chunkPosition.getX(), chunkPosition.getZ())) return KeyMaps.createEmptyMap(); KeyMap blockCounts = KeyMaps.createHashMap(KeyIndicator.CUSTOM); Chunk chunk = world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ()); for (Entity entity : chunk.getEntities()) { FurnitureMechanic mechanic = NexoFurniture.furnitureMechanic(entity); if (mechanic != null) { Key blockKey = Keys.of(NEXO_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); blockCounts.put(blockKey, blockCounts.getRaw(blockKey, 0) + 1); } } return blockCounts; } } private static class NexoListener implements Listener { @WorldRecordFlags private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; @WorldRecordFlags private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS; @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onNexoBlockBreak(BlockBreakEvent e) { Key blockKey = Keys.of(e.getBlock()); if (blockKey.getGlobalKey().equals(NEXO_PREFIX)) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { worldRecordService.get().recordBlockBreak(blockKey, e.getBlock().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS); } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onFurniturePlace(NexoFurniturePlaceEvent e) { Key blockKey = Keys.of(NEXO_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(wrapper.getHandle()), 1, null, REGULAR_RECORD_FLAGS); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onFurnitureBreak(NexoFurnitureBreakEvent e) { Key blockKey = Keys.of(NEXO_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { worldRecordService.get().recordBlockBreak(blockKey, e.getBaseEntity().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onIslandGenerateBlock(IslandGenerateBlockEvent event) { if (!event.getBlock().getGlobalKey().equals(NEXO_PREFIX)) return; String itemId = event.getBlock().getSubKey().toLowerCase(Locale.ENGLISH); if (!NexoItems.exists(itemId)) { event.setCancelled(true); return; } for (MechanicData mechanic : AVAILABLE_MECHANICS) { if (mechanic.mechanicFactory != null && !mechanic.mechanicFactory.isNotImplementedIn(itemId)) { event.setPlaceBlock(false); mechanic.setBlockModelFunction.setBlockModel(event.getLocation().getBlock(), itemId); return; } } // No mechanic was found event.setCancelled(true); } } private static class NexoKeyParser implements CustomKeyParser { @Override public Key getCustomKey(Location location) { Mechanic mechanic = NexoBlocks.customBlockMechanic(location); if (mechanic == null) return BLOCK_KEY; return Keys.of(NEXO_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); } @Override public Key getCustomKey(ItemStack itemStack, Key def) { String itemId = NexoItems.idFromItem(itemStack); if (itemId == null) return def; return Keys.of(NEXO_PREFIX, itemId.toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); } @Override public boolean isCustomKey(Key key) { return key.getGlobalKey().equals(NEXO_PREFIX); } @Override @Nullable public ItemStack getCustomKeyItem(Key key) { ItemBuilder itemBuilder = NexoItems.itemFromId(key.getSubKey().toLowerCase(Locale.ENGLISH)); if (itemBuilder == null) return null; return itemBuilder.build(); } } private record MechanicData(MechanicFactory mechanicFactory, SetBlockModelFunction setBlockModelFunction) { } private interface SetBlockModelFunction { void setBlockModel(Block block, String itemId); } } ================================================ FILE: Hooks/OpenJdkNashornEngine/build.gradle ================================================ group 'Hooks:OpenJdkNashornEngine' java { toolchain { languageVersion.set(JavaLanguageVersion.of(11)) } } repositories { mavenCentral() } dependencies { compileOnly 'org.openjdk.nashorn:nashorn-core:15.4' compileOnly project(":API") compileOnly project(":") } ================================================ FILE: Hooks/OpenJdkNashornEngine/src/main/java/com/bgsoftware/superiorskyblock/core/engine/OpenJdkNashornEngine.java ================================================ package com.bgsoftware.superiorskyblock.core.engine; import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.util.Arrays; import java.util.List; public class OpenJdkNashornEngine implements IScriptEngine { private static final List JAVASCRIPT_ENGINE_NAMES = Arrays.asList( "js", "JS", "javascript", "JavaScript", "ecmascript", "ECMAScript", "nashorn", "Nashorn" ); private static final OpenJdkNashornEngine INSTANCE = new OpenJdkNashornEngine(); public static OpenJdkNashornEngine getInstance() { return INSTANCE; } private final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); private final ScriptEngine engine; private OpenJdkNashornEngine() { ScriptEngineFactory factory = new NashornScriptEngineFactory(); JAVASCRIPT_ENGINE_NAMES.forEach(n -> scriptEngineManager.registerEngineName(n, factory)); engine = scriptEngineManager.getEngineByName("nashorn"); } @Override public Object eval(String stringToEvaluate) throws ScriptException { return engine.eval(stringToEvaluate); } @Override public Object eval(String stringToEvaluate, Bindings bindings) throws ScriptException { return engine.eval(stringToEvaluate, bindings); } } ================================================ FILE: Hooks/Oraxen/build.gradle ================================================ group 'Hooks:Oraxen' java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } dependencies { compileOnly 'io.th0rgal:Oraxen:1.187.0' compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_oraxen') && !Boolean.valueOf(project.findProperty("hook.compile_oraxen").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider; import io.th0rgal.oraxen.api.OraxenBlocks; import io.th0rgal.oraxen.api.OraxenFurniture; import io.th0rgal.oraxen.api.OraxenItems; import io.th0rgal.oraxen.api.events.furniture.OraxenFurnitureBreakEvent; import io.th0rgal.oraxen.api.events.furniture.OraxenFurniturePlaceEvent; import io.th0rgal.oraxen.items.ItemBuilder; import io.th0rgal.oraxen.mechanics.Mechanic; import io.th0rgal.oraxen.mechanics.MechanicFactory; import io.th0rgal.oraxen.mechanics.MechanicsManager; import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory; import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureMechanic; import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory; import io.th0rgal.oraxen.mechanics.provided.gameplay.stringblock.StringBlockMechanicFactory; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; public class OraxenHook { private static final String ORAXEN_PREFIX = "ORAXEN"; private static final Key BLOCK_ITEM_KEY = Keys.of(Material.PAPER); private static final Key BLOCK_KEY = Keys.of(Material.NOTE_BLOCK); private static final List AVAILABLE_MECHANICS = initializeMechanics(); private static List initializeMechanics() { List mechanics = new LinkedList<>(); try { Class.forName("io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory"); mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("block"), BlockMechanicFactory::setBlockModel)); mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("noteblock"), NoteBlockMechanicFactory::setBlockModel)); mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("stringblock"), StringBlockMechanicFactory::setBlockModel)); } catch (Throwable error) { { ReflectMethod setBlockModel = new ReflectMethod<>( new ClassInfo("io.th0rgal.oraxen.mechanics.provided.block.BlockMechanicFactory", ClassInfo.PackageType.UNKNOWN), "setBlockModel", Block.class, String.class); mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("block"), (block, itemId) -> { if (setBlockModel.isValid()) setBlockModel.invoke(null, block, itemId); })); } { ReflectMethod setBlockModel = new ReflectMethod<>( new ClassInfo("io.th0rgal.oraxen.mechanics.provided.noteblock.NoteBlockMechanicFactory", ClassInfo.PackageType.UNKNOWN), "setBlockModel", Block.class, String.class); mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("noteblock"), (block, itemId) -> { if (setBlockModel.isValid()) setBlockModel.invoke(null, block, itemId); })); } } return Collections.unmodifiableList(mechanics); } private static final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; private static boolean registered = false; private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { OraxenHook.plugin = plugin; plugin.getServer().getPluginManager().registerEvents(new OraxenListener(), plugin); if (!registered) { registered = true; plugin.getProviders().registerCustomBlocksProvider(new OraxenCustomBlocksProvider()); plugin.getBlockValues().registerKeyParser(new OraxenKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); } } private static class OraxenCustomBlocksProvider implements ICustomBlocksProvider { @Nullable @Override public KeyMap getBlockCountsForChunk(ChunkPosition chunkPosition) { if (!Bukkit.isPrimaryThread()) return null; World world = chunkPosition.getWorld(); if (!world.isChunkLoaded(chunkPosition.getX(), chunkPosition.getZ())) return KeyMaps.createEmptyMap(); KeyMap blockCounts = KeyMaps.createHashMap(KeyIndicator.CUSTOM); Chunk chunk = world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ()); for (Entity entity : chunk.getEntities()) { FurnitureMechanic mechanic = OraxenFurniture.getFurnitureMechanic(entity); if (mechanic != null) { Key blockKey = Keys.of(ORAXEN_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); blockCounts.put(blockKey, blockCounts.getRaw(blockKey, 0) + 1); } } return blockCounts; } } private static class OraxenListener implements Listener { @WorldRecordFlags private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; @WorldRecordFlags private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS; @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onOraxenBlockBreak(BlockBreakEvent e) { Key blockKey = Keys.of(e.getBlock()); if (blockKey.getGlobalKey().equals(ORAXEN_PREFIX)) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { worldRecordService.get().recordBlockBreak(blockKey, e.getBlock().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS); } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onFurniturePlace(OraxenFurniturePlaceEvent e) { Key blockKey = Keys.of(ORAXEN_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(wrapper.getHandle()), 1, null, REGULAR_RECORD_FLAGS); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onFurnitureBreak(OraxenFurnitureBreakEvent e) { Key blockKey = Keys.of(ORAXEN_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { worldRecordService.get().recordBlockBreak(blockKey, e.getBaseEntity().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onIslandGenerateBlock(IslandGenerateBlockEvent event) { if (!event.getBlock().getGlobalKey().equals(ORAXEN_PREFIX)) return; String itemId = event.getBlock().getSubKey().toLowerCase(Locale.ENGLISH); if (!OraxenItems.exists(itemId)) { event.setCancelled(true); return; } for (MechanicData mechanic : AVAILABLE_MECHANICS) { if (mechanic.mechanicFactory != null && !mechanic.mechanicFactory.isNotImplementedIn(itemId)) { event.setPlaceBlock(false); mechanic.setBlockModelFunction.setBlockModel(event.getLocation().getBlock(), itemId); return; } } // No mechanic was found event.setCancelled(true); } } private static class OraxenKeyParser implements CustomKeyParser { @Override public Key getCustomKey(Location location) { Mechanic mechanic = OraxenBlocks.getOraxenBlock(location); if (mechanic == null) return BLOCK_KEY; return Keys.of(ORAXEN_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); } @Override public Key getCustomKey(ItemStack itemStack, Key def) { String itemId = OraxenItems.getIdByItem(itemStack); if (itemId == null) return def; return Keys.of(ORAXEN_PREFIX, itemId.toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); } @Override public boolean isCustomKey(Key key) { return key.getGlobalKey().equals(ORAXEN_PREFIX); } @Override @Nullable public ItemStack getCustomKeyItem(Key key) { ItemBuilder itemBuilder = OraxenItems.getItemById(key.getSubKey().toLowerCase(Locale.ENGLISH)); if (itemBuilder == null) return null; return itemBuilder.build(); } } private record MechanicData(MechanicFactory mechanicFactory, SetBlockModelFunction setBlockModelFunction) { } private interface SetBlockModelFunction { void setBlockModel(Block block, String itemId); } } ================================================ FILE: Hooks/PaperMC/build.gradle ================================================ group 'Hooks:PaperMC' dependencies { compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_papermc') && !Boolean.valueOf(project.findProperty("hook.compile_papermc").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/PaperMC/src/main/java/com/bgsoftware/superiorskyblock/external/async/AsyncProvider_Paper.java ================================================ package com.bgsoftware.superiorskyblock.external.async; import com.bgsoftware.superiorskyblock.external.async.AsyncProvider; import org.bukkit.Location; import org.bukkit.entity.Entity; import java.util.function.Consumer; public class AsyncProvider_Paper implements AsyncProvider { @Override public void teleport(Entity entity, Location location, Consumer teleportResult) { entity.teleportAsync(location).whenComplete((result, ex) -> { if (teleportResult != null) teleportResult.accept(result); }); } } ================================================ FILE: Hooks/PaperMC/src/main/java/com/bgsoftware/superiorskyblock/external/chunks/ChunksProvider_Paper.java ================================================ package com.bgsoftware.superiorskyblock.external.chunks; import com.bgsoftware.superiorskyblock.api.hooks.ChunksProvider; import org.bukkit.Chunk; import org.bukkit.World; import java.util.concurrent.CompletableFuture; public class ChunksProvider_Paper implements ChunksProvider { @Override public CompletableFuture loadChunk(World world, int chunkX, int chunkZ) { return world.getChunkAtAsync(chunkX, chunkZ); } } ================================================ FILE: Hooks/PaperMC/src/main/java/com/bgsoftware/superiorskyblock/external/remapper/PluginRemapperFilesLookupProvider.java ================================================ package com.bgsoftware.superiorskyblock.external.remapper; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupProvider; import java.io.File; import java.nio.file.Path; import java.util.LinkedList; import java.util.List; public class PluginRemapperFilesLookupProvider implements FilesLookupProvider { private static final ReflectMethod CREATE_PLUGIN_REMAPPER; private static final ReflectMethod PLUGIN_REMAPPER_REWRITE_PLUGIN_DIRECTORY; private static final ReflectMethod PLUGIN_REMAPPER_REWRITE_PLUGIN; private static final ReflectMethod PLUGIN_REMAPPER_LOADING_PLUGINS; private static final ReflectMethod PLUGIN_REMAPPER_PLUGINS_ENABLED; private static final ReflectMethod PLUGIN_REMAPPER_SHUTDOWN; static { ClassInfo pluginRemapperClassInfo = new ClassInfo("io.papermc.paper.pluginremap.PluginRemapper", ClassInfo.PackageType.UNKNOWN); CREATE_PLUGIN_REMAPPER = new ReflectMethod<>(pluginRemapperClassInfo, "create", Path.class); PLUGIN_REMAPPER_REWRITE_PLUGIN_DIRECTORY = new ReflectMethod<>(pluginRemapperClassInfo, "rewritePluginDirectory", List.class); PLUGIN_REMAPPER_REWRITE_PLUGIN = new ReflectMethod<>(pluginRemapperClassInfo, "rewritePlugin", Path.class); PLUGIN_REMAPPER_LOADING_PLUGINS = new ReflectMethod<>(pluginRemapperClassInfo, "loadingPlugins", new Class[0]); PLUGIN_REMAPPER_PLUGINS_ENABLED = new ReflectMethod<>(pluginRemapperClassInfo, "pluginsEnabled", new Class[0]); PLUGIN_REMAPPER_SHUTDOWN = new ReflectMethod<>(pluginRemapperClassInfo, "shutdown", new Class[0]); } @Override public FilesLookup createFilesLookup(File folder) { Object pluginRemapper = CREATE_PLUGIN_REMAPPER.invoke(null, folder.toPath()); if (pluginRemapper == null) throw new IllegalStateException("Cannot create PluginRemapper"); PLUGIN_REMAPPER_LOADING_PLUGINS.invoke(pluginRemapper); List folderFiles = new LinkedList<>(); for (File file : Files.listFolderFiles(folder, false, file -> file.getName().endsWith(".jar"))) { folderFiles.add(file.toPath()); } PLUGIN_REMAPPER_REWRITE_PLUGIN_DIRECTORY.invoke(pluginRemapper, folderFiles); File remappedFolder = new File(folder, ".paper-remapped"); if (!remappedFolder.isDirectory()) throw new IllegalStateException("Cannot find remapped folder: " + remappedFolder.getAbsolutePath()); return new PluginRemapperFilesLookup(remappedFolder, pluginRemapper); } private static class PluginRemapperFilesLookup implements FilesLookup { private final File remappedFolder; private Object pluginRemapper; public PluginRemapperFilesLookup(File remappedFolder, Object pluginRemapper) { this.remappedFolder = remappedFolder; this.pluginRemapper = pluginRemapper; } @Override public File getFile(String name) { File file = new File(this.remappedFolder, name); return PLUGIN_REMAPPER_REWRITE_PLUGIN.invoke(this.pluginRemapper, file.toPath()).toFile(); } @Override public void close() { PLUGIN_REMAPPER_PLUGINS_ENABLED.invoke(this.pluginRemapper); PLUGIN_REMAPPER_SHUTDOWN.invoke(this.pluginRemapper); this.pluginRemapper = null; } } } ================================================ FILE: Hooks/PlaceholderAPI/build.gradle ================================================ group 'Hooks:PlaceholderAPI' dependencies { compileOnly 'me.clip:PlaceholderAPI:2.10.3' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_placeholderapi') && !Boolean.valueOf(project.findProperty("hook.compile_placeholderapi").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/PlaceholderAPI/src/main/java/com/bgsoftware/superiorskyblock/external/placeholders/PlaceholdersProvider_PlaceholderAPI.java ================================================ package com.bgsoftware.superiorskyblock.external.placeholders; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl; import me.clip.placeholderapi.PlaceholderAPI; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; @SuppressWarnings("unused") public class PlaceholdersProvider_PlaceholderAPI implements PlaceholdersProvider { private final SuperiorSkyblockPlugin plugin; public PlaceholdersProvider_PlaceholderAPI(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; new EZPlaceholder((PlaceholdersServiceImpl) plugin.getServices().getService(PlaceholdersService.class)).register(); Log.info("Using PlaceholderAPI for placeholders support."); } @Override public String parsePlaceholders(OfflinePlayer offlinePlayer, String value) { return PlaceholderAPI.setPlaceholders(offlinePlayer, value); } private class EZPlaceholder extends PlaceholderExpansion { private final PlaceholdersServiceImpl placeholdersService; public EZPlaceholder(PlaceholdersServiceImpl placeholdersService) { this.placeholdersService = placeholdersService; } @Override public String getIdentifier() { return "superior"; } @Override public String getAuthor() { return "Ome_R"; } @Override public String getVersion() { return plugin.getDescription().getVersion(); } @Override public boolean persist() { return true; } @Override public String onRequest(OfflinePlayer player, String placeholder) { return placeholdersService.handlePluginPlaceholder(player, placeholder); } @Override public String onPlaceholderRequest(Player player, String placeholder) { return onRequest(player, placeholder); } } } ================================================ FILE: Hooks/Plan/build.gradle ================================================ group 'Hooks:Plan' java { toolchain { languageVersion = JavaLanguageVersion.of(8) } } repositories { maven { url 'https://jitpack.io' } } dependencies { compileOnly project(":API") compileOnly rootProject compileOnly 'org.spigotmc:v1_8_R3-Taco:latest' compileOnly 'com.github.plan-player-analytics:Plan:5.7.3232' } if (project.hasProperty('hook.compile_plan') && !Boolean.valueOf(project.findProperty("hook.compile_plan").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/Plan/src/main/java/com/bgsoftware/superiorskyblock/external/PlanHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.djrapitops.plan.capability.CapabilityService; import com.djrapitops.plan.extension.DataExtension; import com.djrapitops.plan.extension.ExtensionService; import com.djrapitops.plan.extension.annotation.NumberProvider; import com.djrapitops.plan.extension.annotation.PluginInfo; import com.djrapitops.plan.extension.annotation.TableProvider; import com.djrapitops.plan.extension.icon.Color; import com.djrapitops.plan.extension.icon.Icon; import com.djrapitops.plan.extension.table.Table; import java.math.BigDecimal; import java.util.List; public class PlanHook { public static void register(SuperiorSkyblockPlugin plugin) { try { Log.info("Plan detected - attempting to register SuperiorSkyblock DataExtension."); if (CapabilityService.getInstance().hasCapability("DATA_EXTENSION_VALUES")) { ExtensionService.getInstance().register(new PlanDataExtension(plugin)); Log.info("Registered SuperiorSkyblock Plan DataExtension."); } else { Log.warn("Plan installed but DataExtension capability not available - skipping registration."); } } catch (Throwable t) { Log.error(t, "Failed to initialize Plan integration:"); } } private PlanHook() { } @PluginInfo(name = "SuperiorSkyblock") private static class PlanDataExtension implements DataExtension { private final SuperiorSkyblockPlugin plugin; PlanDataExtension(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @NumberProvider( text = "Total Islands", description = "Total number of islands on the server", priority = 100 ) public long islandCount() { return plugin.getGrid().getIslandsContainer().getIslandsAmount(); } @NumberProvider( text = "Total Island Level", description = "Sum of all island levels", priority = 90 ) public long totalLevel() { return plugin.getGrid().getTotalLevel().toBigInteger().longValue(); } @NumberProvider( text = "Total Island Worth", description = "Sum of all island worths", priority = 80 ) public long totalWorth() { return plugin.getGrid().getTotalWorth().toBigInteger().longValue(); } @NumberProvider( text = "Active Islands", description = "Islands that currently have visitors", priority = 70 ) public long activeIslands() { return plugin.getGrid().getIslands().stream() .filter(island -> !island.getIslandVisitors().isEmpty()) .count(); } @NumberProvider( text = "Islands With Bank Balance", description = "Islands that have money in their bank", priority = 60 ) public long islandsWithBankBalance() { return plugin.getGrid().getIslands().stream() .filter(island -> island.getIslandBank() != null && island.getIslandBank().getBalance().compareTo(BigDecimal.ZERO) > 0) .count(); } @NumberProvider( text = "Average Island Level", description = "Average level across all islands", priority = 50 ) public long averageIslandLevel() { List islands = plugin.getGrid().getIslands(); if (islands.isEmpty()) return 0L; BigDecimal sum = BigDecimal.ZERO; int count = 0; for (Island island : islands) { BigDecimal lvl = island.getIslandLevel(); if (lvl != null) { sum = sum.add(lvl); count++; } } if (count == 0) return 0L; return sum.divide(BigDecimal.valueOf(count), 0, plugin.getSettings().getIslandLevelRoundingMode()) .toBigInteger().longValue(); } @TableProvider( tableColor = Color.GREEN ) public Table topIslandsTable() { List islands = plugin.getGrid().getIslands(SortingTypes.BY_WORTH); Table.Factory table = Table.builder() .columnOne("Pos", Icon.called("list-ol").build()) .columnTwo("Owner", Icon.called("user").build()) .columnThree("Island", Icon.called("home").build()) .columnFour("Level", Icon.called("star").build()) .columnFive("Worth", Icon.called("coins").build()); int pos = 1; for (Island island : islands) { if (pos > 25) break; BigDecimal worth = island.getWorth(); BigDecimal level = island.getIslandLevel(); String ownerName = island.getOwner() == null ? "" : island.getOwner().getName(); String islandName = island.getName() == null || island.getName().isEmpty() ? ownerName : island.getName(); table.addRow(pos, ownerName, islandName, level == null ? 0L : level.toBigInteger().longValue(), worth == null ? 0L : worth.toBigInteger().longValue() ); pos++; } return table.build(); } } } ================================================ FILE: Hooks/ProtocolLib/build.gradle ================================================ group 'Hooks:ProtocolLib' dependencies { compileOnly "com.comphenix.protocol:ProtocolLib:4.8.0" compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_protocollib') && !Boolean.valueOf(project.findProperty("hook.compile_protocollib").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/ProtocolLib/src/main/java/com/bgsoftware/superiorskyblock/external/ProtocolLibHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import java.util.Locale; public class ProtocolLibHook { private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { ProtocolLibHook.plugin = plugin; ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager(); protocolManager.addPacketListener(new ChangePlayerLanguageListener(plugin)); } private static class ChangePlayerLanguageListener extends PacketAdapter { private ChangePlayerLanguageListener(SuperiorSkyblockPlugin plugin) { super(plugin, PacketType.Play.Client.SETTINGS); } @Override public void onPacketReceiving(PacketEvent event) { if (!ProtocolLibHook.plugin.getSettings().isAutoLanguageDetection() || event.getPlayer() == null || event.isPlayerTemporary()) return; PacketContainer packetContainer = event.getPacket(); Locale newPlayerLocale; try { newPlayerLocale = PlayerLocales.getLocale(packetContainer.getStrings().read(0)); } catch (Throwable error) { return; } SuperiorPlayer superiorPlayer = ProtocolLibHook.plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(event.getPlayer().getUniqueId()); if (superiorPlayer != null && PlayerLocales.isValidLocale(newPlayerLocale) && !superiorPlayer.getUserLocale().equals(newPlayerLocale)) { if (PluginEventsFactory.callPlayerChangeLanguageEvent(superiorPlayer, newPlayerLocale)) superiorPlayer.setUserLocale(newPlayerLocale); } } } } ================================================ FILE: Hooks/PvpingSpawners/build.gradle ================================================ group 'Hooks:PvpingSpawners' dependencies { compileOnly 'skyblock.hassan:PvpingSpawners:1.3' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_pvpingspawners') && !Boolean.valueOf(project.findProperty("hook.compile_pvpingspawners").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.CreatureSpawner; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import skyblock.hassan.plugin.Main; import skyblock.hassan.plugin.api.SpawnerStackEvent; import skyblock.hassan.plugin.api.SpawnerUnstackEvent; import skyblock.hassan.plugin.spawners.StackedSpawner; public class SpawnersProvider_PvpingSpawners implements SpawnersProviderItemMetaSpawnerType { private final SuperiorSkyblockPlugin plugin; private final Main main; public SpawnersProvider_PvpingSpawners(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; main = (Main) Bukkit.getPluginManager().getPlugin("PvpingSpawners"); Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using PvpingSpawners as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; if (Bukkit.isPrimaryThread()) { StackedSpawner stackedSpawner = main.getProps().getStackedSpawner(main, (CreatureSpawner) location.getBlock().getState()); blockCount = stackedSpawner.getSize(); } return new Pair<>(blockCount, null); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerStack(SpawnerStackEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location spawnerLocation = e.getSpawner().getLocation(wrapper.getHandle()); island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(spawnerLocation)); if (island != null) island.handleBlockPlace(spawnerLocation.getBlock(), e.getSpawnerAmount()); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerUnstackEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location spawnerLocation = e.getSpawner().getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(spawnerLocation); if (island != null) island.handleBlockBreak(spawnerLocation.getBlock(), e.getSpawnerAmount()); } } } } ================================================ FILE: Hooks/RoseStacker/build.gradle ================================================ group 'Hooks:RoseStacker' dependencies { compileOnly 'dev.rosewood:RoseStacker:1.4.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_rosestacker') && !Boolean.valueOf(project.findProperty("hook.compile_rosestacker").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/entities/EntitiesProvider_RoseStacker.java ================================================ package com.bgsoftware.superiorskyblock.external.entities; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import dev.rosewood.rosestacker.api.RoseStackerAPI; import dev.rosewood.rosestacker.stack.StackedEntity; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDeathEvent; import java.util.UUID; import java.util.concurrent.TimeUnit; public class EntitiesProvider_RoseStacker implements EntitiesProvider { private final AutoRemovalCollection stackedEntityDeaths = AutoRemovalCollection.newHashSet(5, TimeUnit.SECONDS); private final SuperiorSkyblockPlugin plugin; public EntitiesProvider_RoseStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; plugin.getServer().getPluginManager().registerEvents(new DeathListener(), plugin); } @Override public boolean shouldTrackEntity(Entity entity) { return !stackedEntityDeaths.contains(entity.getUniqueId()); } private class DeathListener implements Listener { @EventHandler public void onEntityDeath(EntityDeathEvent e) { if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class) || !BukkitEntities.canHaveLimit(e.getEntityType()) || BukkitEntities.canBypassEntityLimit(e.getEntity(), false)) return; StackedEntity stackedEntity = RoseStackerAPI.getInstance().getStackedEntity(e.getEntity()); if (stackedEntity == null || stackedEntity.getStackSize() <= 1) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); } if (island == null) return; stackedEntityDeaths.add(e.getEntity().getUniqueId()); } } } ================================================ FILE: Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import dev.rosewood.rosestacker.api.RoseStackerAPI; import dev.rosewood.rosestacker.event.SpawnerStackEvent; import dev.rosewood.rosestacker.event.SpawnerUnstackEvent; import dev.rosewood.rosestacker.stack.StackedSpawner; import dev.rosewood.rosestacker.utils.ItemUtils; import dev.rosewood.rosestacker.utils.StackerUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; public class SpawnersProvider_RoseStacker implements SpawnersProvider_AutoDetect { private static final ReflectMethod GET_STACKED_ITEM_ENTITY_TYPE = new ReflectMethod<>(StackerUtils.class, "getStackedItemEntityType", ItemStack.class); private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_RoseStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using RoseStacker as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; if (Bukkit.isPrimaryThread()) { StackedSpawner stackedSpawner = RoseStackerAPI.getInstance().getStackedSpawner(location.getBlock()); blockCount = stackedSpawner == null ? 1 : stackedSpawner.getStackSize(); } return new Pair<>(blockCount, null); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); EntityType entityType = GET_STACKED_ITEM_ENTITY_TYPE.isValid() ? GET_STACKED_ITEM_ENTITY_TYPE.invoke(null, itemStack) : ItemUtils.getStackedItemEntityType(itemStack); return entityType == null ? null : entityType.name(); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerStack(SpawnerStackEvent e) { Location location = e.getStack().getLocation(); Island island = plugin.getGrid().getIslandAt(location); if (island != null) { Key blockKey = Keys.of(e.getStack().getBlock()); int increaseAmount = e.getStack().getStackSize() + e.getIncreaseAmount() > e.getStack().getStackSettings().getMaxStackSize() ? e.getStack().getStackSettings().getMaxStackSize() - e.getStack().getStackSize() : e.getIncreaseAmount(); int newBlocksCount = e.isNew() ? Math.max(1, increaseAmount - 1) : increaseAmount; if (island.hasReachedBlockLimit(blockKey, newBlocksCount)) { e.setCancelled(true); } else { island.handleBlockPlace(blockKey, newBlocksCount); } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerUnstackEvent e) { Location location = e.getStack().getLocation(); Island island = plugin.getGrid().getIslandAt(location); if (island != null) { island.handleBlockBreak(Keys.of(e.getStack().getBlock()), e.getDecreaseAmount()); } } } } ================================================ FILE: Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java ================================================ package com.bgsoftware.superiorskyblock.external.stackedblocks; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.google.common.base.Preconditions; import dev.rosewood.rosestacker.api.RoseStackerAPI; import dev.rosewood.rosestacker.event.BlockStackEvent; import dev.rosewood.rosestacker.event.BlockUnstackEvent; import dev.rosewood.rosestacker.stack.StackedBlock; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerInteractEvent; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; public class StackedBlocksProvider_RoseStacker implements StackedBlocksProvider_AutoDetect { private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @Override protected RegionManagerService create() { return plugin.getServices().getService(RegionManagerService.class); } }; public StackedBlocksProvider_RoseStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using RoseStacker as a stacked-blocks provider."); } @Override public Collection> getBlocks(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); if (!Bukkit.isPrimaryThread()) return null; Map blockKeys = new HashMap<>(); try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ); ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { RoseStackerAPI.getInstance().getStackedBlocks().entrySet().stream() .filter(entry -> chunkPosition.isInsideChunk(entry.getKey().getLocation(wrapper.getHandle()))) .forEach(entry -> { Key blockKey = Key.of(entry.getKey()); blockKeys.put(blockKey, blockKeys.getOrDefault(blockKey, 0) + entry.getValue().getStackSize()); }); } return blockKeys.entrySet().stream() .map(entry -> new Pair<>(entry.getKey(), entry.getValue())) .collect(Collectors.toSet()); } private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockStack(BlockStackEvent e) { Location location = e.getStack().getLocation(); Island island = plugin.getGrid().getIslandAt(location); if (island == null) return; Key blockKey = Keys.of(e.getStack().getBlock()); int increaseAmount = e.getStack().getStackSize() + e.getIncreaseAmount() > e.getStack().getStackSettings().getMaxStackSize() ? e.getStack().getStackSettings().getMaxStackSize() - e.getStack().getStackSize() : e.getIncreaseAmount(); int newBlocksCount = e.isNew() ? Math.max(1, increaseAmount - 1) : increaseAmount; if (island.hasReachedBlockLimit(blockKey, newBlocksCount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, newBlocksCount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockUnstack(BlockUnstackEvent e) { Location location = e.getStack().getLocation(); Island island = plugin.getGrid().getIslandAt(location); if (island != null) { island.handleBlockBreak(e.getStack().getBlock(), e.getDecreaseAmount()); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockStackProtection(BlockStackEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); InteractionResult interactionResult = protectionManager.get().handleBlockPlace(superiorPlayer, e.getStack().getBlock()); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockUnstackProtection(BlockUnstackEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); InteractionResult interactionResult = protectionManager.get().handleBlockBreak(superiorPlayer, e.getStack().getBlock()); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockStackInteractionProtection(PlayerInteractEvent e) { if (e.getClickedBlock() == null || e.getPlayer().isSneaking()) return; StackedBlock stackedBlock = RoseStackerAPI.getInstance().getStackedBlock(e.getClickedBlock()); if (stackedBlock == null) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); InteractionResult interactionResult = protectionManager.get().handleBlockPlace(superiorPlayer, e.getClickedBlock()); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } } } ================================================ FILE: Hooks/SkinsRestorer/build.gradle ================================================ group 'Hooks:SkinsRestorer' dependencies { compileOnly 'net.skinsrestorer:SkinsRestorer:13.7.5' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_skinsrestorer') && !Boolean.valueOf(project.findProperty("hook.compile_skinsrestorer").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/SkinsRestorer/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorerHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.mojang.authlib.properties.Property; import skinsrestorer.bukkit.SkinsRestorer; import skinsrestorer.shared.exception.SkinRequestException; import skinsrestorer.shared.storage.SkinStorage; @SuppressWarnings("unused") public class SkinsRestorerHook { private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { SkinsRestorerHook.plugin = plugin; plugin.getProviders().registerSkinsListener(SkinsRestorerHook::setSkinTexture); } private static void setSkinTexture(SuperiorPlayer superiorPlayer) { BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer)); } private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) { Property property = getSkin(superiorPlayer); if (property != null) BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property)); } public static Property getSkin(SuperiorPlayer superiorPlayer) { try { SkinStorage skinStorage = SkinsRestorer.getInstance().getSkinStorage(); return (Property) skinStorage.getOrCreateSkinForPlayer(superiorPlayer.getName(), true); } catch (SkinRequestException | NullPointerException ignored) { return null; } } } ================================================ FILE: Hooks/SkinsRestorer14/build.gradle ================================================ group 'Hooks:SkinsRestorer14' dependencies { compileOnly 'net.skinsrestorer:SkinsRestorer:14.1.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_skinsrestorer') && !Boolean.valueOf(project.findProperty("hook.compile_skinsrestorer").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/SkinsRestorer14/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer14Hook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.mojang.authlib.properties.Property; import net.skinsrestorer.api.SkinsRestorerAPI; import net.skinsrestorer.api.bukkit.events.SkinApplyBukkitEvent; import net.skinsrestorer.api.property.IProperty; import net.skinsrestorer.shared.storage.Config; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; import java.nio.file.Path; public class SkinsRestorer14Hook { private static final ReflectMethod SKINS_RESTORER_GET_SKIN = new ReflectMethod<>(SkinsRestorerAPI.class, "getSkinData", String.class); private static SuperiorSkyblockPlugin plugin; public static boolean isCompatible() { if (Config.MYSQL_ENABLED) return true; ReflectField skinsFolderMethod = new ReflectField<>(net.skinsrestorer.shared.storage.SkinStorage.class, Object.class, "skinsFolder"); if (!skinsFolderMethod.isValid()) return false; net.skinsrestorer.bukkit.SkinsRestorer skinsRestorer = JavaPlugin.getPlugin(net.skinsrestorer.bukkit.SkinsRestorer.class); Object skinsFolder = skinsFolderMethod.get(skinsRestorer.getSkinStorage()); if (skinsFolder instanceof File) { return ((File) skinsFolder).exists(); } else if (skinsFolder instanceof Path) { return ((Path) skinsFolder).toFile().exists(); } return false; } public static void register(SuperiorSkyblockPlugin plugin) { SkinsRestorer14Hook.plugin = plugin; plugin.getProviders().registerSkinsListener(SkinsRestorer14Hook::setSkinTexture); plugin.getServer().getPluginManager().registerEvents(new SkinsListener(), plugin); } private static void setSkinTexture(SuperiorPlayer superiorPlayer) { BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer)); } private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) { Property property = getSkin(superiorPlayer); if (property != null) BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property)); } private static Property getSkin(SuperiorPlayer superiorPlayer) { IProperty property; try { property = SkinsRestorerAPI.getApi().getSkinData(superiorPlayer.getName()); } catch (Throwable ex) { property = (IProperty) SKINS_RESTORER_GET_SKIN.invoke(SkinsRestorerAPI.getApi(), superiorPlayer.getName()); } if (property == null) return null; if (property instanceof Property) return ((Property) property); Object propertyHandle = property.getHandle(); return propertyHandle instanceof Property ? ((Property) propertyHandle) : null; } private static class SkinsListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSkinApply(SkinApplyBukkitEvent event) { if (event.getProperty() instanceof Property) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getWho()); plugin.getNMSPlayers().setSkinTexture(superiorPlayer, (Property) event.getProperty()); } } } } ================================================ FILE: Hooks/SkinsRestorer15/build.gradle ================================================ group 'Hooks:SkinsRestorer15' dependencies { compileOnly 'net.skinsrestorer:SkinsRestorer:15.0.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_skinsrestorer') && !Boolean.valueOf(project.findProperty("hook.compile_skinsrestorer").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/SkinsRestorer15/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer15Hook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.mojang.authlib.properties.Property; import net.skinsrestorer.api.SkinsRestorer; import net.skinsrestorer.api.SkinsRestorerProvider; import net.skinsrestorer.api.event.SkinApplyEvent; import net.skinsrestorer.api.exception.DataRequestException; import net.skinsrestorer.api.property.SkinProperty; import org.bukkit.entity.Player; import java.util.function.Consumer; public class SkinsRestorer15Hook { private static SuperiorSkyblockPlugin plugin; private static SkinsRestorer skinsRestorer; public static boolean isCompatible() { try { SkinsRestorer skinsRestorer = SkinsRestorerProvider.get(); return skinsRestorer != null; } catch (IllegalStateException error) { return false; } } public static void register(SuperiorSkyblockPlugin plugin) { SkinsRestorer15Hook.plugin = plugin; skinsRestorer = SkinsRestorerProvider.get(); plugin.getProviders().registerSkinsListener(SkinsRestorer15Hook::setSkinTexture); skinsRestorer.getEventBus().subscribe(plugin, SkinApplyEvent.class, new SkinsListener()); } private static void setSkinTexture(SuperiorPlayer superiorPlayer) { BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer)); } private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) { Property property = getSkin(superiorPlayer); if (property != null) BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property)); } private static Property getSkin(SuperiorPlayer superiorPlayer) { SkinProperty skinProperty; try { skinProperty = skinsRestorer.getPlayerStorage().getSkinForPlayer(superiorPlayer.getUniqueId(), superiorPlayer.getName()).orElse(null); } catch (DataRequestException error) { return null; } if (skinProperty == null) return null; return new Property("", skinProperty.getValue(), skinProperty.getSignature()); } private static class SkinsListener implements Consumer { @Override public void accept(SkinApplyEvent event) { Object playerObject = event.getPlayer(Object.class); if (!(playerObject instanceof Player)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) playerObject); Property property = new Property("", event.getProperty().getValue(), event.getProperty().getSignature()); plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property); } } } ================================================ FILE: Hooks/SlimeWorldManager/build.gradle ================================================ group 'Hooks:SlimeWorldManager' dependencies { compileOnly 'com.grinderwolf:SlimeWorldManager:2.2.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_slimeworldmanager') && !Boolean.valueOf(project.findProperty("hook.compile_slimeworldmanager").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/SlimeWorldManager/src/main/java/com/bgsoftware/superiorskyblock/external/SlimeWorldManagerHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.grinderwolf.swm.api.SlimePlugin; import com.grinderwolf.swm.plugin.config.ConfigManager; import com.grinderwolf.swm.plugin.config.WorldData; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; @SuppressWarnings("unused") public class SlimeWorldManagerHook { private static Plugin slimeWorldPlugin = null; public static void register(SuperiorSkyblockPlugin plugin) { slimeWorldPlugin = Bukkit.getPluginManager().getPlugin("SlimeWorldManager"); plugin.getProviders().registerWorldsListener(SlimeWorldManagerHook::loadWorld); } private static void loadWorld(String worldName) { SlimePlugin slimePlugin = (SlimePlugin) slimeWorldPlugin; WorldData worldData = ConfigManager.getWorldConfig().getWorlds().get(worldName); if (worldData == null) return; try { slimePlugin.getLoader(worldData.getDataSource()).loadWorld(worldName, false); } catch (Exception ignored) { } } } ================================================ FILE: Hooks/Slimefun/ProtectionModule_Dev999/build.gradle ================================================ group 'ProtectionModule_Dev999' dependencies { compileOnly 'me.mrcookieslime:Slimefun:4.Dev999' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_slimefun') && !Boolean.valueOf(project.findProperty("hook.compile_slimefun").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/Slimefun/ProtectionModule_Dev999/src/main/java/com/bgsoftware/superiorskyblock/external/slimefun/ProtectionModule_Dev999.java ================================================ package com.bgsoftware.superiorskyblock.external.slimefun; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.Interaction; import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.ProtectionManager; import io.github.thebusybiscuit.slimefun4.libraries.dough.protection.ProtectionModule; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.Server; import org.bukkit.plugin.Plugin; import java.util.function.Function; public class ProtectionModule_Dev999 { private static final ReflectMethod OLD_REGISTER_MODULE = new ReflectMethod<>(ProtectionManager.class, "registerModule", Server.class, String.class, Function.class); private ProtectionModule_Dev999() { } public static void register(Plugin plugin, PermissionCheck permissionCheck) { new ProtectionModuleImpl(plugin, permissionCheck).register(); } private static class ProtectionModuleImpl implements ProtectionModule { private final Plugin plugin; private final PermissionCheck permissionCheck; ProtectionModuleImpl(Plugin plugin, PermissionCheck permissionCheck) { this.plugin = plugin; this.permissionCheck = permissionCheck; } @Override public void load() { // Do nothing. } @Override public Plugin getPlugin() { return plugin; } @Override public boolean hasPermission(OfflinePlayer offlinePlayer, Location location, Interaction interaction) { return this.permissionCheck.checkPermission(offlinePlayer, location, interaction.name()); } void register() { BukkitExecutor.sync(() -> { if (OLD_REGISTER_MODULE.isValid()) { OLD_REGISTER_MODULE.invoke(Slimefun.getProtectionManager(), Bukkit.getServer(), plugin.getName(), (Function) pl -> this); } else { Slimefun.getProtectionManager().registerModule(Bukkit.getServer().getPluginManager(), plugin.getName(), pl -> this); } }, 2L); } } public interface PermissionCheck { boolean checkPermission(OfflinePlayer offlinePlayer, Location location, String permission); } } ================================================ FILE: Hooks/Slimefun/ProtectionModule_RC13/build.gradle ================================================ group 'ProtectionModule_RC13' dependencies { compileOnly 'me.mrcookieslime:Slimefun:4.RC13' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_slimefun') && !Boolean.valueOf(project.findProperty("hook.compile_slimefun").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/Slimefun/ProtectionModule_RC13/src/main/java/com/bgsoftware/superiorskyblock/external/slimefun/ProtectionModule_RC13.java ================================================ package com.bgsoftware.superiorskyblock.external.slimefun; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.cscorelib2.protection.ProtectableAction; import me.mrCookieSlime.Slimefun.cscorelib2.protection.ProtectionModule; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.plugin.Plugin; public class ProtectionModule_RC13 { private ProtectionModule_RC13() { } public static void register(Plugin plugin, PermissionCheck permissionCheck) { new ProtectionModuleImpl(plugin, permissionCheck).register(); } private static class ProtectionModuleImpl implements ProtectionModule { private final Plugin plugin; private final PermissionCheck permissionCheck; ProtectionModuleImpl(Plugin plugin, PermissionCheck permissionCheck) { this.plugin = plugin; this.permissionCheck = permissionCheck; } @Override public void load() { } @Override public Plugin getPlugin() { return plugin; } @Override public boolean hasPermission(OfflinePlayer offlinePlayer, Location location, ProtectableAction protectableAction) { return permissionCheck.checkPermission(offlinePlayer, location, protectableAction.name()); } void register() { SlimefunPlugin.getProtectionManager().registerModule(Bukkit.getServer(), plugin.getName(), pl -> this); } } public interface PermissionCheck { boolean checkPermission(OfflinePlayer offlinePlayer, Location location, String permission); } } ================================================ FILE: Hooks/Slimefun/build.gradle ================================================ group 'Hooks:Slimefun' dependencies { compileOnly 'me.mrcookieslime:Slimefun:4.Dev744' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":Hooks:Slimefun:ProtectionModule_RC13") compileOnly project(":Hooks:Slimefun:ProtectionModule_Dev999") compileOnly project(":") } if (project.hasProperty('hook.compile_slimefun') && !Boolean.valueOf(project.findProperty("hook.compile_slimefun").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandChunkResetEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.external.slimefun.ProtectionModule_Dev999; import com.bgsoftware.superiorskyblock.external.slimefun.ProtectionModule_RC13; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksServiceHelper; import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent; import io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.cscorelib2.protection.ProtectableAction; import me.mrCookieSlime.Slimefun.cscorelib2.protection.ProtectionModule; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.plugin.Plugin; public class SlimefunHook { @WorldRecordFlags private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; private static final ReflectMethod BLOCK_STORAGE_CLEAR_ALL_BLOCK_INFO_AT_CHUNK_METHOD = new ReflectMethod<>( BlockStorage.class, "clearAllBlockInfoAtChunk", World.class, int.class, int.class, boolean.class); private static final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; private static final LazyReference stackedBlocksInteractionService = new LazyReference() { @Override protected StackedBlocksInteractionService create() { return plugin.getServices().getService(StackedBlocksInteractionService.class); } }; private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { SlimefunHook.plugin = plugin; if (isClassLoaded("me.mrCookieSlime.Slimefun.SlimefunPlugin")) { ProtectionModule_RC13.register(plugin, SlimefunHook::checkPermission); } else if (isClassLoaded("io.github.thebusybiscuit.slimefun4.libraries.dough.protection.ProtectionModule")) { ProtectionModule_Dev999.register(plugin, SlimefunHook::checkPermission); } else if (isClassLoaded("io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin")) { // Dev 744 version, which is the one we use here. new ProtectionModuleImpl(plugin).register(); } plugin.getServer().getPluginManager().registerEvents(new AndroidMineListener(), plugin); if (isClassLoaded("io.github.thebusybiscuit.slimefun4.api.events.BlockPlacerPlaceEvent")) plugin.getServer().getPluginManager().registerEvents(new AutoPlacerPlaceListener(), plugin); if (BLOCK_STORAGE_CLEAR_ALL_BLOCK_INFO_AT_CHUNK_METHOD.isValid()) plugin.getServer().getPluginManager().registerEvents(new ChunkWipeListener(), plugin); } private static boolean isClassLoaded(String clazz) { try { Class.forName(clazz); return true; } catch (ClassNotFoundException error) { return false; } } private static boolean checkPermission(OfflinePlayer offlinePlayer, Location location, String protectableAction) { Island island = plugin.getGrid().getIslandAt(location); SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(offlinePlayer.getUniqueId()); if (!plugin.getGrid().isIslandsWorld(location.getWorld())) return true; if (protectableAction.equals("PVP") || protectableAction.equals("ATTACK_PLAYER")) return island != null && island.hasSettingsEnabled(IslandFlags.PVP); IslandPrivilege islandPrivilege; switch (protectableAction) { case "BREAK_BLOCK": islandPrivilege = IslandPrivileges.BREAK; break; case "PLACE_BLOCK": islandPrivilege = IslandPrivileges.BUILD; break; case "ACCESS_INVENTORIES": case "INTERACT_BLOCK": islandPrivilege = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(ConstantKeys.CHEST); break; default: islandPrivilege = IslandPrivileges.BREAK; break; } return island != null && islandPrivilege != null && island.hasPermission(superiorPlayer, islandPrivilege); } private static class AndroidMineListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onAndroidMiner(AndroidMineEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Log.debug(Debug.BLOCK_BREAK, e.getBlock().getLocation(wrapper.getHandle()), e.getBlock().getType()); } InteractionResult interactionResult = stackedBlocksInteractionService.get() .handleStackedBlockBreak(e.getBlock(), null); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) { e.setCancelled(true); } else { worldRecordService.get().recordBlockBreak(e.getBlock(), REGULAR_RECORD_FLAGS); } } } private static class AutoPlacerPlaceListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onAutoPlacerPlaceBlock(BlockPlacerPlaceEvent e) { worldRecordService.get().recordBlockPlace(e.getBlock(), 1, null, REGULAR_RECORD_FLAGS); } } private static class ChunkWipeListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onChunkWipe(IslandChunkResetEvent e) { BukkitExecutor.async(() -> { // Might be unsafe to call async. Should fix: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2474 BLOCK_STORAGE_CLEAR_ALL_BLOCK_INFO_AT_CHUNK_METHOD.invoke(null, e.getWorld(), e.getChunkX(), e.getChunkZ(), true); }); } } private static class ProtectionModuleImpl implements ProtectionModule { private final Plugin plugin; ProtectionModuleImpl(Plugin plugin) { this.plugin = plugin; } @Override public void load() { } @Override public Plugin getPlugin() { return plugin; } @Override public boolean hasPermission(OfflinePlayer offlinePlayer, Location location, ProtectableAction protectableAction) { return checkPermission(offlinePlayer, location, protectableAction.name()); } void register() { SlimefunPlugin.getProtectionManager().registerModule(Bukkit.getServer(), plugin.getName(), pl -> this); } } } ================================================ FILE: Hooks/SmoothTimber/build.gradle ================================================ group 'Hooks:SmoothTimber' java { toolchain { languageVersion.set(JavaLanguageVersion.of(11)) } } dependencies { compileOnly 'com.syntaxphoenix:SmoothTimber:1.27.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_smoothtimber') && !Boolean.valueOf(project.findProperty("hook.compile_smoothtimber").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/SmoothTimber/src/main/java/com/bgsoftware/superiorskyblock/external/SmoothTimberHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.syntaxphoenix.spigot.smoothtimber.event.AsyncPlayerChopTreeEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; public class SmoothTimberHook { private static SuperiorSkyblockPlugin plugin; private static final LazyReference protectionManager = new LazyReference<>() { @Override protected RegionManagerService create() { return plugin.getServices().getService(RegionManagerService.class); } }; public static void register(SuperiorSkyblockPlugin plugin) { SmoothTimberHook.plugin = plugin; plugin.getServer().getPluginManager().registerEvents(new ChopListener(), plugin); } private static class ChopListener implements Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onChopEvent(AsyncPlayerChopTreeEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); InteractionResult interactionResult = protectionManager.get().handleBlockBreak(superiorPlayer, e.getTreeLocation().getBlock()); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.getBlockLocations().clear(); return; } Island island = plugin.getGrid().getIslandAt(e.getTreeLocation()); if (island != null) e.getBlockLocations().removeIf(location -> !island.isInsideRange(location)); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onChopEventMonitor(AsyncPlayerChopTreeEvent e) { Island island = plugin.getGrid().getIslandAt(e.getTreeLocation()); if (island == null) return; e.getBlockLocations().forEach(location -> island.handleBlockBreak(Keys.of(location.getBlock()))); } } } ================================================ FILE: Hooks/SuperVanish/build.gradle ================================================ group 'Hooks:SuperVanish' dependencies { compileOnly 'de.myzelyam:SuperVanish:6.1.6' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_supervanish') && !Boolean.valueOf(project.findProperty("hook.compile_supervanish").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/SuperVanish/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_SuperVanish.java ================================================ package com.bgsoftware.superiorskyblock.external.vanish; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications; import de.myzelyam.api.vanish.PlayerVanishStateChangeEvent; import de.myzelyam.api.vanish.VanishAPI; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; public class VanishProvider_SuperVanish implements VanishProvider, Listener { private final SuperiorSkyblockPlugin plugin; public VanishProvider_SuperVanish(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(this, plugin); Log.info("Hooked into SuperVanish for support of vanish status of players."); } @Override public boolean isVanished(Player player) { return VanishAPI.isInvisible(player); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerVanish(PlayerVanishStateChangeEvent e) { if (e.isVanishing()) { IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(e.getUUID())); } else { IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(e.getUUID())); } } } ================================================ FILE: Hooks/TimbruSilkSpawners/build.gradle ================================================ group 'Hooks:TimbruSilkSpawners' dependencies { compileOnly 'de.dustplanet:SilkSpawners:6.0.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_timbrusilkspawners') && !Boolean.valueOf(project.findProperty("hook.compile_timbrusilkspawners").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/TimbruSilkSpawnersHook.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.Keys; import de.dustplanet.silkspawners.events.SilkSpawnersSpawnerChangeEvent; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import java.util.Locale; public class TimbruSilkSpawnersHook { public static void register(SuperiorSkyblockPlugin plugin) { Bukkit.getPluginManager().registerEvents(new SpawnersListener(plugin), plugin); } private TimbruSilkSpawnersHook() { } private static class SpawnersListener implements Listener { private final SuperiorSkyblockPlugin plugin; SpawnersListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerChange(SilkSpawnersSpawnerChangeEvent e) { EntityType oldEntity = EnumHelper.getEnum(EntityType.class, e.getOldEntityID().toUpperCase(Locale.ENGLISH)); EntityType newEntity = EnumHelper.getEnum(EntityType.class, e.getEntityID().toUpperCase(Locale.ENGLISH)); if (oldEntity == null || newEntity == null || oldEntity == newEntity) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); } if (island == null) return; island.handleBlockBreak(Keys.ofSpawner(oldEntity), 1); island.handleBlockPlace(Keys.ofSpawner(newEntity), 1); } } } ================================================ FILE: Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_TimbruSilkSpawners.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import de.dustplanet.util.SilkUtil; import org.bukkit.Location; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.util.Locale; public class SpawnersProvider_TimbruSilkSpawners implements SpawnersProvider_AutoDetect { private final SilkUtil silkUtil; public SpawnersProvider_TimbruSilkSpawners() { this.silkUtil = SilkUtil.hookIntoSilkSpanwers(); Log.info("Using SilkSpawners as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); return new Pair<>(1, null); } @Override public String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); String entityId = this.silkUtil.getStoredSpawnerItemEntityID(itemStack); if (entityId != null) { EntityType entityType = EnumHelper.getEnum(EntityType.class, entityId.toUpperCase(Locale.ENGLISH)); if (entityType != null) return entityType.name(); } return "PIG"; } } ================================================ FILE: Hooks/UltimateStacker/build.gradle ================================================ group 'Hooks:UltimateStacker' dependencies { compileOnly 'com.songoda:UltimateStacker:2.1.7' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_ultimatestacker') && !Boolean.valueOf(project.findProperty("hook.compile_ultimatestacker").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.google.common.base.Preconditions; import com.songoda.ultimatestacker.UltimateStacker; import com.songoda.ultimatestacker.events.SpawnerBreakEvent; import com.songoda.ultimatestacker.events.SpawnerPlaceEvent; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; public class SpawnersProvider_UltimateStacker implements SpawnersProviderItemMetaSpawnerType { private final UltimateStacker instance = UltimateStacker.getInstance(); private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_UltimateStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using UltimateStacker as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; if (Bukkit.isPrimaryThread()) { blockCount = instance.getSpawnerStackManager().getSpawner(location).getAmount(); } return new Pair<>(blockCount, null); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onSpawnerStack(SpawnerPlaceEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawnerType()); int increaseAmount = e.getAmount(); if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } if (island != null) island.handleBlockBreak(e.getBlock(), e.getAmount()); } } } ================================================ FILE: Hooks/UltimateStacker3/build.gradle ================================================ group 'Hooks:UltimateStacker3' dependencies { compileOnly 'com.craftaro:UltimateStacker:3.0.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_ultimatestacker') && !Boolean.valueOf(project.findProperty("hook.compile_ultimatestacker").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.craftaro.ultimatestacker.api.UltimateStackerApi; import com.craftaro.ultimatestacker.api.events.spawner.SpawnerBreakEvent; import com.craftaro.ultimatestacker.api.events.spawner.SpawnerPlaceEvent; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; public class SpawnersProvider_UltimateStacker3 implements SpawnersProviderItemMetaSpawnerType { private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_UltimateStacker3(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using UltimateStacker as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; if (Bukkit.isPrimaryThread()) { blockCount = UltimateStackerApi.getSpawnerStackManager().getSpawner(location).getAmount(); } return new Pair<>(blockCount, null); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onSpawnerStack(SpawnerPlaceEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawnerType()); int increaseAmount = e.getAmount(); if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } if (island != null) island.handleBlockBreak(e.getBlock(), e.getAmount()); } } } ================================================ FILE: Hooks/UltimateStacker4/build.gradle ================================================ group 'Hooks:UltimateStacker4' dependencies { compileOnly 'com.songoda:UltimateStacker:4.3.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_ultimatestacker') && !Boolean.valueOf(project.findProperty("hook.compile_ultimatestacker").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.google.common.base.Preconditions; import com.songoda.ultimatestacker.api.UltimateStackerApi; import com.songoda.ultimatestacker.api.events.spawner.SpawnerBreakEvent; import com.songoda.ultimatestacker.api.events.spawner.SpawnerPlaceEvent; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; public class SpawnersProvider_UltimateStacker4 implements SpawnersProviderItemMetaSpawnerType { private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_UltimateStacker4(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Log.info("Using UltimateStacker as a spawners provider."); } @Override public Pair getSpawner(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); int blockCount = -1; if (Bukkit.isPrimaryThread()) { blockCount = UltimateStackerApi.getSpawnerStackManager().getSpawner(location).getAmount(); } return new Pair<>(blockCount, null); } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onSpawnerStack(SpawnerPlaceEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } if (island == null) return; Key blockKey = Key.ofSpawner(e.getSpawnerType()); int increaseAmount = e.getAmount(); if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } if (island != null) island.handleBlockBreak(e.getBlock(), e.getAmount()); } } } ================================================ FILE: Hooks/VanishNoPacket/build.gradle ================================================ group 'Hooks:VanishNoPacket' dependencies { compileOnly 'org.kitteh:VanishNoPacket:3.20.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_vanishnopacket') && !Boolean.valueOf(project.findProperty("hook.compile_vanishnopacket").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/VanishNoPacket/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_VanishNoPacket.java ================================================ package com.bgsoftware.superiorskyblock.external.vanish; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import org.kitteh.vanish.VanishPlugin; import org.kitteh.vanish.event.VanishStatusChangeEvent; public class VanishProvider_VanishNoPacket implements VanishProvider, Listener { private final SuperiorSkyblockPlugin plugin; private final VanishPlugin instance; public VanishProvider_VanishNoPacket(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; this.instance = JavaPlugin.getPlugin(VanishPlugin.class); Bukkit.getPluginManager().registerEvents(this, plugin); Log.info("Hooked into VanishNoPacket for support of vanish status of players."); } @Override public boolean isVanished(Player player) { return instance.getManager().isVanished(player); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerVanish(VanishStatusChangeEvent e) { if (e.isVanishing()) { IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(e.getPlayer())); } else { IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(e.getPlayer())); } } } ================================================ FILE: Hooks/Vault/build.gradle ================================================ group 'Hooks:Vault' dependencies { compileOnly 'net.milkbowl:Vault:1.6.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_vault') && !Boolean.valueOf(project.findProperty("hook.compile_vault").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/Vault/src/main/java/com/bgsoftware/superiorskyblock/external/economy/EconomyProvider_Vault.java ================================================ package com.bgsoftware.superiorskyblock.external.economy; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Precision; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.EconomyResponse; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.plugin.RegisteredServiceProvider; import java.math.BigDecimal; import java.math.RoundingMode; public class EconomyProvider_Vault implements EconomyProvider { private static Economy econ; public static boolean isCompatible() { RegisteredServiceProvider rsp = Bukkit.getServicesManager().getRegistration(Economy.class); if (rsp != null) econ = rsp.getProvider(); if (econ != null) Log.info("Using Vault as an economy provider."); return econ != null; } @Override public BigDecimal getBalance(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return BigDecimal.valueOf(getMoneyInBank(superiorPlayer.asOfflinePlayer())) .setScale(3, RoundingMode.HALF_DOWN); } @Override public EconomyResult depositMoney(SuperiorPlayer superiorPlayer, double amount) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer(); double moneyBeforeDeposit = getMoneyInBank(offlinePlayer); EconomyResponse economyResponse = econ.depositPlayer(offlinePlayer, amount); double moneyInTransaction = Precision.round(getMoneyInBank(offlinePlayer) - moneyBeforeDeposit, 3); String errorMessage = moneyInTransaction == amount ? getErrorMessageFromResponse(economyResponse) : moneyInTransaction == 0 ? "You have exceed the limit of your bank" : ""; return new EconomyResult(errorMessage, moneyInTransaction); } @Override public EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, double amount) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer(); double moneyBeforeWithdraw = getMoneyInBank(offlinePlayer); EconomyResponse economyResponse = econ.withdrawPlayer(offlinePlayer, amount); double moneyInTransaction = Precision.round(moneyBeforeWithdraw - getMoneyInBank(offlinePlayer), 3); String errorMessage = moneyInTransaction == amount ? getErrorMessageFromResponse(economyResponse) : moneyInTransaction == 0 ? "Couldn't process the transaction" : ""; return new EconomyResult(errorMessage, moneyInTransaction); } private double getMoneyInBank(OfflinePlayer offlinePlayer) { if (!econ.hasAccount(offlinePlayer)) econ.createPlayerAccount(offlinePlayer); return Precision.round(econ.getBalance(offlinePlayer), 3); } @Nullable private static String getErrorMessageFromResponse(EconomyResponse economyResponse) { return economyResponse.transactionSuccess() ? null : economyResponse.errorMessage; } } ================================================ FILE: Hooks/WildStacker/build.gradle ================================================ group 'Hooks:WildStacker' dependencies { compileOnly 'com.bgsoftware:WildStackerAPI:3.6.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('hook.compile_wildstacker') && !Boolean.valueOf(project.findProperty("hook.compile_wildstacker").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.wildstacker.api.WildStackerAPI; import com.bgsoftware.wildstacker.api.objects.StackedSnapshot; import org.bukkit.Chunk; import java.util.function.Function; public class WildStackerSnapshotsContainer { private static final Synchronized>> cachedSnapshots = Synchronized.of(new Chunk2ObjectMap<>()); private WildStackerSnapshotsContainer() { } public static void takeSnapshot(Chunk chunk) { try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { cachedSnapshots.write(cachedSnapshots -> takeSnapshotInternal(chunk, chunkPosition, cachedSnapshots)); } } private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPosition, Chunk2ObjectMap> cachedSnapshots) { RefCount refCountBase = cachedSnapshots.get(chunkPosition); if (refCountBase != null) { refCountBase.incRef(); return; } refCountBase = new RefCount<>(); try { StackedSnapshot stackedSnapshot; try { stackedSnapshot = WildStackerAPI.getWildStacker().getSystemManager().getStackedSnapshot(chunk); } catch (Throwable ex) { //noinspection deprecation stackedSnapshot = WildStackerAPI.getWildStacker().getSystemManager().getStackedSnapshot(chunk, false); } if (stackedSnapshot != null) { refCountBase.set(stackedSnapshot); cachedSnapshots.put(chunkPosition, refCountBase); } } catch (Throwable error) { Log.error(error, "Received an unexpected error while taking a snapshot for WildStacker:"); } } public static void releaseSnapshot(ChunkPosition chunkPosition) { cachedSnapshots.write(m -> { RefCount refCountBase = m.get(chunkPosition); if (refCountBase != null) { if (refCountBase.defRef()) m.remove(chunkPosition); } }); } public static R accessStackedSnapshot(ChunkPosition chunkPosition, Function function) { return cachedSnapshots.readAndGet(cachedSnapshots -> { RefCount refCountBase = cachedSnapshots.get(chunkPosition); if (refCountBase == null) return null; return refCountBase.readAndGet(function); }); } private static class RefCount { private int refCount; private Synchronized handle; synchronized void incRef() { if (this.handle == null) throw new IllegalStateException("Inc ref on null RefCount object " + this); int ref = this.handle.writeAndGet(unused -> { return ++this.refCount; }); if (ref <= 0) throw new IllegalStateException("Inc ref on null RefCount object " + this); } synchronized boolean defRef() { if (this.handle == null) throw new IllegalStateException("Dec ref on null RefCount object " + this); int ref = this.handle.writeAndGet(unused -> { return --this.refCount; }); if (ref == 0) { this.handle = null; return true; } else if (ref < 0) { throw new IllegalStateException("Dec ref on null RefCount object " + this); } return false; } synchronized R readAndGet(Function function) { if (this.handle == null) throw new IllegalStateException("Access null RefCount object " + this); return this.handle.writeAndGet(handle -> { if (this.refCount <= 0) throw new IllegalStateException("Access null RefCount object " + this); return function.apply(handle); }); } synchronized void set(T handle) { this.handle = Synchronized.of(handle); incRef(); } @Override public synchronized String toString() { if (this.handle == null) { return "{ ref = " + this.refCount + ", handle = " + this.handle + "}"; } else { return this.handle.readAndGet(handle -> { return "{ ref = " + this.refCount + ", handle = " + handle + "}"; }); } } } } ================================================ FILE: Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersSnapshotProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.external.WildStackerSnapshotsContainer; import com.bgsoftware.superiorskyblock.module.upgrades.listeners.WildStackerListener; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.wildstacker.api.WildStackerAPI; import com.bgsoftware.wildstacker.api.events.SpawnerPlaceEvent; import com.bgsoftware.wildstacker.api.events.SpawnerPlaceInventoryEvent; import com.bgsoftware.wildstacker.api.events.SpawnerStackEvent; import com.bgsoftware.wildstacker.api.events.SpawnerUnstackEvent; import com.bgsoftware.wildstacker.api.objects.StackedSpawner; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import java.util.Map; public class SpawnersProvider_WildStacker implements SpawnersProviderItemMetaSpawnerType, SpawnersSnapshotProvider { private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @Override protected RegionManagerService create() { return plugin.getServices().getService(RegionManagerService.class); } }; public SpawnersProvider_WildStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); Bukkit.getPluginManager().registerEvents(new WildStackerListener(), plugin); Log.info("Using WildStacker as a spawners provider."); } @Override public Pair getSpawner(Location location) { Map.Entry entry; try (ChunkPosition chunkPosition = ChunkPosition.of(location)) { entry = WildStackerSnapshotsContainer.accessStackedSnapshot(chunkPosition, stackedSnapshot -> stackedSnapshot.getStackedSpawner(location)); } if (entry == null) { StackedSpawner stackedSpawner = WildStackerAPI.getWildStacker().getSystemManager().getStackedSpawner(location); if (stackedSpawner == null) { return new Pair<>(1, null); } else { return new Pair<>(stackedSpawner.getStackAmount(), stackedSpawner.getSpawnedType().name()); } } return new Pair<>(entry.getKey(), entry.getValue() + ""); } @Override public void takeSnapshot(Chunk chunk) { WildStackerSnapshotsContainer.takeSnapshot(chunk); } @Override public void releaseSnapshot(World world, int chunkX, int chunkZ) { try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { WildStackerSnapshotsContainer.releaseSnapshot(chunkPosition); } } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerPlace(SpawnerPlaceEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Keys.ofSpawner(e.getSpawner().getSpawnedType()); int increaseAmount = e.getSpawner().getStackAmount(); if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else if (increaseAmount > 1) { island.handleBlockPlace(blockKey, increaseAmount - 1); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerStack(SpawnerStackEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Keys.ofSpawner(e.getSpawner().getSpawnedType()); int increaseAmount = e.getTarget().getStackAmount(); if (increaseAmount < 0) { island.handleBlockBreak(blockKey, -increaseAmount); } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerUnstackEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island != null) island.handleBlockBreak(Keys.ofSpawner(e.getSpawner().getSpawnedType()), e.getAmount()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerPlaceInventoryMonitor(SpawnerPlaceInventoryEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; Key blockKey = Keys.ofSpawner(e.getSpawner().getSpawnedType()); int increaseAmount = e.getIncreaseAmount(); if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } /* Protection Listener */ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onSpawnerPlaceInventoryNormal(SpawnerPlaceInventoryEvent e) { Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); if (island == null) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); InteractionResult interactionResult = protectionManager.get().handleBlockPlace(superiorPlayer, e.getSpawner().getLocation().getBlock()); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } } } ================================================ FILE: Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java ================================================ package com.bgsoftware.superiorskyblock.external.stackedblocks; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksSnapshotProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.external.WildStackerSnapshotsContainer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.wildstacker.api.WildStackerAPI; import com.bgsoftware.wildstacker.api.events.BarrelPlaceEvent; import com.bgsoftware.wildstacker.api.events.BarrelPlaceInventoryEvent; import com.bgsoftware.wildstacker.api.events.BarrelStackEvent; import com.bgsoftware.wildstacker.api.events.BarrelUnstackEvent; import com.bgsoftware.wildstacker.api.handlers.SystemManager; import com.bgsoftware.wildstacker.api.objects.StackedBarrel; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import java.util.Collection; import java.util.stream.Collectors; public class StackedBlocksProvider_WildStacker implements StackedBlocksProvider_AutoDetect, StackedBlocksSnapshotProvider { private static boolean registered = false; private final SuperiorSkyblockPlugin plugin; public StackedBlocksProvider_WildStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); if (!registered) { registered = true; SuperiorSkyblockAPI.getBlockValues().registerKeyParser(new CustomKeyParser() { private final SystemManager systemManager = WildStackerAPI.getWildStacker().getSystemManager(); @Override public Key getCustomKey(Location location) { return systemManager.isStackedBarrel(location) ? getBarrelKey(systemManager.getStackedBarrel(location)) : ConstantKeys.CAULDRON; } @Override public boolean isCustomKey(Key key) { return false; } }, ConstantKeys.CAULDRON); } Log.info("Using WildStacker as a stacked-blocks provider."); } @Override public Collection> getBlocks(World world, int chunkX, int chunkZ) { try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { return WildStackerSnapshotsContainer.accessStackedSnapshot(chunkPosition, stackedSnapshot -> { try { return stackedSnapshot.getAllBarrelsItems().values().stream() .filter(entry -> entry.getValue() != null) .map(entry -> new Pair<>(Key.of(entry.getValue()), entry.getKey())) .collect(Collectors.toSet()); } catch (Throwable ex) { return stackedSnapshot.getAllBarrels().values().stream() .map(entry -> new Pair<>(Key.of(entry.getValue(), (short) 0), entry.getKey())) .collect(Collectors.toSet()); } }); } } @Override public void takeSnapshot(Chunk chunk) { WildStackerSnapshotsContainer.takeSnapshot(chunk); } @Override public void releaseSnapshot(World world, int chunkX, int chunkZ) { try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { WildStackerSnapshotsContainer.releaseSnapshot(chunkPosition); } } @SuppressWarnings("unused") private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBarrelPlace(BarrelPlaceEvent e) { Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation()); if (island == null) return; Key blockKey = getBarrelKey(e.getBarrel()); int increaseAmount = e.getBarrel().getStackAmount(); if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBarrelStack(BarrelStackEvent e) { Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation()); if (island == null) return; Key blockKey = getBarrelKey(e.getTarget()); int increaseAmount = e.getTarget().getStackAmount(); if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBarrelUnstackOnOtherIsland(BarrelUnstackEvent e) { Entity unstackSource = e.getUnstackSource(); if (!(unstackSource instanceof Player)) return; Player player = (Player) unstackSource; Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation()); if (island == null) return; Key blockKey = getBarrelKey(e.getBarrel()); IslandPrivilege islandPrivilege = plugin.getSettings().getValuableBlocks().contains(blockKey) ? IslandPrivileges.VALUABLE_BREAK : IslandPrivileges.BREAK; if (!island.hasPermission(player, islandPrivilege)) { e.setCancelled(true); ProtectionHelper.sendProtectionMessage(player); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBarrelUnstack(BarrelUnstackEvent e) { Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation()); if (island != null) island.handleBlockBreak(getBarrelKey(e.getBarrel()), e.getAmount()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBarrelPlace(BarrelPlaceInventoryEvent e) { Island island = plugin.getGrid().getIslandAt(e.getBarrel().getLocation()); if (island == null) return; Key blockKey = getBarrelKey(e.getBarrel()); int increaseAmount = e.getIncreaseAmount(); if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } else { island.handleBlockPlace(blockKey, increaseAmount); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBarrelInteract(PlayerInteractEvent e) { Block block = e.getClickedBlock(); if (block == null) return; StackedBarrel stackedBarrel; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = block.getLocation(wrapper.getHandle()); if(!WildStackerAPI.getWildStacker().getSystemManager().isStackedBarrel(location)) return; stackedBarrel = WildStackerAPI.getWildStacker().getSystemManager().getStackedBarrel(location); island = plugin.getGrid().getIslandAt(location); } if (island == null) return; Player player = e.getPlayer(); Key blockKey = getBarrelKey(stackedBarrel); IslandPrivilege privilege = player.isSneaking() ? IslandPrivileges.BUILD : plugin.getSettings().getValuableBlocks().contains(blockKey) ? IslandPrivileges.VALUABLE_BREAK : IslandPrivileges.BREAK; if (!island.hasPermission(player, privilege)) { e.setCancelled(true); ProtectionHelper.sendProtectionMessage(player); } } } private static Key getBarrelKey(StackedBarrel barrel) { ItemStack barrelItem = barrel.getBarrelItem(1); return ServerVersion.isLegacy() ? Key.of(barrelItem) : Key.of(barrelItem.getType()); } } ================================================ FILE: Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/listeners/WildStackerListener.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.listeners; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeSpawnerRates; import com.bgsoftware.wildstacker.api.events.SpawnerPlaceEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; public class WildStackerListener implements Listener { @Nullable private final UpgradeTypeSpawnerRates spawnerRates = BuiltinModules.UPGRADES .getEnabledUpgradeType(UpgradeTypeSpawnerRates.class); @EventHandler public void onWildStackerStackSpawn(SpawnerPlaceEvent e) { if (spawnerRates != null) spawnerRates.handleSpawnerPlace(e.getSpawner().getLocation().getBlock()); } } ================================================ FILE: Hooks/build.gradle ================================================ group 'Hooks' ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: Missions/BlocksMissions/build.gradle ================================================ group 'Missions:BlocksMissions' dependencies { compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly "com.bgsoftware:WildStackerAPI:3.6.3" compileOnly "com.bgsoftware:WildToolsAPI:2.11.4" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.blocks' } ================================================ FILE: Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BlocksMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.missions.blocks.BlocksTracker; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.Placeholders; import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; import com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker; import com.bgsoftware.wildstacker.api.WildStackerAPI; import com.bgsoftware.wildstacker.api.events.BarrelUnstackEvent; import com.bgsoftware.wildtools.api.events.CuboidWandUseEvent; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.function.Predicate; import java.util.stream.Collectors; public class BlocksMissions extends BuiltinMission implements Listener { private final Map requiredBlocks = new LinkedHashMap<>(); private boolean onlyNatural; private ProgressAction progressAction; private Predicate isBarrelCheck = block -> false; @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { if (!section.contains("required-blocks")) throw new MissionLoadException("You must have the \"required-blocks\" section in the config."); for (String key : section.getConfigurationSection("required-blocks").getKeys(false)) { KeySet blocks = KeySet.createKeySet(); section.getStringList("required-blocks." + key + ".types").forEach(requiredBlock -> blocks.add(Key.ofMaterialAndData(requiredBlock.toUpperCase(Locale.ENGLISH)))); int requiredAmount = section.getInt("required-blocks." + key + ".amount"); this.requiredBlocks.put(new KeyRequirements(blocks), requiredAmount); } this.onlyNatural = section.getBoolean("only-natural-blocks", false); this.progressAction = section.getBoolean("blocks-placement", false) ? ProgressAction.PLACE : ProgressAction.BREAK; } @Override protected void registerListeners() { registerListener(this); Bukkit.getScheduler().runTaskLater(plugin, () -> { if (Bukkit.getPluginManager().isPluginEnabled("WildStacker")) { registerListener(new WildStackerListener()); this.isBarrelCheck = block -> WildStackerAPI.getWildStacker().getSystemManager().isStackedBarrel(block); } if (Bukkit.getPluginManager().isPluginEnabled("WildTools")) { registerListener(new WildToolsListener()); } }, 1L); } @Override protected void clearModuleData(KeyDataTracker data) { data.clear(); } @Override public double getProgress(SuperiorPlayer superiorPlayer) { KeyDataTracker blocksCounter = get(superiorPlayer); if (blocksCounter == null) return 0.0; int requiredBlocks = 0; int interactions = 0; for (Map.Entry requiredBlock : this.requiredBlocks.entrySet()) { requiredBlocks += requiredBlock.getValue(); interactions += Math.min(blocksCounter.getCounts(requiredBlock.getKey()), requiredBlock.getValue()); } return (double) interactions / requiredBlocks; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { KeyDataTracker blocksCounter = get(superiorPlayer); if (blocksCounter == null) return 0; int interactions = 0; for (Map.Entry requiredBlock : this.requiredBlocks.entrySet()) interactions += Math.min(blocksCounter.getCounts(requiredBlock.getKey()), requiredBlock.getValue()); return interactions; } @Override public void saveProgress(ConfigurationSection section) { for (Map.Entry entry : entrySet()) { String uuid = entry.getKey().getUniqueId().toString(); for (Map.Entry blockCountEntry : entry.getValue().getCounts().entrySet()) { section.set(uuid + ".counts." + blockCountEntry.getKey(), blockCountEntry.getValue().get()); } } BlocksTracker.INSTANCE.save(section); } @Override public void loadProgress(ConfigurationSection section) { for (String uuid : section.getKeys(false)) { KeyDataTracker blocksCounter = new KeyDataTracker(); UUID playerUUID; try { playerUUID = UUID.fromString(uuid); } catch (Exception error) { // tracked section probably, skipping. continue; } SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); insertData(superiorPlayer, blocksCounter); if (section.contains(uuid + ".counts")) { ConfigurationSection countsSection = section.getConfigurationSection(uuid + ".counts"); if (countsSection != null) { for (String key : countsSection.getKeys(false)) { Key typeKey = getMissionBlockKey(Key.ofMaterialAndData(key)); blocksCounter.load(typeKey, countsSection.getInt(key)); } } } else { ConfigurationSection countsSection = section.getConfigurationSection(uuid); if (countsSection != null) { for (String key : countsSection.getKeys(false)) { Key typeKey = getMissionBlockKey(Key.ofMaterialAndData(key)); blocksCounter.load(typeKey, section.getInt(uuid + "." + key)); } } } loadTrackedBlocks(section.getConfigurationSection(uuid + ".tracked.placed"), section.getConfigurationSection(uuid + ".tracked.broken")); } loadTrackedBlocks(section.getConfigurationSection("tracked.placed"), section.getConfigurationSection("tracked.broken")); } private static void loadTrackedBlocks(@Nullable ConfigurationSection trackedPlacedSection, @Nullable ConfigurationSection trackedBrokenSection) { if (trackedPlacedSection != null) { for (String worldName : trackedPlacedSection.getKeys(false)) { ConfigurationSection worldSection = trackedPlacedSection.getConfigurationSection(worldName); BlocksTracker.INSTANCE.loadTrackedBlocks(BlocksTracker.TrackingType.PLACED_BLOCKS, worldName, worldSection); } } if (trackedBrokenSection != null) { for (String worldName : trackedBrokenSection.getKeys(false)) { ConfigurationSection worldSection = trackedBrokenSection.getConfigurationSection(worldName); BlocksTracker.INSTANCE.loadTrackedBlocks(BlocksTracker.TrackingType.BROKEN_BLOCKS, worldName, worldSection); } } } @Override public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { KeyDataTracker blocksCounter = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); if (blocksCounter == null) return; ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta == null) return; if (itemMeta.hasDisplayName()) itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredBlocks, blocksCounter, itemMeta.getDisplayName(), true)); if (itemMeta.hasLore()) { List lore = new ArrayList<>(); for (String line : Objects.requireNonNull(itemMeta.getLore())) lore.add(Placeholders.parseKeyPlaceholders(this.requiredBlocks, blocksCounter, line, true)); itemMeta.setLore(lore); } itemStack.setItemMeta(itemMeta); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPlace(BlockPlaceEvent e) { SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) return; Key blockKey = getMissionBlockKey(Key.of(e.getBlock())); if (blockKey == null) return; if (this.progressAction == ProgressAction.PLACE) { // We want to handle block place only if players gain progress by placing blocks. handleBlockAction(e.getPlayer(), e.getBlock().getLocation(), blockKey, superiorPlayer, false); } if (this.onlyNatural) { // We want to track block broken & placed only if this mission only progresses for natural blocks // We do that in a delayed tick so all other missions will check for their progress as well. Bukkit.getScheduler().runTaskLater(this.plugin, () -> { BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, e.getBlock()); BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, e.getBlock()); }, 1L); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent e) { SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) return; Key blockKey = getMissionBlockKey(Key.of(e.getBlock())); if (blockKey == null) return; if (this.progressAction == ProgressAction.BREAK) { // We want to handle block break only if players gain progress by breaking blocks. handleBlockAction(e.getPlayer(), e.getBlock().getLocation(), blockKey, superiorPlayer, true); } if (this.onlyNatural) { // We want to track block broken & placed only if this mission only progresses for natural blocks // We do that in a delayed tick so all other missions will check for their progress as well. Bukkit.getScheduler().runTaskLater(this.plugin, () -> { BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, e.getBlock()); BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, e.getBlock()); }, 1L); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPistonRetract(BlockPistonRetractEvent e) { if (!e.getBlocks().isEmpty()) handleBlockPistonMove(new LinkedList<>(e.getBlocks()), e.getDirection()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPistonExtend(BlockPistonExtendEvent e) { if (!e.getBlocks().isEmpty()) handleBlockPistonMove(new LinkedList<>(e.getBlocks()), e.getDirection()); } private class WildStackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBarrelUnstack(BarrelUnstackEvent e) { if (onlyNatural || progressAction != ProgressAction.BREAK || !(e.getUnstackSource() instanceof Player)) return; Player player = (Player) e.getUnstackSource(); SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (!BlocksMissions.this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, BlocksMissions.this)) return; Key blockKey = getMissionBlockKey(Key.of(e.getBarrel().getType(), e.getBarrel().getData())); if (blockKey == null) return; handleBlockAction(player, e.getBarrel().getLocation(), blockKey, superiorPlayer, false); } } private class WildToolsListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onCuboidUse(CuboidWandUseEvent e) { if (progressAction != ProgressAction.BREAK) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); if (!BlocksMissions.this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, BlocksMissions.this)) return; for (Location location : e.getBlocks()) { Block block = location.getBlock(); Key blockKey = getMissionBlockKey(Key.of(block)); if (blockKey == null) return; handleBlockAction(e.getPlayer(), location, blockKey, superiorPlayer, true); if (onlyNatural) { // We want to track block broken & placed only if this mission only progresses for natural blocks // We do that in a delayed tick so all other missions will check for their progress as well. Bukkit.getScheduler().runTaskLater(plugin, () -> { BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block); BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, block); }, 1L); } } } } private void handleBlockPistonMove(LinkedList blockList, BlockFace direction) { blockList.removeIf(block -> getMissionBlockKey(Key.of(block)) == null || !BlocksTracker.INSTANCE.isTracked(BlocksTracker.TrackingType.PLACED_BLOCKS, block)); if (blockList.isEmpty()) return; List movedBlocks = blockList.stream() .map(block -> block.getRelative(direction)) .collect(Collectors.toList()); List addedBlocks = new LinkedList<>(movedBlocks); addedBlocks.removeAll(blockList); List removedBlocks = new LinkedList<>(blockList); removedBlocks.removeAll(movedBlocks); removedBlocks.forEach(block -> BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block)); addedBlocks.forEach(block -> BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block)); } /** * Handle placing or breaking of a block and add count to mission progress. * * @param player The player. * @param blockLocation The location of the block. * @param blockKey The {@link Key} of the block in @param blockLocation. * @param superiorPlayer The {@link SuperiorPlayer} wrapper of @param player. */ private void handleBlockAction(Player player, Location blockLocation, Key blockKey, @Nullable SuperiorPlayer superiorPlayer, boolean checkForBarrels) { int blockAmount = getBlockAmount(player, blockLocation); if (superiorPlayer == null) superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (checkForBarrels && this.isBarrelCheck.test(blockLocation)) return; // In case we progress for breaking blocks, we want to ensure the block is not tracked in case // the mission only progresses for natural blocks. if (this.onlyNatural && this.progressAction == ProgressAction.BREAK && BlocksTracker.INSTANCE.isTracked(BlocksTracker.TrackingType.PLACED_BLOCKS, blockLocation)) { return; } handleBlockTrack(superiorPlayer, blockKey, blockAmount); } private void handleBlockTrack(SuperiorPlayer superiorPlayer, Key blockKey, int amount) { KeyDataTracker blocksCounter = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); blocksCounter.track(blockKey, amount); Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(_player -> { if (canComplete(superiorPlayer)) this.plugin.getMissions().rewardMission(this, superiorPlayer, true); }), 2L); } private int getBlockAmount(Player player, Location blockLocation) { int blockAmount = this.plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); // When sneaking, you'll break 64 from the stack. Otherwise, 1. int amount = !player.isSneaking() ? 1 : 64; // Fix amount so it won't be more than the stack's amount amount = Math.min(amount, blockAmount); return amount; } @Nullable private Key getMissionBlockKey(Key blockKey) { for (KeyRequirements requirementsList : requiredBlocks.keySet()) { if (requirementsList.contains(blockKey)) return requirementsList.getKey(blockKey); } return null; } private enum ProgressAction { BREAK, PLACE } } ================================================ FILE: Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTracker.java ================================================ package com.bgsoftware.superiorskyblock.missions.blocks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; import java.util.EnumMap; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.function.Function; public class BlocksTracker { public static final BlocksTracker INSTANCE = new BlocksTracker(); private final EnumMap> trackingComponentMap = new EnumMap<>(TrackingType.class); private EnumMap> rawData = null; private boolean saved = false; private BlocksTracker() { } public void trackBlock(TrackingType trackingType, Block block) { getComponent(trackingType, block.getWorld()).add(block.getX(), block.getY(), block.getZ()); } public boolean untrackBlock(TrackingType trackingType, Block block) { return ifComponentExists(trackingType, block.getWorld(), false, component -> component.remove(block.getX(), block.getY(), block.getZ())); } public boolean isTracked(TrackingType trackingType, Block block) { return ifComponentExists(trackingType, block.getWorld(), false, component -> component.contains(block.getX(), block.getY(), block.getZ())); } public boolean isTracked(TrackingType trackingType, Location blockLocation) { return ifComponentExists(trackingType, blockLocation.getWorld(), false, component -> component.contains(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ())); } public void loadTrackedBlocks(TrackingType trackingType, String worldName, ConfigurationSection section) { if (this.rawData == null) this.rawData = new EnumMap<>(TrackingType.class); this.rawData.computeIfAbsent(trackingType, t -> new HashMap<>()).put(worldName, new TrackedBlocksData(section)); } public void save(ConfigurationSection section) { if (!this.saved) { saveInternal(section, TrackingType.PLACED_BLOCKS); saveInternal(section, TrackingType.BROKEN_BLOCKS); this.saved = true; } } private void saveInternal(ConfigurationSection section, TrackingType trackingType) { Map trackingComponentMap = this.trackingComponentMap.get(trackingType); if (trackingComponentMap == null) return; trackingComponentMap.forEach((worldName, component) -> { component.getBlocks().forEach((chunkKey, blocksBitSet) -> { List blocks = new LinkedList<>(); blocksBitSet.forEach(blocks::add); if (!blocks.isEmpty()) section.set("tracked." + trackingType.path + "." + worldName + "." + chunkKey, blocks); }); }); if (this.rawData != null) { Map rawData = this.rawData.get(trackingType); if (rawData != null) { rawData.forEach((worldName, trackedBlocksData) -> { trackedBlocksData.getBlocks().forEach((chunkKey, blocksBitSet) -> { List blocks = new LinkedList<>(); blocksBitSet.forEach(blocks::add); if (!blocks.isEmpty()) section.set("tracked." + trackingType.path + "." + worldName + "." + chunkKey, blocks); }); }); } } } private BlocksTrackingComponent getComponent(TrackingType trackingType, World world) { BlocksTrackingComponent trackingComponent = loadRawData(trackingType, world); return trackingComponent != null ? trackingComponent : trackingComponentMap.computeIfAbsent(trackingType, t -> new HashMap<>()) .computeIfAbsent(world.getName(), uuid -> new BlocksTrackingComponent(world)); } private R ifComponentExists(TrackingType trackingType, World world, R def, Function function) { String worldName = world.getName(); BlocksTrackingComponent trackingComponent = loadRawData(trackingType, world); if (trackingComponent != null) return function.apply(trackingComponent); Map trackingTypeComponents = trackingComponentMap.get(trackingType); if (trackingTypeComponents != null) { trackingComponent = trackingTypeComponents.get(worldName); if (trackingComponent != null) return function.apply(trackingComponent); } return def; } private BlocksTrackingComponent loadRawData(TrackingType trackingType, World world) { String worldName = world.getName(); if (this.rawData != null) { Map rawData = this.rawData.get(trackingType); if (rawData != null) { TrackedBlocksData trackedBlocksData = rawData.remove(worldName); if (trackedBlocksData != null) { BlocksTrackingComponent trackingComponent = new BlocksTrackingComponent(world); trackingComponent.loadBlocks(trackedBlocksData); this.trackingComponentMap.computeIfAbsent(trackingType, i -> new HashMap<>()) .put(worldName, trackingComponent); if (rawData.isEmpty()) { this.rawData.remove(trackingType); if(this.rawData.isEmpty()) this.rawData = null; } return trackingComponent; } } } return null; } public enum TrackingType { PLACED_BLOCKS("placed"), BROKEN_BLOCKS("broken"); private final String path; TrackingType(String path) { this.path = path; } } } ================================================ FILE: Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTrackingComponent.java ================================================ package com.bgsoftware.superiorskyblock.missions.blocks; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectMethod; import org.bukkit.World; import java.util.Map; public class BlocksTrackingComponent { private static final ReflectMethod WORLD_GET_MIN_HEIGHT = new ReflectMethod<>( new ClassInfo("CraftWorld", ClassInfo.PackageType.CRAFTBUKKIT), "getMinHeight", new ClassInfo[0]); // Key represents chunk's coords // Value represents all blocks broken in that chunk private TrackedBlocksData trackedBlocksData = new TrackedBlocksData(); private final int worldMinHeight; public BlocksTrackingComponent(World world) { this(!WORLD_GET_MIN_HEIGHT.isValid() ? 0 : WORLD_GET_MIN_HEIGHT.invoke(world)); } public BlocksTrackingComponent(int worldMinHeight) { this.worldMinHeight = worldMinHeight; } public int getWorldMinHeight() { return worldMinHeight; } public void add(int blockX, int blockY, int blockZ) { long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4); this.trackedBlocksData.track(chunkKey, serializeLocation(blockX, blockY, blockZ)); } public boolean remove(int blockX, int blockY, int blockZ) { long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4); return this.trackedBlocksData.untrack(chunkKey, () -> serializeLocation(blockX, blockY, blockZ)); } public boolean contains(int blockX, int blockY, int blockZ) { long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4); return this.trackedBlocksData.contains(chunkKey, () -> serializeLocation(blockX, blockY, blockZ)); } public void loadBlocks(TrackedBlocksData trackedBlocksData) { this.trackedBlocksData = trackedBlocksData; } public Map getBlocks() { return this.trackedBlocksData.getBlocks(); } private int serializeLocation(int blockX, int blockY, int blockZ) { int chunkMinX = blockX >> 4 << 4; int chunkMinZ = blockZ >> 4 << 4; byte relativeX = (byte) (blockX - chunkMinX); short relativeY = (short) (blockY - this.worldMinHeight); byte relativeZ = (byte) (blockZ - chunkMinZ); return (relativeY << 8) | (relativeX << 4) | relativeZ; } private static long serializeChunk(int chunkX, int chunkZ) { return (long) chunkX << 32 | chunkZ; } } ================================================ FILE: Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/ChunkBitSet.java ================================================ package com.bgsoftware.superiorskyblock.missions.blocks; import java.util.Arrays; import java.util.BitSet; import java.util.function.IntConsumer; public class ChunkBitSet { private static final BitSet[] EMPTY_BIT_SET_ARRAY = new BitSet[0]; private BitSet[] bitSets = EMPTY_BIT_SET_ARRAY; public ChunkBitSet() { } public void set(int index) { BitSet bitSet = getBitSetForBlock(index, true); if (bitSet == null) throw new IllegalStateException(); int blockIdx = index & 0xFFF; bitSet.set(blockIdx); } public boolean clear(int index) { BitSet bitSet = getBitSetForBlock(index, false); if (bitSet == null) return false; int blockIdx = index & 0xFFF; boolean old = bitSet.get(blockIdx); bitSet.clear(blockIdx); return old; } public boolean get(int index) { BitSet bitSet = getBitSetForBlock(index, false); if (bitSet == null) return false; int blockIdx = index & 0xFFF; return bitSet.get(blockIdx); } public void forEach(IntConsumer consumer) { for (int i = 0; i < this.bitSets.length; ++i) { BitSet bitSet = this.bitSets[i]; if (bitSet != null) { for (int j = bitSet.nextSetBit(0); j != -1; j = bitSet.nextSetBit(j + 1)) { consumer.accept(((i << 4) << 8) | j); } } } } private void ensureCapacity(int capacity) { if (bitSets.length >= capacity) return; bitSets = Arrays.copyOf(bitSets, capacity); } private BitSet getBitSetForBlock(int block, boolean createNew) { int sectionIdx = (block >> 8) >> 4; if (bitSets.length <= sectionIdx) { if (!createNew) return null; ensureCapacity(sectionIdx + 1); } BitSet bitSet = bitSets[sectionIdx]; if (bitSet == null) { if (!createNew) return null; bitSet = bitSets[sectionIdx] = new BitSet(); } return bitSet; } } ================================================ FILE: Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/TrackedBlocksData.java ================================================ package com.bgsoftware.superiorskyblock.missions.blocks; import org.bukkit.configuration.ConfigurationSection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.IntSupplier; public class TrackedBlocksData { private final Map TRACKED_BLOCKS = new HashMap<>(); private final Map TRACKED_BLOCKS_VIEW = Collections.unmodifiableMap(TRACKED_BLOCKS); public TrackedBlocksData(ConfigurationSection section) { for (String chunkKey : section.getKeys(false)) { List trackedBlocks = section.getIntegerList(chunkKey); ChunkBitSet bitSet = new ChunkBitSet(); trackedBlocks.forEach(bitSet::set); try { TRACKED_BLOCKS.put(Long.parseLong(chunkKey), bitSet); } catch (NumberFormatException ignored) { } } } public TrackedBlocksData() { } public void track(long chunkKey, int block) { TRACKED_BLOCKS.computeIfAbsent(chunkKey, key -> new ChunkBitSet()).set(block); } public boolean untrack(long chunkKey, IntSupplier block) { return Optional.ofNullable(TRACKED_BLOCKS.get(chunkKey)) .map(bitSet -> bitSet.clear(block.getAsInt())) .orElse(false); } public boolean contains(long chunkKey, IntSupplier block) { return Optional.ofNullable(TRACKED_BLOCKS.get(chunkKey)) .map(bitSet -> bitSet.get(block.getAsInt())) .orElse(false); } public Map getBlocks() { return TRACKED_BLOCKS_VIEW; } } ================================================ FILE: Missions/BrewingMissions/build.gradle ================================================ group 'Missions:BrewingMissions' dependencies { compileOnly "org.spigotmc:v1_16_R3:latest" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.brewing' } ================================================ FILE: Missions/BrewingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BrewingMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.Placeholders; import com.bgsoftware.superiorskyblock.missions.common.requirements.CustomRequirements; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.BrewingStand; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.inventory.BrewEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.BrewerInventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.Potion; import org.bukkit.potion.PotionType; import javax.annotation.Nullable; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.function.Predicate; public final class BrewingMissions extends BuiltinMission implements Listener { private static final boolean isUsing18 = Bukkit.getServer().getClass().getPackage().getName().contains("1_8"); private final Map, Integer> requiredPotions = new LinkedHashMap<>(); private final Map trackedBrewItems = new HashMap<>(); @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { ConfigurationSection requiredPotionsSection = section.getConfigurationSection("required-potions"); if (requiredPotionsSection == null) throw new MissionLoadException("You must have the \"required-potions\" section in the config."); for (String key : requiredPotionsSection.getKeys(false)) { CustomRequirements requiredPotions = new CustomRequirements<>(); ConfigurationSection potionsSection = section.getConfigurationSection("required-potions." + key + ".potions"); for (String potionSectionName : potionsSection.getKeys(false)) { ConfigurationSection potionSection = potionsSection.getConfigurationSection(potionSectionName); if (potionSection == null) { plugin.getLogger().info(ChatColor.RED + "Potion section " + potionSectionName + " is invalid, skipping..."); continue; } PotionType potionType; try { potionType = PotionType.valueOf(potionSection.getString("type")); } catch (Exception ex) { plugin.getLogger().info(ChatColor.RED + "Potion type in section " + potionsSection.getCurrentPath() + "." + potionSectionName + " is invalid, skipping..."); continue; } boolean upgraded = potionSection.getBoolean("upgraded", false); boolean extended = potionSection.getBoolean("extended", false); boolean splash = potionSection.getBoolean("splash", false); requiredPotions.add(new PotionData(potionType, upgraded, extended, splash)); } if (!requiredPotions.isEmpty()) { int requiredAmount = section.getInt("required-potions." + key + ".amount"); this.requiredPotions.put(requiredPotions, requiredAmount); } } if (requiredPotions.isEmpty()) { throw new MissionLoadException("There are no valid required potions for this mission."); } } @Override protected void registerListeners() { registerListener(this); } @Override protected void clearModuleData(BrewingTracker data) { data.brewingTracker.clear(); } @Override public double getProgress(SuperiorPlayer superiorPlayer) { BrewingTracker brewingTracker = get(superiorPlayer); if (brewingTracker == null) return 0.0; int requiredPotions = 0; int kills = 0; for (Map.Entry, Integer> requiredPotion : this.requiredPotions.entrySet()) { requiredPotions += requiredPotion.getValue(); kills += Math.min(brewingTracker.getBrews(requiredPotion.getKey()), requiredPotion.getValue()); } return (double) kills / requiredPotions; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { BrewingTracker brewingTracker = get(superiorPlayer); if (brewingTracker == null) return 0; int kills = 0; for (Map.Entry, Integer> requiredEntity : this.requiredPotions.entrySet()) kills += Math.min(brewingTracker.getBrews(requiredEntity.getKey()), requiredEntity.getValue()); return kills; } @Override public void saveProgress(ConfigurationSection section) { for (Map.Entry entry : entrySet()) { String uuid = entry.getKey().getUniqueId().toString(); for (Map.Entry brokenEntry : entry.getValue().brewingTracker.entrySet()) { section.set(uuid + "." + brokenEntry.getKey(), brokenEntry.getValue()); } } } @Override public void loadProgress(ConfigurationSection section) { for (String uuid : section.getKeys(false)) { BrewingTracker brewingTracker = new BrewingTracker(); UUID playerUUID = UUID.fromString(uuid); SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); insertData(superiorPlayer, brewingTracker); for (String key : section.getConfigurationSection(uuid).getKeys(false)) { brewingTracker.brewingTracker.put(PotionData.fromString(key), section.getInt(uuid + "." + key)); } } } @Override public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { BrewingTracker brewingTracker = getOrCreate(superiorPlayer, s -> new BrewingTracker()); if (brewingTracker == null) return; ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta == null) return; Placeholders.PlaceholdersFunctions> placeholdersFunctions = new Placeholders.PlaceholdersFunctions>() { @Override public CustomRequirements getRequirementFromKey(String key) { PotionData potionData = PotionData.fromString(key); for (CustomRequirements requirements : requiredPotions.keySet()) { if (requirements.contains(potionData)) return requirements; } return null; } @Override public Optional lookupRequirement(CustomRequirements requirement) { return Optional.ofNullable(requiredPotions.get(requirement)); } @Override public int getCountForRequirement(CustomRequirements requirement) { return brewingTracker.getBrews(requirement); } }; if (itemMeta.hasDisplayName()) itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions)); if (itemMeta.hasLore()) { List lore = new LinkedList<>(); for (String line : Objects.requireNonNull(itemMeta.getLore())) lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions)); itemMeta.setLore(lore); } itemStack.setItemMeta(itemMeta); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBrew(BrewEvent e) { ItemStack[] originalResultItems = new ItemStack[3]; for (int i = 0; i < 3; ++i) { ItemStack resultItem = e.getContents().getItem(i); if (resultItem != null) { originalResultItems[i] = resultItem.clone(); } } Bukkit.getScheduler().runTaskLater(plugin, () -> { for (int i = 0; i < 3; ++i) { ItemStack resultItem = e.getContents().getItem(i); if (resultItem != null && !resultItem.isSimilar(originalResultItems[i]) && isMissionBrewing(resultItem)) { trackedBrewItems.computeIfAbsent(e.getBlock().getLocation(), block -> new boolean[3])[i] = true; } } }, 1L); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBrew(InventoryClickEvent e) { if (!(e.getClickedInventory() instanceof BrewerInventory) || e.getRawSlot() > 2) return; BrewerInventory inventory = (BrewerInventory) e.getClickedInventory(); handleBrewing((Player) e.getWhoClicked(), inventory, slot -> slot == e.getRawSlot()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent e) { BlockState blockState = e.getBlock().getState(); if (!(blockState instanceof BrewingStand)) return; BrewingStand brewingStand = (BrewingStand) blockState; handleBrewing(e.getPlayer(), brewingStand.getInventory(), slot -> true); } private void handleBrewing(Player player, BrewerInventory inventory, Predicate checkSlot) { Block block = inventory.getHolder().getBlock(); boolean[] brewItems = this.trackedBrewItems.get(block.getLocation()); if (brewItems == null) { return; } try { SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player); if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) return; BrewingTracker brewingTracker = getOrCreate(superiorPlayer, s -> new BrewingTracker()); if (brewingTracker == null) return; for (int i = 0; i < 3; ++i) { if (checkSlot.test(i) && brewItems[i]) { brewItems[i] = false; ItemStack brewItem = inventory.getItem(i); brewingTracker.track(brewItem, brewItem.getAmount()); } } this.plugin.getServer().getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(unused -> { if (canComplete(superiorPlayer)) this.plugin.getMissions().rewardMission(this, superiorPlayer, true); }), 2L); } finally { if (!brewItems[0] && !brewItems[1] && !brewItems[2]) this.trackedBrewItems.remove(block.getLocation()); } } private boolean isMissionBrewing(ItemStack itemStack) { PotionData potionData = PotionData.fromItemStack(itemStack); if (potionData == null) return false; for (Collection requiredPotion : requiredPotions.keySet()) { if (requiredPotion.contains(potionData)) return true; } return false; } public static class BrewingTracker { private final Map brewingTracker = new HashMap<>(); void track(ItemStack brewing, int amount) { PotionData potionData = PotionData.fromItemStack(brewing); int newAmount = amount + brewingTracker.getOrDefault(potionData, 0); brewingTracker.put(potionData, newAmount); } int getBrews(Collection potions) { int amount = 0; for (Map.Entry potionData : brewingTracker.entrySet()) { if (potions.contains(potionData.getKey())) amount += potionData.getValue(); } return amount; } } private static class PotionData { private final PotionType potionType; private final boolean upgraded; private final boolean extended; private final boolean splash; public PotionData(PotionType potionType, boolean upgraded, boolean extended, boolean splash) { this.potionType = potionType; this.upgraded = upgraded; this.extended = extended; this.splash = splash; } @Nullable public static PotionData fromItemStack(ItemStack itemStack) { return isUsing18 ? fromItemStack18(itemStack) : fromItemStack19(itemStack); } public static PotionData fromString(String line) { String[] sections = line.split(";"); PotionType potionType; try { potionType = PotionType.valueOf(sections[0]); } catch (IllegalArgumentException ex) { throw new IllegalArgumentException("Potion type '" + sections[0] + "' is invalid."); } boolean upgraded = sections.length >= 2 && Boolean.parseBoolean(sections[1]); boolean extended = sections.length >= 3 && Boolean.parseBoolean(sections[2]); boolean splash = sections.length >= 4 && Boolean.parseBoolean(sections[3]); return new PotionData(potionType, upgraded, extended, splash); } private static PotionData fromItemStack19(ItemStack itemStack) { ItemMeta itemMeta = itemStack.getItemMeta(); if (!(itemMeta instanceof PotionMeta)) { return null; } PotionMeta potionMeta = (PotionMeta) itemMeta; org.bukkit.potion.PotionData potionData = potionMeta.getBasePotionData(); return new PotionData(potionData.getType(), potionData.isUpgraded(), potionData.isExtended(), itemStack.getType() == Material.SPLASH_POTION); } @SuppressWarnings("deprecation") private static PotionData fromItemStack18(ItemStack itemStack) { Potion potion = Potion.fromItemStack(itemStack); return new PotionData(potion.getType(), potion.getLevel() > 1, potion.hasExtendedDuration(), potion.isSplash()); } @Override public String toString() { return potionType.name() + ";" + upgraded + ";" + extended + ";" + splash; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PotionData that = (PotionData) o; return upgraded == that.upgraded && extended == that.extended && splash == that.splash && potionType == that.potionType; } @Override public int hashCode() { return Objects.hash(potionType, upgraded, extended, splash); } } } ================================================ FILE: Missions/CraftingMissions/build.gradle ================================================ group 'Missions:EnchantingMissions' dependencies { compileOnly "org.spigotmc:v1_8_R3-Taco:latest" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.crafting' } ================================================ FILE: Missions/CraftingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/CraftingMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.Placeholders; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.ItemMeta; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; public final class CraftingMissions extends BuiltinMission implements Listener { private final Map itemsToCraft = new LinkedHashMap<>(); @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { ConfigurationSection craftingsSection = section.getConfigurationSection("craftings"); if (craftingsSection == null) throw new MissionLoadException("You must have the \"craftings\" section in the config."); for (String key : craftingsSection.getKeys(false)) { String type = section.getString("craftings." + key + ".type"); short data = (short) section.getInt("craftings." + key + ".data", 0); int amount = section.getInt("craftings." + key + ".amount", 1); Material material; try { material = Material.valueOf(type); } catch (IllegalArgumentException ex) { throw new MissionLoadException("Invalid crafting result " + type + "."); } this.itemsToCraft.put(new ItemStack(material, 1, data), amount); } } @Override protected void registerListeners() { registerListener(this); } @Override protected void clearModuleData(CraftingsTracker data) { data.craftedItems.clear(); } @Override public double getProgress(SuperiorPlayer superiorPlayer) { CraftingsTracker craftingsTracker = get(superiorPlayer); if (craftingsTracker == null) return 0.0; int requiredItems = 0; int interactions = 0; for (Map.Entry entry : this.itemsToCraft.entrySet()) { requiredItems += entry.getValue(); interactions += Math.min(craftingsTracker.getCrafts(entry.getKey()), entry.getValue()); } return (double) interactions / requiredItems; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { CraftingsTracker craftingsTracker = get(superiorPlayer); if (craftingsTracker == null) return 0; int interactions = 0; for (Map.Entry entry : this.itemsToCraft.entrySet()) interactions += Math.min(craftingsTracker.getCrafts(entry.getKey()), entry.getValue()); return interactions; } @Override public void saveProgress(ConfigurationSection section) { for (Map.Entry entry : entrySet()) { String uuid = entry.getKey().getUniqueId().toString(); int index = 0; for (Map.Entry craftedEntry : entry.getValue().craftedItems.entrySet()) { section.set(uuid + "." + index + ".item", craftedEntry.getKey()); section.set(uuid + "." + index + ".amount", craftedEntry.getValue()); index++; } } } @Override public void loadProgress(ConfigurationSection section) { for (String uuid : section.getKeys(false)) { if (uuid.equals("players")) continue; CraftingsTracker craftingsTracker = new CraftingsTracker(); UUID playerUUID = UUID.fromString(uuid); SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); insertData(superiorPlayer, craftingsTracker); for (String key : section.getConfigurationSection(uuid).getKeys(false)) { ItemStack itemStack = section.getItemStack(uuid + "." + key + ".item"); int amount = section.getInt(uuid + "." + key + ".amount"); craftingsTracker.craftedItems.put(itemStack, amount); } } } @Override public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { CraftingsTracker craftingsTracker = getOrCreate(superiorPlayer, s -> new CraftingsTracker()); if (craftingsTracker == null) return; ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta == null) return; Placeholders.PlaceholdersFunctions placeholdersFunctions = new Placeholders.PlaceholdersFunctions() { @Override public ItemStack getRequirementFromKey(String key) { return new ItemStack(Material.valueOf(key)); } @Override public Optional lookupRequirement(ItemStack requirement) { return itemsToCraft.entrySet().stream() .filter(e -> e.getKey().isSimilar(requirement)) .findFirst() .map(Map.Entry::getValue); } @Override public int getCountForRequirement(ItemStack requirement) { return craftingsTracker.getCrafts(requirement); } }; if (itemMeta.hasDisplayName()) itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions)); if (itemMeta.hasLore()) { List lore = new ArrayList<>(); for (String line : Objects.requireNonNull(itemMeta.getLore())) lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions)); itemMeta.setLore(lore); } itemStack.setItemMeta(itemMeta); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onInventoryClick(InventoryClickEvent e) { if (e.getClickedInventory() == null || (e.getClickedInventory().getType() != InventoryType.WORKBENCH && e.getClickedInventory().getType() != InventoryType.CRAFTING && e.getClickedInventory().getType() != InventoryType.FURNACE)) return; int requiredSlot = e.getClickedInventory().getType() == InventoryType.FURNACE ? 2 : 0; ItemStack resultItem = e.getCurrentItem().clone(); resultItem.setAmount(1); SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer((Player) e.getWhoClicked()); if (e.getRawSlot() == requiredSlot && itemsToCraft.containsKey(resultItem) && this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) { int amountOfResult = countItems(e.getWhoClicked(), resultItem); Bukkit.getScheduler().runTaskLater(this.plugin, () -> { int afterTickAmountOfResult = countItems(e.getWhoClicked(), resultItem); resultItem.setAmount(afterTickAmountOfResult - amountOfResult); trackItem(superiorPlayer, resultItem); }, 1L); } } private void trackItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { CraftingsTracker blocksTracker = getOrCreate(superiorPlayer, s -> new CraftingsTracker()); if (blocksTracker == null) return; blocksTracker.trackItem(itemStack); Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(player -> { if (canComplete(superiorPlayer)) this.plugin.getMissions().rewardMission(this, superiorPlayer, true); }), 2L); } private static int countItems(HumanEntity humanEntity, ItemStack itemStack) { int amount = 0; if (itemStack == null) return amount; PlayerInventory playerInventory = humanEntity.getInventory(); for (ItemStack invItem : playerInventory.getContents()) { if (invItem != null && itemStack.isSimilar(invItem)) amount += invItem.getAmount(); } if (humanEntity.getItemOnCursor() != null && itemStack.isSimilar(humanEntity.getItemOnCursor())) amount += humanEntity.getItemOnCursor().getAmount(); return amount; } public static class CraftingsTracker { private final Map craftedItems = new HashMap<>(); void trackItem(ItemStack itemStack) { ItemStack keyItem = itemStack.clone(); keyItem.setAmount(1); craftedItems.put(keyItem, craftedItems.getOrDefault(keyItem, 0) + itemStack.getAmount()); } int getCrafts(ItemStack itemStack) { ItemStack keyItem = itemStack.clone(); keyItem.setAmount(1); return craftedItems.getOrDefault(keyItem, 0); } } } ================================================ FILE: Missions/EnchantingMissions/build.gradle ================================================ group 'Missions:EnchantingMissions' dependencies { compileOnly "org.spigotmc:v1_9_R1:latest" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.enchanting' } ================================================ FILE: Missions/EnchantingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/EnchantingMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.Placeholders; import com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements; import com.bgsoftware.superiorskyblock.missions.common.tracker.RawDataTracker; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.enchantment.EnchantItemEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; public final class EnchantingMissions extends BuiltinMission implements Listener { private static final Pattern ENCHANTED_PATTERN = Pattern.compile("\\{enchanted_(.+?)}"); private final Map requiredEnchantments = new LinkedHashMap<>(); private String enchantedPlaceholder, notEnchantedPlaceholder; @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { ConfigurationSection requiredEnchantsSection = section.getConfigurationSection("required-enchants"); if (requiredEnchantsSection == null) throw new MissionLoadException("You must have the \"required-enchants\" section in the config."); for (String key : requiredEnchantsSection.getKeys(false)) { List itemTypes = section.getStringList("required-enchants." + key + ".types"); Map enchantments = new HashMap<>(); ConfigurationSection enchantsSection = section.getConfigurationSection("required-enchants." + key + ".enchants"); if (enchantsSection == null) throw new MissionLoadException("You must have the \"required-enchants." + key + ".enchants\" section in the config."); for (String enchantment : enchantsSection.getKeys(false)) { Enchantment _enchantment = Enchantment.getByName(enchantment.toUpperCase(Locale.ENGLISH)); if (_enchantment == null) throw new MissionLoadException("Enchantment " + enchantment + " is not valid."); enchantments.put(_enchantment, section.getInt("required-enchants." + key + ".enchants." + enchantment)); } if (!enchantments.isEmpty()) { this.requiredEnchantments.put(new Requirements(itemTypes), new RequiredEnchantment(key, enchantments, section.getInt("required-enchants." + key + ".amount", 1))); } } this.enchantedPlaceholder = section.getString("enchanted-placeholder", "Yes"); this.notEnchantedPlaceholder = section.getString("not-enchanted-placeholder", "No"); } @Override protected void registerListeners() { registerListener(this); try { Class.forName("org.bukkit.event.inventory.PrepareAnvilEvent"); registerListener(new PrepareAnvilListener()); } catch (Exception ignored) { } } @Override protected void clearModuleData(RawDataTracker data) { data.clear(); } @Override public double getProgress(SuperiorPlayer superiorPlayer) { RawDataTracker enchantsTracker = get(superiorPlayer); if (enchantsTracker == null) return 0.0; int requiredItems = 0; int enchants = 0; for (RequiredEnchantment requiredEnchantment : this.requiredEnchantments.values()) { requiredItems += requiredEnchantment.amount; enchants += Math.min(enchantsTracker.getCount(requiredEnchantment.key), requiredEnchantment.amount); } return (double) enchants / requiredItems; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { RawDataTracker enchantsTracker = get(superiorPlayer); if (enchantsTracker == null) return 0; int enchants = 0; for (RequiredEnchantment requiredEnchantment : this.requiredEnchantments.values()) { enchants += Math.min(enchantsTracker.getCount(requiredEnchantment.key), requiredEnchantment.amount); } return enchants; } @Override public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { RawDataTracker enchantsTracker = getOrCreate(superiorPlayer, s -> new RawDataTracker()); if (enchantsTracker == null) return; ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta == null) return; Placeholders.PlaceholdersFunctions placeholdersFunctions = new Placeholders.PlaceholdersFunctions() { @Override public Requirements getRequirementFromKey(String key) { for (Requirements requirements : requiredEnchantments.keySet()) { if (requirements.contains(key)) return requirements; } return null; } @Override public Optional lookupRequirement(Requirements requirement) { return Optional.ofNullable(requiredEnchantments.get(requirement)) .map(requiredEnchantment -> requiredEnchantment.amount); } @Override public int getCountForRequirement(Requirements requirement) { return Optional.ofNullable(requiredEnchantments.get(requirement)) .map(requiredEnchantment -> enchantsTracker.getCount(requiredEnchantment.key)) .orElse(0); } }; if (itemMeta.hasDisplayName()) itemMeta.setDisplayName(parsePlaceholders(placeholdersFunctions, enchantsTracker, itemMeta.getDisplayName())); if (itemMeta.hasLore()) { List lore = new ArrayList<>(); for (String line : Objects.requireNonNull(itemMeta.getLore())) lore.add(parsePlaceholders(placeholdersFunctions, enchantsTracker, line)); itemMeta.setLore(lore); } itemStack.setItemMeta(itemMeta); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onItemEnchant(EnchantItemEvent e) { ItemStack simulateEnchanted = e.getItem().clone(); ItemMeta itemMeta = simulateEnchanted.getItemMeta(); for (Map.Entry entry : e.getEnchantsToAdd().entrySet()) { if (simulateEnchanted.getType() == Material.BOOK) { simulateEnchanted = new ItemStack(Material.ENCHANTED_BOOK); itemMeta = simulateEnchanted.getItemMeta(); } if (itemMeta == null) continue; if (simulateEnchanted.getType() == Material.ENCHANTED_BOOK) { ((EnchantmentStorageMeta) itemMeta).addStoredEnchant(entry.getKey(), entry.getValue(), true); } else if (entry.getKey().canEnchantItem(simulateEnchanted)) { itemMeta.addEnchant(entry.getKey(), entry.getValue(), true); } } simulateEnchanted.setItemMeta(itemMeta); getMissionRequirement(simulateEnchanted).ifPresent(requirement -> handleEnchanting(e.getEnchanter(), requirement)); } @Override public void saveProgress(ConfigurationSection section) { for (Map.Entry entry : entrySet()) { String uuid = entry.getKey().getUniqueId().toString(); List data = new ArrayList<>(); entry.getValue().getCounts().forEach((enchant, amount) -> data.add(enchant + ";" + amount.get())); section.set(uuid, data); } } @Override public void loadProgress(ConfigurationSection section) { for (String uuid : section.getKeys(false)) { RawDataTracker enchantsTracker = new RawDataTracker(); UUID playerUUID = UUID.fromString(uuid); SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); insertData(superiorPlayer, enchantsTracker); section.getStringList(uuid).forEach(line -> { String[] sections = line.split(";"); int amount = sections.length == 2 ? Integer.parseInt(sections[1]) : 1; String enchantment = sections[0]; enchantsTracker.load(enchantment, amount); }); } } private Optional getMissionRequirement(ItemStack itemStack) { outerLoop: for (Map.Entry requirement : this.requiredEnchantments.entrySet()) { if (!requirement.getKey().contains(itemStack.getType().name())) continue; for (Map.Entry requiredEnchantment : requirement.getValue().enchantments.entrySet()) { Enchantment enchantment = requiredEnchantment.getKey(); int requiredLevel = requiredEnchantment.getValue(); if (itemStack.getType() == Material.ENCHANTED_BOOK) { EnchantmentStorageMeta storageMeta = (EnchantmentStorageMeta) itemStack.getItemMeta(); if (storageMeta == null || storageMeta.getStoredEnchantLevel(enchantment) < requiredLevel) continue outerLoop; } else if (itemStack.getEnchantmentLevel(enchantment) < requiredLevel) { continue outerLoop; } } return Optional.of(requirement.getValue()); } return Optional.empty(); } private void handleEnchanting(Player player, RequiredEnchantment requirement) { SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player); if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) return; RawDataTracker enchantsTracker = getOrCreate(superiorPlayer, s -> new RawDataTracker()); if (enchantsTracker == null) return; enchantsTracker.track(requirement.key, 1); Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(_player -> { if (canComplete(superiorPlayer)) this.plugin.getMissions().rewardMission(this, superiorPlayer, true); }), 2L); } private String parsePlaceholders(Placeholders.PlaceholdersFunctions placeholdersFunctions, RawDataTracker enchantsTracker, String line) { Matcher matcher = ENCHANTED_PATTERN.matcher(line); if (matcher.find()) { String requiredBlock = matcher.group(1).toUpperCase(Locale.ENGLISH); Optional> entry = requiredEnchantments.entrySet().stream() .filter(e -> e.getKey().contains(requiredBlock)).findAny(); if (entry.isPresent()) { RequiredEnchantment requiredEnchantment = entry.get().getValue(); line = matcher.replaceAll(enchantsTracker.getCount(requiredEnchantment.key) > 0 ? enchantedPlaceholder : notEnchantedPlaceholder); } } return Placeholders.parsePlaceholders(line, placeholdersFunctions); } private static class RequiredEnchantment { private final String key; private final Map enchantments; private final Integer amount; RequiredEnchantment(String key, Map enchantments, Integer amount) { this.key = key; this.enchantments = enchantments; this.amount = amount; } } private class PrepareAnvilListener implements Listener { private final Map addingEnchantments = new HashMap<>(); @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onItemAnvil(org.bukkit.event.inventory.PrepareAnvilEvent e) { if (e.getResult() == null || !isAddingEnchantment(e)) return; getMissionRequirement(e.getResult()).ifPresent(requirement -> addingEnchantments.put(e.getView().getPlayer().getUniqueId(), requirement)); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onItemAnvil(InventoryClickEvent e) { if (e.getRawSlot() != 2) return; RequiredEnchantment requiredEnchantment = addingEnchantments.remove(e.getWhoClicked().getUniqueId()); if (requiredEnchantment == null) return; handleEnchanting((Player) e.getWhoClicked(), requiredEnchantment); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onInventoryClose(InventoryCloseEvent e) { addingEnchantments.remove(e.getPlayer().getUniqueId()); } private boolean isAddingEnchantment(org.bukkit.event.inventory.PrepareAnvilEvent e) { ItemStack result = e.getResult(); if (result == null) return false; ItemStack firstSlot = e.getInventory().getItem(0); if (firstSlot == null) return false; ItemStack secondSlot = e.getInventory().getItem(1); if (secondSlot == null) return false; return firstSlot.getType() == secondSlot.getType() || secondSlot.getType().name().contains("BOOK"); } } } ================================================ FILE: Missions/FarmingMissions/build.gradle ================================================ group 'Missions:FarmingMissions' dependencies { compileOnly "org.spigotmc:v1_16_R3:latest" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.farming' } ================================================ FILE: Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FarmingMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.Placeholders; import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; import com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker; import com.bgsoftware.superiorskyblock.missions.farming.PlantType; import com.bgsoftware.superiorskyblock.missions.farming.PlantsTracker; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockGrowEvent; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockSpreadEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; public final class FarmingMissions extends BuiltinMission implements Listener { private static final BlockFace[] STEM_NEARBY_BLOCKS = new BlockFace[]{ BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH }; private static final BlockFace[] CHORUS_NEARBY_BLOCKS = new BlockFace[]{ BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.DOWN }; private final Map requiredPlants = new LinkedHashMap<>(); @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { ConfigurationSection requiredPlantsSection = section.getConfigurationSection("required-plants"); if (requiredPlantsSection == null) throw new MissionLoadException("You must have the \"required-plants\" section in the config."); for (String key : requiredPlantsSection.getKeys(false)) { KeySet requiredPlants = KeySet.createKeySet(); section.getStringList("required-plants." + key + ".types").forEach(requiredPlant -> requiredPlants.add(Key.ofMaterialAndData(requiredPlant.toUpperCase(Locale.ENGLISH)))); int requiredAmount = section.getInt("required-plants." + key + ".amount"); this.requiredPlants.put(new KeyRequirements(requiredPlants), requiredAmount); } } @Override protected void registerListeners() { registerListener(this); } @Override protected void clearModuleData(KeyDataTracker data) { data.clear(); } @Override public double getProgress(SuperiorPlayer superiorPlayer) { KeyDataTracker farmingTracker = get(superiorPlayer); if (farmingTracker == null) return 0.0; int requiredPlants = 0; int grewPlants = 0; for (Map.Entry requiredPlant : this.requiredPlants.entrySet()) { requiredPlants += requiredPlant.getValue(); grewPlants += Math.min(farmingTracker.getCounts(requiredPlant.getKey()), requiredPlant.getValue()); } return (double) grewPlants / requiredPlants; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { KeyDataTracker farmingTracker = get(superiorPlayer); if (farmingTracker == null) return 0; int kills = 0; for (Map.Entry requiredPlant : this.requiredPlants.entrySet()) kills += Math.min(farmingTracker.getCounts(requiredPlant.getKey()), requiredPlant.getValue()); return kills; } @Override public void saveProgress(ConfigurationSection section) { for (Map.Entry entry : entrySet()) { String uuid = entry.getKey().getUniqueId().toString(); entry.getValue().getCounts().forEach((plant, count) -> section.set("grown-plants." + uuid + "." + plant, count.get())); } PlantsTracker.INSTANCE.save(section); } @Override public void loadProgress(ConfigurationSection section) { ConfigurationSection grownPlants = section.getConfigurationSection("grown-plants"); if (grownPlants != null) { for (String uuid : grownPlants.getKeys(false)) { KeyDataTracker farmingTracker = new KeyDataTracker(); UUID playerUUID = UUID.fromString(uuid); SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); insertData(superiorPlayer, farmingTracker); for (String key : grownPlants.getConfigurationSection(uuid).getKeys(false)) { Key typeKey = getMissionPlantKey(Key.ofMaterialAndData(key)); farmingTracker.load(typeKey, grownPlants.getInt(uuid + "." + key)); } } } ConfigurationSection placedPlants = section.getConfigurationSection("placed-plants"); if (placedPlants != null) { int dataVersion = section.getInt("data-version", 0); if (dataVersion == 0) { loadLegacyData(placedPlants); } else { for (String placerUUID : placedPlants.getKeys(false)) { UUID placer = UUID.fromString(placerUUID); ConfigurationSection placerSection = placedPlants.getConfigurationSection(placerUUID); if (placerSection == null) continue; for (String worldName : placerSection.getKeys(false)) { ConfigurationSection worldSection = placerSection.getConfigurationSection(worldName); if (worldSection == null) continue; for (String chunkKey : worldSection.getKeys(false)) { PlantsTracker.INSTANCE.load(worldName, Long.parseLong(chunkKey), worldSection.getIntegerList(chunkKey), placer); } } } ConfigurationSection legacyPlacedPlants = section.getConfigurationSection("placed-plants-legacy"); if (legacyPlacedPlants != null) loadLegacyData(legacyPlacedPlants); } } } private void loadLegacyData(ConfigurationSection section) { for (String locationKey : section.getKeys(false)) { UUID placer = UUID.fromString(section.getString(locationKey)); String[] sections = locationKey.split(";"); if (sections.length == 4) { BlockPosition plantPosition = plugin.getFactory().createBlockPosition(Integer.parseInt(sections[1]), Integer.parseInt(sections[2]), Integer.parseInt(sections[3])); PlantsTracker.INSTANCE.loadLegacy(sections[0], plantPosition, placer); } } } @Override public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { KeyDataTracker farmingTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); if (farmingTracker == null) return; ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta == null) return; if (itemMeta.hasDisplayName()) itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredPlants, farmingTracker, itemMeta.getDisplayName(), true)); if (itemMeta.hasLore()) { List lore = new ArrayList<>(); for (String line : Objects.requireNonNull(itemMeta.getLore())) lore.add(Placeholders.parseKeyPlaceholders(this.requiredPlants, farmingTracker, line, true)); itemMeta.setLore(lore); } itemStack.setItemMeta(itemMeta); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockPlace(BlockPlaceEvent e) { PlantType plantType = PlantType.getBySaplingType(e.getBlock().getType()); Key plantKey = plantType == PlantType.UNKNOWN ? Key.of(e.getBlock()) : plantType.getCachedKey(); if (getMissionPlantKey(plantKey) == null) return; PlantsTracker.INSTANCE.track(e.getBlock(), e.getPlayer().getUniqueId()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockBreak(BlockBreakEvent e) { PlantsTracker.INSTANCE.untrack(e.getBlock()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockExplode(EntityExplodeEvent e) { for (Block block : e.blockList()) PlantsTracker.INSTANCE.untrack(block); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPistonRetract(BlockPistonRetractEvent e) { for (Block block : e.getBlocks()) PlantsTracker.INSTANCE.untrack(block); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPistonRetract(BlockPistonExtendEvent e) { for (Block block : e.getBlocks()) PlantsTracker.INSTANCE.untrack(block); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBambooGrow(BlockSpreadEvent e) { handlePlantGrow(e.getBlock(), e.getNewState()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlantGrow(StructureGrowEvent e) { Block block = e.getLocation().getBlock(); handlePlantGrow(block, block.getState()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlantGrow(BlockGrowEvent e) { handlePlantGrow(e.getBlock(), e.getNewState()); } private void handlePlantGrow(Block plantBlock, BlockState newState) { PlantType plantType = PlantType.getByType(newState.getType()); Key plantKey = plantType == PlantType.UNKNOWN ? Key.of(newState) : plantType.getCachedKey(); plantKey = getMissionPlantKey(plantKey); if (plantKey == null) return; int maxAge = plantType.getMaxAge(); if (maxAge > 0 && getBlockAge(newState) < maxAge) return; Location placedBlockLocation = plantBlock.getLocation(); switch (plantType) { case CACTUS: case SUGAR_CANE: case BAMBOO: placedBlockLocation = getRoot(plantBlock); break; case MELON: case PUMPKIN: placedBlockLocation = getStemRoot(plantType, plantBlock); break; case CHORUS_PLANT: placedBlockLocation = getChorusRoot(plantBlock); break; } UUID placerUUID = PlantsTracker.INSTANCE.getPlacer(placedBlockLocation); if (placerUUID == null) return; SuperiorPlayer playerTracked; SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(placerUUID); if (getIslandMission()) { // In case this is an island mission, we want to get the uuid of the owner. Island island = superiorPlayer.getIsland(); if (island == null) return; playerTracked = island.getOwner(); } else { playerTracked = superiorPlayer; } if (!this.plugin.getMissions().canCompleteNoProgress(playerTracked, this)) return; KeyDataTracker farmingTracker = getOrCreate(playerTracked, s -> new KeyDataTracker()); if (farmingTracker == null) return; farmingTracker.track(plantKey, 1); Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> playerTracked.runIfOnline(player -> { if (canComplete(playerTracked)) this.plugin.getMissions().rewardMission(this, playerTracked, true); }), 2L); } private int getBlockAge(BlockState newState) { try { BlockData blockData = newState.getBlockData(); return blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0; } catch (Throwable error) { // noinspection deprecation return newState.getRawData(); } } private static Location getRoot(Block original) { Block lastSimilarBlock = original.getRelative(BlockFace.DOWN); Material originalType = lastSimilarBlock.getType(); while (lastSimilarBlock.getType() == originalType) { lastSimilarBlock = lastSimilarBlock.getRelative(BlockFace.DOWN); } return lastSimilarBlock.getLocation().add(0, 1, 0); } private static Location getStemRoot(PlantType plantType, Block plantBlock) { Material stemType = plantType == PlantType.PUMPKIN ? Material.PUMPKIN_STEM : Material.MELON_STEM; for (BlockFace blockFace : STEM_NEARBY_BLOCKS) { Block nearbyBlock = plantBlock.getRelative(blockFace); if (nearbyBlock.getType() == stemType) { return nearbyBlock.getLocation(); } } return plantBlock.getLocation(); } private static Location getChorusRoot(Block plantBlock) { return findChorusRoot(plantBlock, BlockFace.SELF).orElseGet(plantBlock::getLocation); } private static Optional findChorusRoot(Block plantBlock, BlockFace ignoredFace) { Block downBlock = plantBlock.getRelative(BlockFace.DOWN); if (downBlock.getType() == Material.END_STONE) return Optional.of(plantBlock.getLocation()); for (BlockFace blockFace : CHORUS_NEARBY_BLOCKS) { if (blockFace != ignoredFace) { Block nearbyBlock = plantBlock.getRelative(blockFace); if (PlantType.getByType(nearbyBlock.getType()) == PlantType.CHORUS_PLANT) { Optional nearbyResult = findChorusRoot(nearbyBlock, blockFace.getOppositeFace()); if (nearbyResult.isPresent()) return nearbyResult; } } } return Optional.empty(); } @Nullable private Key getMissionPlantKey(@Nullable Key blockKey) { if (blockKey == null) return null; for (KeyRequirements requirement : requiredPlants.keySet()) { if (requirement.contains(blockKey)) return requirement.getKey(blockKey); } return null; } } ================================================ FILE: Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantType.java ================================================ package com.bgsoftware.superiorskyblock.missions.farming; import com.bgsoftware.superiorskyblock.api.key.Key; import org.bukkit.Material; import java.util.EnumMap; public enum PlantType { BAMBOO(0, Plants.of("BAMBOO"), Plants.of("BAMBOO_SAPLING")), BEETROOT(3, Plants.of("BEETROOT", "BEETROOTS", "BEETROOT_SEEDS")), CACTUS(0, Plants.of("CACTUS")), CARROT(7, Plants.of("CARROT", "CARROTS")), CHORUS_PLANT(0, Plants.of("CHORUS_PLANT", "CHORUS_FLOWER")), COCOA(2, Plants.of("COCOA", "COCOA_BEANS")), MELON(-1, Plants.of("MELON", "MELON_BLOCK"), Plants.of("MELON_STEM")), NETHER_WART(3, Plants.of("NETHER_WART", "NETHER_STALK")), POTATO(7, Plants.of("POTATO", "POTATOES")), PUMPKIN(-1, Plants.of("PUMPKIN"), Plants.of("PUMPKIN_STEM")), SUGAR_CANE(0, Plants.of("SUGAR_CANE", "SUGAR_CANE_BLOCK")), SWEET_BERRY_BUSH(3, Plants.of("SWEET_BERRY_BUSH")), WHEAT(7, Plants.of("WHEAT", "CROPS", "WHEAT_SEEDS")), UNKNOWN(-1, Plants.EMPTY); private static final EnumMap MATERIALS_TO_PLANT_TYPE = new EnumMap<>(Material.class); private static final EnumMap SAPLING_MATERIALS_TO_PLANT_TYPE = new EnumMap<>(Material.class); private static boolean hasRegisteredPlantTypes = false; private final String[] plantTypes; private final String[] saplingTypes; private final int maxAge; private final Key cachedKey; PlantType(int maxAge, Plants plantTypes) { this(maxAge, plantTypes, plantTypes); } PlantType(int maxAge, Plants plantTypes, Plants saplingTypes) { this.maxAge = maxAge; this.plantTypes = plantTypes.arr; this.saplingTypes = saplingTypes.arr; this.cachedKey = Key.ofMaterialAndData(name()); } public int getMaxAge() { return maxAge; } public Key getCachedKey() { return cachedKey; } public static PlantType getByType(Material material) { registerPlantTypes(); return MATERIALS_TO_PLANT_TYPE.getOrDefault(material, UNKNOWN); } public static PlantType getBySaplingType(Material material) { registerPlantTypes(); return SAPLING_MATERIALS_TO_PLANT_TYPE.getOrDefault(material, UNKNOWN); } private static void registerPlantType(PlantType plantType) { for (String material : plantType.plantTypes) { try { MATERIALS_TO_PLANT_TYPE.put(Material.valueOf(material), plantType); } catch (IllegalArgumentException ignored) { } } for (String material : plantType.saplingTypes) { try { SAPLING_MATERIALS_TO_PLANT_TYPE.put(Material.valueOf(material), plantType); } catch (IllegalArgumentException ignored) { } } } private static void registerPlantTypes() { if (!hasRegisteredPlantTypes) { for (PlantType plantType : PlantType.values()) registerPlantType(plantType); hasRegisteredPlantTypes = true; } } private static class Plants { static Plants EMPTY = of(); private final String[] arr; static Plants of(String... arr) { return new Plants(arr); } Plants(String[] arr) { this.arr = arr; } } } ================================================ FILE: Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTracker.java ================================================ package com.bgsoftware.superiorskyblock.missions.farming; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.configuration.ConfigurationSection; import javax.annotation.Nullable; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; public class PlantsTracker { public static final PlantsTracker INSTANCE = new PlantsTracker(); private final Map plantsTracker = new HashMap<>(); private Map rawData = null; private Map>> legacyRawData = null; private boolean saved = false; private PlantsTracker() { } public void track(Block block, UUID placer) { track(block.getWorld(), block.getX(), block.getY(), block.getZ(), placer); } public void track(World world, int x, int y, int z, UUID placer) { loadRawData(world); plantsTracker.computeIfAbsent(world.getName(), s -> new PlantsTrackingComponent(world)) .track(x, y, z, placer); } public void untrack(Block block) { untrack(block.getWorld(), block.getX(), block.getY(), block.getZ()); } public void untrack(World world, int x, int y, int z) { loadRawData(world); PlantsTrackingComponent trackingComponent = this.plantsTracker.get(world.getName()); if (trackingComponent != null) trackingComponent.untrack(x, y, z); } @Nullable public UUID getPlacer(Location location) { World world = location.getWorld(); return world == null ? null : getPlacer(world, location.getBlockX(), location.getBlockY(), location.getBlockZ()); } @Nullable public UUID getPlacer(World world, int x, int y, int z) { loadRawData(world); PlantsTrackingComponent trackingComponent = this.plantsTracker.get(world.getName()); return trackingComponent == null ? null : trackingComponent.getPlacer(x, y, z); } public void load(String worldName, long chunkKey, List blocks, UUID placer) { if (this.rawData == null) this.rawData = new HashMap<>(); TrackedPlantsData trackedPlantsData = this.rawData.computeIfAbsent(worldName, w -> new TrackedPlantsData()); blocks.forEach(block -> trackedPlantsData.track(chunkKey, block, placer)); } public void loadLegacy(String worldName, BlockPosition plant, UUID placer) { if (this.legacyRawData == null) this.legacyRawData = new HashMap<>(); this.legacyRawData.computeIfAbsent(worldName, w -> new LinkedHashMap<>()) .computeIfAbsent(placer, i -> new LinkedList<>()).add(plant); } public void save(ConfigurationSection section) { if (!this.saved) { saveInternal(section); this.saved = true; } } private void saveInternal(ConfigurationSection section) { MutableBoolean savedData = new MutableBoolean(false); this.plantsTracker.forEach((worldName, component) -> { component.getPlants().forEach((chunkKey, blocks) -> { blocks.forEach((block, placer) -> { String path = "placed-plants." + placer + "." + worldName + "." + chunkKey; List blocksList = section.getIntegerList(path); blocksList.add(block); section.set(path, blocksList); savedData.set(true); }); }); }); if (this.rawData != null) { this.rawData.forEach((worldName, worldData) -> { worldData.getPlants().forEach((chunkKey, blocks) -> { blocks.forEach((block, placer) -> { String path = "placed-plants." + placer + "." + worldName + "." + chunkKey; List blocksList = section.getIntegerList(path); blocksList.add(block); section.set(path, blocksList); savedData.set(true); }); }); }); } if (this.legacyRawData != null) { this.legacyRawData.forEach((worldName, worldData) -> { worldData.forEach((placer, plants) -> { plants.forEach(plant -> { String plantKey = worldName + ";" + plant.getX() + ";" + plant.getY() + ";" + plant.getZ(); section.set("placed-plants-legacy." + plantKey, placer.toString()); savedData.set(true); }); }); }); } if (savedData.get()) { section.set("data-version", 1); } } private void loadRawData(World world) { String worldName = world.getName(); if (this.rawData != null) { TrackedPlantsData rawDataForWorld = this.rawData.remove(worldName); if (rawDataForWorld != null) { plantsTracker.put(worldName, new PlantsTrackingComponent(world, rawDataForWorld)); if (this.rawData.isEmpty()) this.rawData = null; } } if (this.legacyRawData != null) { Map> legacyRawDataForWorld = this.legacyRawData.remove(worldName); if (legacyRawDataForWorld != null) { PlantsTrackingComponent plantsTrackingComponent = new PlantsTrackingComponent(world); legacyRawDataForWorld.forEach((placer, plants) -> { plants.forEach(plant -> plantsTrackingComponent.track(plant.getX(), plant.getY(), plant.getZ(), placer)); }); this.plantsTracker.put(worldName, plantsTrackingComponent); if (this.legacyRawData.isEmpty()) this.legacyRawData = null; } } } } ================================================ FILE: Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTrackingComponent.java ================================================ package com.bgsoftware.superiorskyblock.missions.farming; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectMethod; import org.bukkit.World; import javax.annotation.Nullable; import java.util.Map; import java.util.UUID; public class PlantsTrackingComponent { private static final ReflectMethod WORLD_GET_MIN_HEIGHT = new ReflectMethod<>( new ClassInfo("CraftWorld", ClassInfo.PackageType.CRAFTBUKKIT), "getMinHeight", new ClassInfo[0]); private final TrackedPlantsData trackedPlantsData; private final int worldMinHeight; public PlantsTrackingComponent(World world) { this(world, new TrackedPlantsData()); } public PlantsTrackingComponent(World world, TrackedPlantsData trackedPlantsData) { this.worldMinHeight = WORLD_GET_MIN_HEIGHT.isValid() ? WORLD_GET_MIN_HEIGHT.invoke(world) : 0; this.trackedPlantsData = trackedPlantsData; } public void track(int x, int y, int z, UUID placer) { int block = getBlockIndex(x, y, z); trackedPlantsData.track(getChunkKey(x, z), block, placer); } public void untrack(int x, int y, int z) { int block = getBlockIndex(x, y, z); trackedPlantsData.untrack(getChunkKey(x, z), block); } @Nullable public UUID getPlacer(int x, int y, int z) { int block = getBlockIndex(x, y, z); return trackedPlantsData.getPlacer(getChunkKey(x, z), block); } public Map> getPlants() { return this.trackedPlantsData.getPlants(); } private int getBlockIndex(int blockX, int blockY, int blockZ) { int chunkMinX = blockX >> 4 << 4; int chunkMinZ = blockZ >> 4 << 4; byte relativeX = (byte) (blockX - chunkMinX); short relativeY = (short) (blockY - this.worldMinHeight); byte relativeZ = (byte) (blockZ - chunkMinZ); return (relativeY << 8) | (relativeX << 4) | relativeZ; } private static long getChunkKey(int blockX, int blockZ) { int chunkX = blockX >> 4; int chunkZ = blockZ >> 4; return (long) chunkX << 32 | chunkZ; } } ================================================ FILE: Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/TrackedPlantsData.java ================================================ package com.bgsoftware.superiorskyblock.missions.farming; import java.util.HashMap; import java.util.Map; import java.util.UUID; public class TrackedPlantsData { private final Map> trackedData = new HashMap<>(); public void track(long chunkKey, int block, UUID placer) { trackedData.computeIfAbsent(chunkKey, i -> new HashMap<>()).put(block, placer); } public void untrack(long chunkKey, int block) { Map chunkTrackedData = this.trackedData.get(chunkKey); if (chunkTrackedData != null) chunkTrackedData.remove(block); } public UUID getPlacer(long chunkKey, int block) { Map chunkTrackedData = this.trackedData.get(chunkKey); return chunkTrackedData == null ? null : chunkTrackedData.get(block); } public Map> getPlants() { return trackedData; } } ================================================ FILE: Missions/FishingMissions/build.gradle ================================================ group 'Missions:FishingMissions' dependencies { compileOnly "org.spigotmc:v1_16_R3:latest" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.fishing' } ================================================ FILE: Missions/FishingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FishingMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.Placeholders; import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; import com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Item; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerFishEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.UUID; public final class FishingMissions extends BuiltinMission implements Listener { private final Map itemsToCatch = new LinkedHashMap<>(); @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { ConfigurationSection requiredCaughtsSection = section.getConfigurationSection("required-caughts"); if (requiredCaughtsSection == null) throw new MissionLoadException("You must have the \"required-caughts\" section in the config."); for (String key : requiredCaughtsSection.getKeys(false)) { KeySet blocks = KeySet.createKeySet(); section.getStringList("required-caughts." + key + ".types").forEach(requiredBlock -> blocks.add(Key.ofMaterialAndData(requiredBlock.toUpperCase(Locale.ENGLISH)))); int amount = section.getInt("required-caughts." + key + ".amount", 1); this.itemsToCatch.put(new KeyRequirements(blocks), amount); } } @Override protected void registerListeners() { registerListener(this); } @Override protected void clearModuleData(KeyDataTracker data) { data.clear(); } @Override public double getProgress(SuperiorPlayer superiorPlayer) { KeyDataTracker fishingTracker = get(superiorPlayer); if (fishingTracker == null) return 0.0; int requiredItems = 0; int interactions = 0; for (Map.Entry entry : this.itemsToCatch.entrySet()) { requiredItems += entry.getValue(); interactions += Math.min(fishingTracker.getCounts(entry.getKey()), entry.getValue()); } return (double) interactions / requiredItems; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { KeyDataTracker fishingTracker = get(superiorPlayer); if (fishingTracker == null) return 0; int interactions = 0; for (Map.Entry entry : this.itemsToCatch.entrySet()) interactions += Math.min(fishingTracker.getCounts(entry.getKey()), entry.getValue()); return interactions; } @Override public void saveProgress(ConfigurationSection section) { for (Map.Entry entry : entrySet()) { String uuid = entry.getKey().getUniqueId().toString(); int index = 0; for (Map.Entry craftedEntry : entry.getValue().getCounts().entrySet()) { section.set(uuid + "." + index + ".item", craftedEntry.getKey().toString()); section.set(uuid + "." + index + ".amount", craftedEntry.getValue().get()); index++; } } } @Override public void loadProgress(ConfigurationSection section) { for (String uuid : section.getKeys(false)) { if (uuid.equals("players")) continue; KeyDataTracker fishingTracker = new KeyDataTracker(); UUID playerUUID = UUID.fromString(uuid); SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); insertData(superiorPlayer, fishingTracker); for (String key : section.getConfigurationSection(uuid).getKeys(false)) { Key typeKey; if (section.isItemStack(uuid + "." + key + ".item")) { ItemStack itemStack = section.getItemStack(uuid + "." + key + ".item"); typeKey = itemStack == null ? null : Key.of(itemStack); } else { typeKey = Key.ofMaterialAndData(section.getString(uuid + "." + key + ".item")); } if (typeKey != null) { typeKey = getMissionItemKey(typeKey); int amount = section.getInt(uuid + "." + key + ".amount"); fishingTracker.load(typeKey, amount); } } } } @Override public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { KeyDataTracker fishingTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); if (fishingTracker == null) return; ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta == null) return; if (itemMeta.hasDisplayName()) itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.itemsToCatch, fishingTracker, itemMeta.getDisplayName(), true)); if (itemMeta.hasLore()) { List lore = new ArrayList<>(); for (String line : Objects.requireNonNull(itemMeta.getLore())) lore.add(Placeholders.parseKeyPlaceholders(this.itemsToCatch, fishingTracker, line, true)); itemMeta.setLore(lore); } itemStack.setItemMeta(itemMeta); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerFish(PlayerFishEvent e) { if (!(e.getCaught() instanceof Item) || e.getState() != PlayerFishEvent.State.CAUGHT_FISH) return; SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) return; Item caughtItem = (Item) e.getCaught(); ItemStack caughtItemStack = caughtItem.getItemStack(); Key itemKey = getMissionItemKey(Key.of(caughtItemStack)); if (itemKey == null) return; trackItem(superiorPlayer, itemKey, caughtItemStack.getAmount()); } private void trackItem(SuperiorPlayer superiorPlayer, Key itemKey, int count) { KeyDataTracker blocksTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); if (blocksTracker == null) return; blocksTracker.track(itemKey, count); Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(player -> { if (canComplete(superiorPlayer)) this.plugin.getMissions().rewardMission(this, superiorPlayer, true); }), 2L); } @Nullable private Key getMissionItemKey(Key blockKey) { for (KeyRequirements requirementsList : itemsToCatch.keySet()) { if (requirementsList.contains(blockKey)) return requirementsList.getKey(blockKey); } return null; } } ================================================ FILE: Missions/IslandMissions/build.gradle ================================================ group 'Missions:IslandMissions' dependencies { compileOnly "org.spigotmc:v1_8_R3-Taco:latest" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.island' } ================================================ FILE: Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/IslandMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.events.IslandEvent; import com.bgsoftware.superiorskyblock.api.events.IslandTransferEvent; import com.bgsoftware.superiorskyblock.api.events.MissionCompleteEvent; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.island.DynamicRegisteredListener; import com.bgsoftware.superiorskyblock.missions.island.EventsHelper; import com.bgsoftware.superiorskyblock.missions.island.timings.ITimings; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.Event; import org.bukkit.event.EventException; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredServiceProvider; import javax.annotation.Nullable; import javax.script.SimpleBindings; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public final class IslandMissions extends BuiltinMission implements Listener { private String successCheck; private PlaceholdersService placeholdersService; @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { if (!section.contains("events")) throw new MissionLoadException("You must have the \"events\" section in the config."); for (String event : section.getStringList("events")) { boolean targetPlayer = false; String eventName = event; if (event.toLowerCase().endsWith("-target")) { targetPlayer = true; eventName = event.split("-")[0]; } try { registerEventListener(plugin, eventName, targetPlayer); } catch (ClassNotFoundException error) { plugin.getLogger().warning("The event " + eventName + " is not valid, skipping"); } catch (Exception error) { plugin.getLogger().warning("Cannot register IslandMission for " + eventName + ":"); error.printStackTrace(); } } this.successCheck = section.getString("success-check", "true"); RegisteredServiceProvider registeredServiceProvider = plugin.getServer() .getServicesManager().getRegistration(PlaceholdersService.class); if (registeredServiceProvider != null) { this.placeholdersService = registeredServiceProvider.getProvider(); } } @Override protected void registerListeners() { registerListener(this); } @Override protected void clearModuleData(Boolean data) { // Do nothing } @Override public double getProgress(SuperiorPlayer superiorPlayer) { return get(superiorPlayer) == null ? 0.0 : 1.0; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { return 0; } private void registerEventListener(Plugin plugin, String eventName, boolean isTarget) throws Exception { Class eventClass = Class.forName("com.bgsoftware.superiorskyblock.api.events." + eventName); if (!Event.class.isAssignableFrom(eventClass)) return; HandlerList handlerList = EventsHelper.getEventListeners(eventClass.asSubclass(Event.class)); ITimings timings = ITimings.of(plugin, "Plugin: " + plugin.getDescription().getFullName() + " Event: DynamicRegisteredListener::" + eventName + "(" + eventClass.getSimpleName() + ")"); Method getPlayerMethod = getMethodSilently(eventClass, "getPlayer"); Method getTargetMethod = getMethodSilently(eventClass, "getTarget"); handlerList.register(new DynamicRegisteredListener(plugin, (listener, event) -> { try { if (eventClass.isAssignableFrom(event.getClass()) && (event instanceof IslandEvent || event instanceof MissionCompleteEvent)) { boolean isAsync = event.isAsynchronous(); if (!isAsync) { timings.startTiming(); } SuperiorPlayer superiorPlayer; SuperiorPlayer targetPlayer; if (event instanceof IslandTransferEvent) { superiorPlayer = ((IslandTransferEvent) event).getOldOwner(); targetPlayer = ((IslandTransferEvent) event).getNewOwner(); } else { superiorPlayer = getPlayerMethod != null ? (SuperiorPlayer) getPlayerMethod.invoke(event) : event instanceof IslandEvent ? ((IslandEvent) event).getIsland().getOwner() : null; targetPlayer = getTargetMethod == null ? null : (SuperiorPlayer) getTargetMethod.invoke(event); } tryComplete(event, superiorPlayer, targetPlayer, isTarget); if (!isAsync) { timings.stopTiming(); } } } catch (InvocationTargetException var4) { throw new EventException(var4.getCause()); } catch (Throwable var5) { throw new EventException(var5); } })); } private void tryComplete(Event event, @Nullable SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer targetPlayer, boolean isTarget) { boolean success = false; SimpleBindings bindings = new SimpleBindings(); bindings.put("event", event); IScriptEngine scriptEngine = this.plugin.getScriptEngine(); try { String result = scriptEngine.eval(successCheck, bindings) + ""; if (this.placeholdersService != null && superiorPlayer != null) { result = placeholdersService.parsePlaceholders(superiorPlayer.asOfflinePlayer(), result); } success = Boolean.parseBoolean(result); } catch (Throwable error) { plugin.getLogger().warning("Error occurred while checking for success condition for IslandMission."); plugin.getLogger().warning("Current Script Engine: " + scriptEngine); error.printStackTrace(); } if (success) { SuperiorPlayer rewardedPlayer = isTarget ? targetPlayer : superiorPlayer; if (rewardedPlayer != null) { Bukkit.getScheduler().runTaskLater(plugin, () -> { insertData(rewardedPlayer, true); this.plugin.getMissions().rewardMission(this, rewardedPlayer, true); }, 5L); } } } private static Method getMethodSilently(Class clazz, String methodName) { try { return clazz.getDeclaredMethod(methodName); } catch (Exception error) { return null; } } } ================================================ FILE: Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/DynamicRegisteredListener.java ================================================ package com.bgsoftware.superiorskyblock.missions.island; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.plugin.EventExecutor; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.TimedRegisteredListener; public class DynamicRegisteredListener extends TimedRegisteredListener { private static final Listener EMPTY_LISTENER = new Listener() { }; public DynamicRegisteredListener(Plugin plugin, EventExecutor executor) { super(EMPTY_LISTENER, executor, EventPriority.MONITOR, plugin, true); } } ================================================ FILE: Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/EventsHelper.java ================================================ package com.bgsoftware.superiorskyblock.missions.island; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.plugin.IllegalPluginAccessException; import java.lang.reflect.Method; public class EventsHelper { private EventsHelper() { } public static HandlerList getEventListeners(Class type) { try { Method method = getRegistrationClass(type).getDeclaredMethod("getHandlerList"); method.setAccessible(true); return (HandlerList) method.invoke(null); } catch (Exception var3) { throw new IllegalPluginAccessException(var3.toString()); } } private static Class getRegistrationClass(Class clazz) { try { clazz.getDeclaredMethod("getHandlerList"); return clazz; } catch (NoSuchMethodException var3) { if (clazz.getSuperclass() != null && !clazz.getSuperclass().equals(Event.class) && Event.class.isAssignableFrom(clazz.getSuperclass())) { return getRegistrationClass(clazz.getSuperclass().asSubclass(Event.class)); } else { throw new IllegalPluginAccessException("Unable to find handler list for event " + clazz.getName() + ". Static getHandlerList method required!"); } } } } ================================================ FILE: Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/DummyTimings.java ================================================ package com.bgsoftware.superiorskyblock.missions.island.timings; public class DummyTimings implements ITimings { public static final DummyTimings INSTANCE = new DummyTimings(); private DummyTimings() { } @Override public void startTiming() { // Do nothing. } @Override public void stopTiming() { // Do nothing. } } ================================================ FILE: Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/ITimings.java ================================================ package com.bgsoftware.superiorskyblock.missions.island.timings; import org.bukkit.plugin.Plugin; public interface ITimings { void startTiming(); void stopTiming(); static ITimings of(Plugin plugin, String name) { try { return TimingsWrapper.create(plugin, name); } catch (Throwable error) { try { return LegacyTimingsWrapper.create(name); } catch (Throwable error2) { return DummyTimings.INSTANCE; } } } } ================================================ FILE: Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/LegacyTimingsWrapper.java ================================================ package com.bgsoftware.superiorskyblock.missions.island.timings; import org.spigotmc.CustomTimingsHandler; public class LegacyTimingsWrapper implements ITimings { private final CustomTimingsHandler handle; public static ITimings create(String name) { return new LegacyTimingsWrapper(name); } private LegacyTimingsWrapper(String name) { this.handle = new CustomTimingsHandler(name); } @Override public void startTiming() { this.handle.startTiming(); } @Override public void stopTiming() { this.handle.stopTiming(); } } ================================================ FILE: Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/TimingsWrapper.java ================================================ package com.bgsoftware.superiorskyblock.missions.island.timings; import co.aikar.timings.Timing; import co.aikar.timings.Timings; import co.aikar.timings.TimingsManager; import com.bgsoftware.common.reflection.ReflectMethod; import org.bukkit.plugin.Plugin; import javax.annotation.Nullable; public class TimingsWrapper implements ITimings { private static final ReflectMethod START_TIMING = new ReflectMethod<>(Timing.class, "startTiming"); @Nullable private final Timing handle; public static ITimings create(Plugin plugin, String name) { return Timings.isTimingsEnabled() ? new TimingsWrapper(plugin, name) : DummyTimings.INSTANCE; } private static final ReflectMethod TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT = new ReflectMethod<>( TimingsManager.class, "getHandler", String.class, String.class, Timing.class, boolean.class); private static final ReflectMethod TIMINGS_MANAGER_GET_HANDLER = new ReflectMethod<>( TimingsManager.class, "getHandler", String.class, String.class, Timing.class); private TimingsWrapper(Plugin plugin, String name) { String pluginName = plugin.getName(); if (TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.isValid()) { Timing pluginHandler = TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.invoke(null, pluginName, "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER, false); this.handle = TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.invoke(null, pluginName, name, pluginHandler, true); } else if (TIMINGS_MANAGER_GET_HANDLER.isValid()) { Timing pluginHandler = TIMINGS_MANAGER_GET_HANDLER.invoke(null, pluginName, "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER); this.handle = TIMINGS_MANAGER_GET_HANDLER.invoke(null, pluginName, name, pluginHandler); } else { this.handle = null; } } @Override public void startTiming() { if (this.handle != null) { try { this.handle.startTiming(); } catch (Throwable error) { START_TIMING.invoke(this.handle); } } } @Override public void stopTiming() { if (this.handle != null) this.handle.stopTiming(); } } ================================================ FILE: Missions/ItemsMissions/build.gradle ================================================ group 'Missions:ItemsMissions' dependencies { compileOnly "org.spigotmc:v1_8_R3-Taco:latest" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.items' } ================================================ FILE: Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import javax.annotation.Nullable; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; @SuppressWarnings("unused") public final class ItemsMissions extends BuiltinMission implements Listener { private static final int ADDITIONAL_SLOT_START = 36; // Boots private static final int ADDITIONAL_SLOT_END = 40; // Off hand private final Map requiredItems = new LinkedHashMap<>(); @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { ConfigurationSection requiredItemsSection = section.getConfigurationSection("required-items"); if (requiredItemsSection == null) throw new MissionLoadException("You must have the \"required-items\" section in the config."); for (String key : requiredItemsSection.getKeys(false)) { KeySet itemStacks = KeySet.createKeySet(); section.getStringList("required-items." + key + ".types").forEach(itemStackName -> itemStacks.add(Key.ofMaterialAndData(itemStackName.toUpperCase(Locale.ENGLISH)))); int requiredAmount = section.getInt("required-items." + key + ".amount"); requiredItems.put(new KeyRequirements(itemStacks), requiredAmount); } } @Override protected void registerListeners() { registerListener(this); } @Override protected void clearModuleData(ItemsTracker data) { data.itemsTracker.clear(); } @Override public double getProgress(SuperiorPlayer superiorPlayer) { double progress = 0.0; Player player = superiorPlayer.asPlayer(); if (player == null) return progress; Inventory inventory = player.getInventory(); Map countedItems = countItems(inventory); int totalRequiredAmount = 0; int totalItemAmount = 0; ItemsTracker itemsTracker = getOrCreate(superiorPlayer, s -> new ItemsTracker()); if (itemsTracker == null) return 0.0; for (Map.Entry entry : requiredItems.entrySet()) { KeyRequirements requirement = entry.getKey(); int requiredAmount = entry.getValue(); int itemAmount = 0; for (Key item : requirement) { try { //Get the amount of the item. Material type = Material.valueOf(item.getGlobalKey()); short data = item.getSubKey().isEmpty() ? 0 : Short.parseShort(item.getSubKey()); int currentItemAmount = countedItems.get(new ItemStack(type, 1, data)); //Making sure to not exceed the required item amount if (itemAmount + currentItemAmount > requiredAmount) currentItemAmount = requiredAmount - itemAmount; //Summing the amount to a global variable itemAmount += currentItemAmount; //Adding the item to a list, so we can remove it later. itemsTracker.track(new ItemStack(type, currentItemAmount, data)); } catch (Exception ignored) { } } totalRequiredAmount += requiredAmount; totalItemAmount += itemAmount; } progress = Math.max(progress, (double) totalItemAmount / totalRequiredAmount); return progress; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { Player player = superiorPlayer.asPlayer(); if (player == null) return 0; Inventory inventory = player.getInventory(); Map countedItems = countItems(inventory); int totalItemAmount = 0; ItemsTracker itemsTracker = getOrCreate(superiorPlayer, s -> new ItemsTracker()); if (itemsTracker == null) return 0; for (Map.Entry entry : requiredItems.entrySet()) { KeyRequirements requirement = entry.getKey(); int requiredAmount = entry.getValue(); int itemAmount = 0; for (Key item : requirement) { try { //Get the amount of the item. Material type = Material.valueOf(item.getGlobalKey()); short data = item.getSubKey().isEmpty() ? 0 : Short.parseShort(item.getSubKey()); int currentItemAmount = countedItems.get(new ItemStack(type, 1, data)); //Making sure to not exceed the required item amount if (itemAmount + currentItemAmount > requiredAmount) currentItemAmount = requiredAmount - itemAmount; //Summing the amount to a global variable itemAmount += currentItemAmount; //Adding the item to a list, so we can remove it later. itemsTracker.track(new ItemStack(type, currentItemAmount, data)); } catch (Exception ignored) { } } totalItemAmount += itemAmount; } return totalItemAmount; } @Override public void onComplete(SuperiorPlayer superiorPlayer) { getProgress(superiorPlayer); ItemsTracker itemsTracker = get(superiorPlayer); if (itemsTracker == null) return; Player player = superiorPlayer.asPlayer(); assert player != null; removeItems(player.getInventory(), itemsTracker.getItems().toArray(new ItemStack[0])); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onItemPickup(PlayerPickupItemEvent e) { ItemStack itemStack = e.getItem().getItemStack(); handleItemPickup(e.getPlayer(), e.getItem().getItemStack()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onInventoryClick(InventoryClickEvent e) { if (!(e.getWhoClicked() instanceof Player) || e.getClickedInventory() == null || e.getClickedInventory().getType() != InventoryType.CHEST || e.getClick() != ClickType.SHIFT_LEFT) return; handleItemPickup((Player) e.getWhoClicked(), e.getCurrentItem()); } private void handleItemPickup(Player player, @Nullable ItemStack itemStack) { if (!isMissionItem(itemStack)) return; SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player); if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) return; Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(unused -> { if (canComplete(superiorPlayer)) this.plugin.getMissions().rewardMission(this, superiorPlayer, true); }), 2L); } private boolean isMissionItem(@Nullable ItemStack itemStack) { if (itemStack == null) return false; for (KeyRequirements requirement : requiredItems.keySet()) { if (requirement.contains(Key.of(itemStack))) return true; } return false; } private static Map countItems(Inventory inventory) { Map countedItems = new HashMap<>(); Arrays.stream(inventory.getContents()).filter(Objects::nonNull).forEach(itemStack -> { ItemStack key = itemStack.clone(); key.setAmount(1); countedItems.put(key, countedItems.getOrDefault(key, 0) + itemStack.getAmount()); }); return countedItems; } private static void removeItems(PlayerInventory inventory, ItemStack... itemStacks) { Collection leftOvers = inventory.removeItem(itemStacks).values(); if (leftOvers.isEmpty()) return; // We try to remove the item from the offhand as well. for (int additionalSlot = ADDITIONAL_SLOT_START; additionalSlot < ADDITIONAL_SLOT_END; ++additionalSlot) { ItemStack additionalItem; try { additionalItem = inventory.getItem(additionalSlot); } catch (Exception ignored) { continue; } if (additionalItem != null && additionalItem.getType() != Material.AIR) { for (ItemStack itemStack : leftOvers) { if (additionalItem.isSimilar(itemStack)) { if (additionalItem.getAmount() > itemStack.getAmount()) { additionalItem.setAmount(additionalItem.getAmount() - itemStack.getAmount()); } else { itemStack.setAmount(itemStack.getAmount() - additionalItem.getAmount()); inventory.setItem(additionalSlot, new ItemStack(Material.AIR)); } } } } } } public static class ItemsTracker { private final Set itemsTracker = new HashSet<>(); void track(ItemStack itemStack) { itemsTracker.add(itemStack.clone()); } Set getItems() { return itemsTracker; } } } ================================================ FILE: Missions/KillsMissions/build.gradle ================================================ group 'Missions:KillsMissions' dependencies { compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly 'com.bgsoftware:WildStackerAPI:3.6.3' } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.kills' } ================================================ FILE: Missions/KillsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/KillsMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.Placeholders; import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; import com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker; import com.bgsoftware.wildstacker.api.WildStackerAPI; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.projectiles.ProjectileSource; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.function.Function; public final class KillsMissions extends BuiltinMission implements Listener { private final Map requiredEntities = new LinkedHashMap<>(); private Function getEntityCount; @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { ConfigurationSection requiredEntitiesSection = section.getConfigurationSection("required-entities"); if (requiredEntitiesSection == null) throw new MissionLoadException("You must have the \"required-entities\" section in the config."); for (String key : requiredEntitiesSection.getKeys(false)) { KeySet entityTypes = KeySet.createKeySet(); section.getStringList("required-entities." + key + ".types").forEach(entityTypeName -> entityTypes.add(Key.ofEntityType(entityTypeName.toUpperCase(Locale.ENGLISH)))); int requiredAmount = section.getInt("required-entities." + key + ".amount"); requiredEntities.put(new KeyRequirements(entityTypes), requiredAmount); } } @Override protected void registerListeners() { registerListener(this); plugin.getServer().getScheduler().runTaskLater(plugin, () -> { if (plugin.getServer().getPluginManager().isPluginEnabled("WildStacker")) { this.getEntityCount = WildStackerAPI::getEntityAmount; } else { this.getEntityCount = entity -> 1; } }, 1L); } @Override protected void clearModuleData(KeyDataTracker data) { data.clear(); } @Override public double getProgress(SuperiorPlayer superiorPlayer) { KeyDataTracker killsTracker = get(superiorPlayer); if (killsTracker == null) return 0.0; int requiredEntities = 0; int kills = 0; for (Map.Entry requiredEntity : this.requiredEntities.entrySet()) { requiredEntities += requiredEntity.getValue(); kills += Math.min(killsTracker.getCounts(requiredEntity.getKey()), requiredEntity.getValue()); } return (double) kills / requiredEntities; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { KeyDataTracker killsTracker = get(superiorPlayer); if (killsTracker == null) return 0; int kills = 0; for (Map.Entry requiredEntity : this.requiredEntities.entrySet()) kills += Math.min(killsTracker.getCounts(requiredEntity.getKey()), requiredEntity.getValue()); return kills; } @Override public void saveProgress(ConfigurationSection section) { for (Map.Entry entry : entrySet()) { String uuid = entry.getKey().getUniqueId().toString(); entry.getValue().getCounts().forEach((killedType, count) -> section.set(uuid + "." + killedType, count.get())); } } @Override public void loadProgress(ConfigurationSection section) { for (String uuid : section.getKeys(false)) { KeyDataTracker killsTracker = new KeyDataTracker(); UUID playerUUID = UUID.fromString(uuid); SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); insertData(superiorPlayer, killsTracker); for (String key : section.getConfigurationSection(uuid).getKeys(false)) { killsTracker.load(Key.ofEntityType(key), section.getInt(uuid + "." + key)); } } } @Override public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { KeyDataTracker killsTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); if (killsTracker == null) return; ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta == null) return; if (itemMeta.hasDisplayName()) itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredEntities, killsTracker, itemMeta.getDisplayName(), false)); if (itemMeta.hasLore()) { List lore = new ArrayList<>(); for (String line : Objects.requireNonNull(itemMeta.getLore())) lore.add(Placeholders.parseKeyPlaceholders(this.requiredEntities, killsTracker, line, false)); itemMeta.setLore(lore); } itemStack.setItemMeta(itemMeta); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityKill(EntityDeathEvent e) { if (!isMissionEntity(e.getEntity())) return; EntityDamageEvent damageCause = e.getEntity().getLastDamageCause(); if (!(damageCause instanceof EntityDamageByEntityEvent)) return; EntityDamageByEntityEvent entityDamageByEntityEvent = (EntityDamageByEntityEvent) damageCause; Player damager = null; if (entityDamageByEntityEvent.getDamager() instanceof Player) { damager = (Player) entityDamageByEntityEvent.getDamager(); } else if (entityDamageByEntityEvent.getDamager() instanceof Projectile) { ProjectileSource shooter = ((Projectile) entityDamageByEntityEvent.getDamager()).getShooter(); if (shooter instanceof Player) damager = (Player) shooter; } if (damager == null) return; SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(damager); if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) return; KeyDataTracker killsTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); if (killsTracker == null) return; killsTracker.track(Key.of(e.getEntity()), this.getEntityCount.apply(e.getEntity())); Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(player -> { if (canComplete(superiorPlayer)) this.plugin.getMissions().rewardMission(this, superiorPlayer, true); }), 2L); } private boolean isMissionEntity(@Nullable Entity entity) { if (entity == null || entity instanceof ArmorStand) return false; Key entityKey = Key.of(entity); for (KeyRequirements requirement : requiredEntities.keySet()) { if (requirement.contains(entityKey)) return true; } return false; } } ================================================ FILE: Missions/StatisticsMissions/build.gradle ================================================ group 'Missions:StatisticsMissions' dependencies { compileOnly "org.spigotmc:v1_8_R3-Taco:latest" } shadowJar { relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.statistics' } ================================================ FILE: Missions/StatisticsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/StatisticsMissions.java ================================================ package com.bgsoftware.superiorskyblock.missions; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; import com.bgsoftware.superiorskyblock.missions.common.Placeholders; import com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerStatisticIncrementEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.OptionalInt; public final class StatisticsMissions extends BuiltinMission implements Listener { private final Map requiredStatistics = new LinkedHashMap<>(); @Override protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { ConfigurationSection requiredStatisticsSection = section.getConfigurationSection("required-statistics"); if (requiredStatisticsSection == null) throw new MissionLoadException("You must have the \"required-blocks\" section in the config."); for (String key : requiredStatisticsSection.getKeys(false)) { List statistics = section.getStringList("required-statistics." + key + ".statistics"); int requiredAmount = section.getInt("required-statistics." + key + ".amount"); requiredStatistics.put(new Requirements(statistics), requiredAmount); } } @Override protected void registerListeners() { registerListener(this); } @Override protected void clearModuleData(Void data) { // Do nothing } @Override public double getProgress(SuperiorPlayer superiorPlayer) { double progress = 0.0; int totalRequiredAmount = 0; int totalItemAmount = 0; Player player = superiorPlayer.asPlayer(); if (player == null) return progress; for (Map.Entry entry : this.requiredStatistics.entrySet()) { Requirements requirement = entry.getKey(); int requiredAmount = entry.getValue(); int statisticAmount = 0; for (String statistic : requirement) { OptionalInt currentStatisticAmountOptional = getStatisticAmount(player, statistic); if (!currentStatisticAmountOptional.isPresent()) continue; int currentStatisticAmount = currentStatisticAmountOptional.getAsInt(); //Making sure to not exceed the required item amount if (statisticAmount + currentStatisticAmount > requiredAmount) currentStatisticAmount = requiredAmount - statisticAmount; //Summing the amount to a global variable statisticAmount += currentStatisticAmount; } totalRequiredAmount += requiredAmount; totalItemAmount += statisticAmount; } progress = Math.max(progress, (double) totalItemAmount / totalRequiredAmount); return progress; } @Override public int getProgressValue(SuperiorPlayer superiorPlayer) { int totalItemAmount = 0; Player player = superiorPlayer.asPlayer(); if (player == null) return totalItemAmount; for (Map.Entry entry : this.requiredStatistics.entrySet()) { Requirements requirement = entry.getKey(); int requiredAmount = entry.getValue(); int statisticAmount = 0; for (String statistic : requirement) { OptionalInt currentItemAmountOptional = getStatisticAmount(player, statistic); if (!currentItemAmountOptional.isPresent()) continue; int currentItemAmount = currentItemAmountOptional.getAsInt(); //Making sure to not exceed the required item amount if (statisticAmount + currentItemAmount > requiredAmount) currentItemAmount = requiredAmount - statisticAmount; //Summing the amount to a global variable statisticAmount += currentItemAmount; } totalItemAmount += statisticAmount; } return totalItemAmount; } @Override public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { Player player = superiorPlayer.asPlayer(); if (player == null) return; ItemMeta itemMeta = itemStack.getItemMeta(); if (itemMeta == null) return; Placeholders.PlaceholdersFunctions placeholdersFunctions = new Placeholders.PlaceholdersFunctions() { @Override public Requirements getRequirementFromKey(String key) { for (Requirements requirements : requiredStatistics.keySet()) { if (requirements.contains(key)) return requirements; } return null; } @Override public Optional lookupRequirement(Requirements requirement) { return Optional.ofNullable(requiredStatistics.get(requirement)); } @Override public int getCountForRequirement(Requirements requirement) { int statisticAmount = 0; for (String statistic : requirement) { OptionalInt currentItemAmountOptional = getStatisticAmount(player, statistic); if (currentItemAmountOptional.isPresent()) statisticAmount += currentItemAmountOptional.getAsInt(); } return statisticAmount; } }; if (itemMeta.hasDisplayName()) itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions)); if (itemMeta.hasLore()) { List lore = new ArrayList<>(); for (String line : Objects.requireNonNull(itemMeta.getLore())) lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions)); itemMeta.setLore(lore); } itemStack.setItemMeta(itemMeta); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerStatistic(PlayerStatisticIncrementEvent e) { SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); if (!isMissionStatistic(e.getStatistic()) || !this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) return; Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(player -> { if (canComplete(superiorPlayer)) this.plugin.getMissions().rewardMission(this, superiorPlayer, true); }), 2L); } private boolean isMissionStatistic(@Nullable Statistic statistic) { if (statistic == null) return false; for (Requirements requirement : requiredStatistics.keySet()) { if (requirement.contains(statistic.name()) || (statistic.isSubstatistic() && requirement.stream().anyMatch(line -> line.contains(statistic.name())))) return true; } return false; } private static OptionalInt getStatisticAmount(Player player, String statisticsString) { String[] sections = statisticsString.split(":"); OptionalInt currentStatisticAmount = OptionalInt.empty(); try { Statistic statistic = Statistic.valueOf(sections[0]); if (sections.length == 1) { currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic)); } else if (sections.length == 2) { Material material = getEnumSafe(Material.class, sections[1]); if (material != null) { currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic, material)); } else { EntityType entityType = getEnumSafe(EntityType.class, sections[1]); if (entityType != null) currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic, entityType)); } } } catch (Exception ignored) { } return currentStatisticAmount; } private static > T getEnumSafe(Class clazz, String name) { try { return Enum.valueOf(clazz, name); } catch (Throwable ex) { return null; } } } ================================================ FILE: Missions/build.gradle ================================================ group 'Missions' subprojects { dependencies { implementation project(":Missions") compileOnly project(":API") compileOnly project(":") } } dependencies { compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") compileOnly project(":") } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/BuiltinMission.java ================================================ package com.bgsoftware.superiorskyblock.missions.common; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import java.util.LinkedList; import java.util.List; public abstract class BuiltinMission extends Mission { private final List registeredListeners = new LinkedList<>(); protected SuperiorSkyblock plugin; @Override public final void load(JavaPlugin plugin, ConfigurationSection section) throws MissionLoadException { this.plugin = (SuperiorSkyblock) plugin; loadConfiguration(section); registerListeners(); setClearMethod(this::clearModuleData); } protected abstract void loadConfiguration(ConfigurationSection section) throws MissionLoadException; protected abstract void registerListeners(); protected abstract void clearModuleData(V data); protected final void registerListener(Listener listener) { Bukkit.getPluginManager().registerEvents(listener, plugin); this.registeredListeners.add(listener); } @Override public void onComplete(SuperiorPlayer superiorPlayer) { } @Override public void onCompleteFail(SuperiorPlayer superiorPlayer) { } public final void unload() { this.registeredListeners.forEach(HandlerList::unregisterAll); this.registeredListeners.clear(); } } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/Placeholders.java ================================================ package com.bgsoftware.superiorskyblock.missions.common; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; import com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements; import com.bgsoftware.superiorskyblock.missions.common.tracker.DataTracker; import org.bukkit.ChatColor; import javax.annotation.Nullable; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Placeholders { private static final Pattern PERCENTAGE_PATTERN = Pattern.compile("\\{percentage_(.+?)}"); private static final Pattern VALUES_PATTERN = Pattern.compile("\\{value_(.+?)}"); private static final Function MATERIAL_KEY_CREATION = Key::ofMaterialAndData; private static final Function ENTITY_KEY_CREATION = Key::ofEntityType; private Placeholders() { } public static String parseKeyPlaceholders(Map requirements, DataTracker dataTracker, String line, boolean isMaterial) { Function creationMethod; if (isMaterial) { creationMethod = MATERIAL_KEY_CREATION; } else { creationMethod = ENTITY_KEY_CREATION; } return parsePlaceholders(line, new PlaceholdersFunctions() { @Override public KeyRequirements getRequirementFromKey(String key) { Key requirementKey = creationMethod.apply(key); for (KeyRequirements requirements : requirements.keySet()) { if (requirements.contains(requirementKey)) { return requirements; } } return null; } @Override public Optional lookupRequirement(KeyRequirements requirementsKey) { return Optional.ofNullable(requirements.get(requirementsKey)); } @Override public int getCountForRequirement(KeyRequirements requirementsKey) { int totalCount = 0; for (Key requirementKey : requirementsKey) { totalCount += dataTracker.getCount(requirementKey); } return totalCount; } }); } public static String parsePlaceholders(Map requirements, DataTracker dataTracker, String line) { return parsePlaceholders(line, new PlaceholdersFunctions() { @Override public Requirements getRequirementFromKey(String key) { for (Requirements requirements : requirements.keySet()) { if (requirements.contains(key)) return requirements; } return null; } @Override public Optional lookupRequirement(Requirements requirementsKey) { return Optional.ofNullable(requirements.get(requirementsKey)); } @Override public int getCountForRequirement(Requirements requirementsKey) { int totalCount = 0; for (String requirementKey : requirementsKey) { totalCount += dataTracker.getCount(requirementKey); } return totalCount; } }); } public static String parsePlaceholders(String line, PlaceholdersFunctions functions) { Matcher matcher = PERCENTAGE_PATTERN.matcher(line); if (matcher.find()) { String requirementKey = matcher.group(1).toUpperCase(Locale.ENGLISH); E requirement = functions.getRequirementFromKey(requirementKey); Optional entry = requirement == null ? Optional.empty() : functions.lookupRequirement(requirement); if (entry.isPresent()) { int count = Math.min(functions.getCountForRequirement(requirement), entry.get()); line = matcher.replaceAll("" + (count * 100) / entry.get()); } } if ((matcher = VALUES_PATTERN.matcher(line)).find()) { String requirementKey = matcher.group(1).toUpperCase(Locale.ENGLISH); E requirement = functions.getRequirementFromKey(requirementKey); Optional entry = requirement == null ? Optional.empty() : functions.lookupRequirement(requirement); if (entry.isPresent()) { int count = Math.min(functions.getCountForRequirement(requirement), entry.get()); line = matcher.replaceAll(String.valueOf(count)); } } return ChatColor.translateAlternateColorCodes('&', line); } public static abstract class PlaceholdersFunctions { @Nullable public abstract E getRequirementFromKey(String key); public abstract Optional lookupRequirement(E requirement); public abstract int getCountForRequirement(E requirement); } } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/CustomRequirements.java ================================================ package com.bgsoftware.superiorskyblock.missions.common.requirements; import java.util.Collection; import java.util.LinkedHashSet; public class CustomRequirements extends RequirementsAbstract { public CustomRequirements() { super(new LinkedHashSet<>()); } public CustomRequirements(Collection elements) { this(); addAll(elements); } @Override protected boolean isAllElement(E element) { return false; } } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/IRequirements.java ================================================ package com.bgsoftware.superiorskyblock.missions.common.requirements; import java.util.Set; public interface IRequirements extends Set { boolean isContainsAll(); } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/KeyRequirements.java ================================================ package com.bgsoftware.superiorskyblock.missions.common.requirements; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import java.util.Collection; import java.util.LinkedHashSet; public class KeyRequirements extends RequirementsAbstract { public KeyRequirements(Collection elements) { super(KeySet.createKeySet(LinkedHashSet::new)); addAll(elements); } @Override protected boolean isAllElement(Key element) { return element.getGlobalKey().equalsIgnoreCase("ALL"); } public Key getKey(Key original) { return ((KeySet) delegate()).getKey(original, original); } } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/Requirements.java ================================================ package com.bgsoftware.superiorskyblock.missions.common.requirements; import java.util.Collection; import java.util.LinkedHashSet; public class Requirements extends RequirementsAbstract { public Requirements(Collection elements) { super(new LinkedHashSet<>()); addAll(elements); } @Override protected boolean isAllElement(String element) { return element.equalsIgnoreCase("all"); } } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/RequirementsAbstract.java ================================================ package com.bgsoftware.superiorskyblock.missions.common.requirements; import com.google.common.collect.ForwardingSet; import java.util.Set; public abstract class RequirementsAbstract extends ForwardingSet implements IRequirements { private final Set handle; private boolean containsAll = false; public RequirementsAbstract(Set handle) { this.handle = handle; } @Override public boolean add(E element) { if (containsAll) return true; if (isAllElement(element)) { this.containsAll = true; return true; } return super.add(element); } @Override public boolean contains(Object object) { return isContainsAll() || super.contains(object); } public boolean isContainsAll() { return this.containsAll; } @Override protected Set delegate() { return this.handle; } protected abstract boolean isAllElement(E element); } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/DataTracker.java ================================================ package com.bgsoftware.superiorskyblock.missions.common.tracker; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.missions.common.requirements.IRequirements; import java.util.Collections; import java.util.Map; import java.util.Optional; public abstract class DataTracker> { private final Map trackedData; private final Counter globalCounter = new Counter(0); protected DataTracker(Map trackedData) { this.trackedData = trackedData; } public void track(K key, int amount) { this.trackedData.computeIfAbsent(key, k -> new Counter(0)).inc(amount); globalCounter.inc(amount); } public void load(K blockKey, int amount) { this.trackedData.put(blockKey, new Counter(amount)); globalCounter.inc(amount); } public int getCount(K blockKey) { return Optional.ofNullable(this.trackedData.get(blockKey)).map(Counter::get).orElse(0); } public int getGlobalCounter() { return this.globalCounter.get(); } public int getCounts(R blocks) { if (blocks.isContainsAll()) return getGlobalCounter(); Counter blocksCount = new Counter(0); blocks.forEach(block -> blocksCount.inc(getCount(block))); return blocksCount.get(); } public void clear() { this.trackedData.clear(); } public Map getCounts() { return Collections.unmodifiableMap(this.trackedData); } } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/KeyDataTracker.java ================================================ package com.bgsoftware.superiorskyblock.missions.common.tracker; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; public class KeyDataTracker extends DataTracker { public KeyDataTracker() { super(KeyMap.createKeyMap()); } } ================================================ FILE: Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/RawDataTracker.java ================================================ package com.bgsoftware.superiorskyblock.missions.common.tracker; import com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements; import java.util.HashMap; public class RawDataTracker extends DataTracker { public RawDataTracker() { super(new HashMap<>()); } } ================================================ FILE: NMS/Paper/build.gradle ================================================ group 'NMS:Paper' dependencies { compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":NMS:Spigot") compileOnly project(":API") compileOnly project(":") } ================================================ FILE: NMS/Paper/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/PaperGlowEnchantment.java ================================================ package com.bgsoftware.superiorskyblock.nms.algorithms; import io.papermc.paper.enchantments.EnchantmentRarity; import net.kyori.adventure.text.Component; import org.bukkit.entity.EntityCategory; import org.bukkit.inventory.EquipmentSlot; import java.util.Collections; import java.util.Set; public class PaperGlowEnchantment extends SpigotGlowEnchantment { public PaperGlowEnchantment(String name) { super(name); } @Override public Component displayName(int i) { return Component.empty(); } @Override public boolean isTradeable() { return false; } @Override public boolean isDiscoverable() { return false; } @Override public EnchantmentRarity getRarity() { return EnchantmentRarity.COMMON; } @Override public float getDamageIncrease(int i, EntityCategory entityCategory) { return 0; } @Override public Set getActiveSlots() { return Collections.emptySet(); } } ================================================ FILE: NMS/Paper-1_20_3/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } group 'NMS:Paper-1_20_3' java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } dependencies { paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":API") compileOnly project(":") } ================================================ FILE: NMS/Paper-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/PaperGlowEnchantment.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms; import io.papermc.paper.enchantments.EnchantmentRarity; import net.kyori.adventure.text.Component; import org.bukkit.entity.EntityCategory; import org.bukkit.inventory.EquipmentSlot; import java.util.Collections; import java.util.Set; public class PaperGlowEnchantment extends SpigotGlowEnchantment { public PaperGlowEnchantment(String name) { super(name); } @Override public Component displayName(int i) { return Component.empty(); } @Override public boolean isTradeable() { return false; } @Override public boolean isDiscoverable() { return false; } @Override public EnchantmentRarity getRarity() { return EnchantmentRarity.COMMON; } @Override public float getDamageIncrease(int i, EntityCategory entityCategory) { return 0; } @Override public Set getActiveSlots() { return Collections.emptySet(); } } ================================================ FILE: NMS/Spigot/build.gradle ================================================ group 'NMS:Spigot' dependencies { compileOnly "org.spigotmc:v1_16_R3:latest" compileOnly project(":API") compileOnly project(":") } ================================================ FILE: NMS/Spigot/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/NMSCachedBlock.java ================================================ package com.bgsoftware.superiorskyblock.nms.algorithms; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; public class NMSCachedBlock implements ICachedBlock { private static final ObjectsPool POOL = new ObjectsPool<>(NMSCachedBlock::new); private BlockData blockData; public static NMSCachedBlock obtain(Block block) { return POOL.obtain().initialize(block); } private NMSCachedBlock() { } private NMSCachedBlock initialize(Block block) { this.blockData = block.getBlockData(); return this; } @Override public void setBlock(Location location) { World world = location.getWorld(); if (world != null) world.getBlockAt(location).setBlockData(blockData); } @Override public void release() { this.blockData = null; POOL.release(this); } } ================================================ FILE: NMS/Spigot/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/SpigotGlowEnchantment.java ================================================ package com.bgsoftware.superiorskyblock.nms.algorithms; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentTarget; public class SpigotGlowEnchantment extends Enchantment { public SpigotGlowEnchantment(String name) { super(NamespacedKey.minecraft(name)); } @Override public String getName() { return "SuperiorSkyblockGlow"; } @Override public int getMaxLevel() { return 1; } @Override public int getStartLevel() { return 0; } @Override public EnchantmentTarget getItemTarget() { return null; } public boolean isTreasure() { return false; } public boolean isCursed() { return false; } @Override public boolean conflictsWith(Enchantment enchantment) { return false; } @Override public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) { return true; } } ================================================ FILE: NMS/Spigot-1_20_3/build.gradle ================================================ group 'NMS:Spigot-1_20_R3' dependencies { compileOnly "org.spigotmc:v1_20_R3:b3973-3" compileOnly project(":API") compileOnly project(":") } ================================================ FILE: NMS/Spigot-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/NMSCachedBlock.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; public class NMSCachedBlock implements ICachedBlock { private static final ObjectsPool POOL = new ObjectsPool<>(NMSCachedBlock::new); private BlockData blockData; public static NMSCachedBlock obtain(Block block) { return POOL.obtain().initialize(block); } private NMSCachedBlock() { } private NMSCachedBlock initialize(Block block) { this.blockData = block.getBlockData(); return this; } @Override public void setBlock(Location location) { World world = location.getWorld(); if (world != null) world.getBlockAt(location).setBlockData(blockData); } @Override public void release() { this.blockData = null; POOL.release(this); } } ================================================ FILE: NMS/Spigot-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/SpigotGlowEnchantment.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentTarget; public class SpigotGlowEnchantment extends Enchantment { private final NamespacedKey key; public SpigotGlowEnchantment(String name) { this.key = NamespacedKey.minecraft(name); } @Override public String getName() { return "SuperiorSkyblockGlow"; } @Override public int getMaxLevel() { return 1; } @Override public int getStartLevel() { return 0; } @Override public EnchantmentTarget getItemTarget() { return null; } public boolean isTreasure() { return false; } public boolean isCursed() { return false; } @Override public boolean conflictsWith(Enchantment enchantment) { return false; } @Override public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) { return true; } @Override public NamespacedKey getKey() { return this.key; } } ================================================ FILE: NMS/build.gradle ================================================ group 'NMS' subprojects { def generatedSrcDir = file("$buildDir/generated/sources/nms") task generateNmsSources { doLast { delete generatedSrcDir generatedSrcDir.mkdirs() def props = new Properties() def propertiesFile = file("$projectDir/properties") if (!propertiesFile.exists()) { return } propertiesFile.withInputStream { stream -> props.load(stream) } def templatesDir = file("${rootDir}/NMS/src/main/templates/") def templates = fileTree(templatesDir) { include '**/*.template' } templates.each { File templateFile -> def relativePath = templatesDir.toPath().relativize(templateFile.toPath()).toString() def outputFile = new File(generatedSrcDir, relativePath.replace('.template', '')) outputFile.parentFile.mkdirs() def templateText = templateFile.text props.each { k, v -> templateText = templateText.replace("\${${k}}", v) } outputFile.text = templateText println "Generated ${outputFile}" } } } sourceSets { main { java { srcDirs = ['src/main/java', generatedSrcDir] } } } compileJava.dependsOn(generateNmsSources) } ================================================ FILE: NMS/src/main/templates/AbstractNMSAlgorithms.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import com.bgsoftware.superiorskyblock.listener.BukkitEventsListener; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuBrewingStandBlockEntity; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuHopperBlockEntity; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextReplacementConfig; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.Container; import net.minecraft.world.entity.item.FallingBlockEntity; import net.minecraft.world.entity.${ABSTRACT_MINECART_SUBPACKAGE}.AbstractMinecart; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.Biome; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import ${CRAFTBUKKIT_PACKAGE}.CraftServer; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftFallingBlock; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftMinecart; import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.world.GenericGameEvent; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; import java.util.Optional; import java.util.function.BiFunction; public abstract class AbstractNMSAlgorithms implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Multimap EMPTY_ATTRIBUTES_MAP = MultimapBuilder.hashKeys().hashSetValues().build(); private static final EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge<>() { @Override public Biome[] getValues() { return Biome.values(); } @Override public String getName(Biome enumValue) { return enumValue.name(); } }; static final int DATA_VERSION = ((CraftMagicNumbers) new ReflectField<>( CraftMagicNumbers.class, Object.class, "INSTANCE").get(null)).getDataVersion(); private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); } private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { @Override public byte[] processClass(byte[] classBytes, String path) { return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); } }; @Override public void registerCommand(BukkitCommand command) { ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); } @Override public int getCombinedId(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); BlockState blockState; try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); blockState = serverLevel.getBlockState(wrapper.getHandle()); } return Block.getId(blockState); } @Override public int getCombinedId(Material material, byte data) { BlockState blockState; if (data == 0) { Block block = CraftMagicNumbers.getBlock(material); if (block == null) return -1; blockState = block.defaultBlockState(); } else { blockState = CraftMagicNumbers.getBlock(material, data); } return blockState == null ? -1 : Block.getId(blockState); } @Override public Optional getTileEntityIdFromCombinedId(int combinedId) { BlockState blockState = Block.stateById(combinedId); if (!blockState.hasBlockEntity()) return Optional.empty(); String id = BlockEntityCache.getBlockEntityId(blockState); return Text.isBlank(id) ? Optional.empty() : Optional.of(id); } @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); return Integer.compare(firstMaterial, secondMaterial); } @Override public short getBlockDataValue(org.bukkit.block.BlockState blockState) { BlockData blockData = blockState.getBlockData(); return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); } @Override public short getBlockDataValue(org.bukkit.block.Block block) { BlockData blockData = block.getBlockData(); return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); } @Override public short getMaxBlockDataValue(Material material) { if (!material.isBlock()) return 0; BlockData blockData = Bukkit.createBlockData(material); return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); } @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); return KeyBlocksCache.getBlockKey(block); } @Override public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); Block block = minecart.getDisplayBlockState().getBlock(); return KeyBlocksCache.getBlockKey(block); } @Override public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); Block block = fallingBlock.getBlockState().getBlock(); return KeyBlocksCache.getBlockKey(block); } @Override public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { // Doesn't exist } @Override public void setRarity(ItemMeta itemMeta, String rarity) { // Doesn't exist } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { // Doesn't exist } @Override public void setHideTooltip(ItemMeta itemMeta) { // Doesn't exist } @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) potionMeta.setColor(potionEffect.getType().getColor()); potionMeta.addCustomEffect(potionEffect, true); } @Nullable @Override public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); } @Override public int getMaxWorldSize() { return Bukkit.getMaxWorldSize(); } @Override public int getDataVersion() { return DATA_VERSION; } @Override public ClassProcessor getClassProcessor() { return CLASS_PROCESSOR; } @Override public void handlePaperChatRenderer(Object event) { if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) return; ChatRenderer originalRenderer = asyncChatEvent.renderer(); asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } @Override public void hideAttributes(ItemMeta itemMeta) { itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); } @Override public EnumBridge getBiomeBridge() { return BIOME_ENUM_BRIDGE; } @Override public BukkitEventsListener.GameEventCreator getGenericGameCreator() { return (eventType, priority, event) -> { GameEventArgs.GenericGameEvent genericGameEvent = new GameEventArgs.GenericGameEvent(); genericGameEvent.world = ((GenericGameEvent) event).getWorld(); genericGameEvent.gameEvent = ((GenericGameEvent) event).getEvent().getKey().getKey(); genericGameEvent.location = ((GenericGameEvent) event).getLocation(); return eventType.createEvent(genericGameEvent); }; } private interface MenuCreator extends BiFunction { } private static class ChatRendererWrapper { private static final String MESSAGE_PLACEHOLDER = "{message}"; private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); private final ChatRenderer renderer = new ChatRenderer() { @Override public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, net.kyori.adventure.text.@NotNull Component sourceDisplayName, net.kyori.adventure.text.@NotNull Component message, @NotNull Audience viewer) { String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); Island island = superiorPlayer.getIsland(); return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) .replaceText(TextReplacementConfig.builder() .matchLiteral(MESSAGE_PLACEHOLDER) .replacement(message) .build()); } }; private final ChatRenderer originalRenderer; public ChatRendererWrapper(ChatRenderer originalRenderer) { this.originalRenderer = originalRenderer; } } } ================================================ FILE: NMS/src/main/templates/AbstractNMSChunks.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SlabBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.phys.AABB; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import ${CRAFTBUKKIT_PACKAGE}.CraftChunk; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.util.CraftNamespacedKey; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public abstract class AbstractNMSChunks implements NMSChunks { protected final SuperiorSkyblockPlugin plugin; protected AbstractNMSChunks(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); CropsTickingMethod.register(); } @Override public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { if (chunkPositions.isEmpty()) return; NMSUtils.runActionOnChunks(chunkPositions, true, getBiomesChunkCallback(bukkitBiome, playersToUpdate)); } protected abstract NMSUtils.ChunkCallback getBiomesChunkCallback( org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate); @Override public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { if (chunkPositions.isEmpty()) return; chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); NMSUtils.runActionOnChunks(chunkPositions, true, getDeleteChunkCallback(onFinish)); } protected abstract NMSUtils.ChunkCallback getDeleteChunkCallback(@Nullable Runnable onFinish); @Override public CompletableFuture> calculateChunks(List chunkPositions, Synchronized> unloadedChunksCache) { List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); Iterator chunkPositionsIterator = chunkPositions.iterator(); while (chunkPositionsIterator.hasNext()) { ChunkPosition chunkPosition = chunkPositionsIterator.next(); CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); if (cachedCalculatedChunk != null) { allCalculatedChunks.add(cachedCalculatedChunk); chunkPositionsIterator.remove(); } else { chunkPositionsToCalculate.add(chunkPosition); } } if (chunkPositions.isEmpty()) return CompletableFuture.completedFuture(allCalculatedChunks); CompletableFuture> completableFuture = new CompletableFuture<>(); NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, getCalculateChunkCallback(completableFuture, unloadedChunksCache, allCalculatedChunks)); return completableFuture; } protected abstract NMSUtils.ChunkCallback getCalculateChunkCallback( CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks); @Override public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { CompletableFuture> completableFuture = new CompletableFuture<>(); List allCalculatedChunks = new LinkedList<>(); List unloadedChunkCompounds = new LinkedList<>(); NMSUtils.runActionOnEntityChunks(chunkPositions, getEntitiesChunkCallback(allCalculatedChunks, unloadedChunkCompounds, completableFuture)); return completableFuture; } protected abstract NMSUtils.ChunkCallback getEntitiesChunkCallback( List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture); protected abstract Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel); @Override public void injectChunkSections(Chunk chunk) { // No implementation } @Override public boolean isChunkEmpty(Chunk bukkitChunk) { ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> chunkSection == null || NMSUtilsVersioned.isLevelChunkSectionEmpty(chunkSection)); } @Override public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; } @Override public void startTickingChunk(Island island, Chunk chunk, boolean stop) { if (plugin.getSettings().getCropsInterval() <= 0) return; if (stop) { long packedPos = NMSUtils.getChunkPackedPos(chunk.getX(), chunk.getZ()); CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(chunk.getWorld().getName(), packedPos); if (cropsBlockEntity != null) cropsBlockEntity.remove(); } else { ServerLevel serverLevel = ((CraftWorld) chunk.getWorld()).getHandle(); LevelChunk levelChunk = serverLevel.getChunk(chunk.getX(), chunk.getZ()); CropsBlockEntity.create(island, chunk.getWorld().getName(), levelChunk); } } @Override public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { if (chunkPositions.isEmpty()) return; CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); } @Override public void shutdown() { List> pendingTasks = NMSUtils.getPendingChunkActions(); if (pendingTasks.isEmpty()) return; Log.info("Waiting for chunk tasks to complete."); CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); } @Override public List getBlockEntities(Chunk chunk) { ServerLevel serverLevel = ((CraftWorld) chunk.getWorld()).getHandle(); LevelChunk levelChunk = serverLevel.getChunk(chunk.getX(), chunk.getZ()); List blockEntities = new LinkedList<>(); World bukkitWorld = chunk.getWorld(); levelChunk.getBlockEntities().keySet().forEach(blockPos -> blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); return blockEntities; } protected CalculatedChunk.Blocks calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); List spawnersLocations = new LinkedList<>(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection levelChunkSection = chunkSections[i]; if (levelChunkSection != null && !NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection)) { int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, sectionBottomY, blockCounts, spawnersLocations); } } } return new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations); } protected CalculatedChunk.Entities calculatedChunk(ChunkPosition chunkPosition, LevelChunk levelChunk) { KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } return new CalculatedChunk.Entities(chunkPosition, chunkEntities); } protected CalculatedChunk.Entities calculatedChunk(ChunkPosition chunkPosition, ServerLevel serverLevel, ListTag entitiesTag) { KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); for (Tag entityTag : entitiesTag) { Entity fakeEntity = createEntityFromTag((CompoundTag) entityTag, serverLevel).orElse(null); if(fakeEntity == null) continue; fakeEntity.valid = false; if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) continue; Key entityKey = Keys.of(fakeEntity.getBukkitEntity()); chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } return new CalculatedChunk.Entities(chunkPosition, chunkEntities); } private void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, int sectionBottomY, KeyMap blockCounts, List spawnersLocations) { Block block = blockState.getBlock(); if (block == Blocks.AIR) return; Location location = new Location(chunkPosition.getWorld(), (chunkPosition.getX() << 4) + x, sectionBottomY + y, (chunkPosition.getZ() << 4) + z); int blockAmount = 1; if (NMSUtils.isDoubleBlock(block, blockState)) { blockAmount = 2; blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); } Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); if (block == Blocks.SPAWNER) { spawnersLocations.add(location); } } protected void removeEntities(LevelChunk levelChunk) { ServerLevel serverLevel = levelChunk.level; int chunkWorldCoordX = levelChunk.locX << 4; int chunkWorldCoordZ = levelChunk.locZ << 4; AABB chunkBounds = new AABB(chunkWorldCoordX, NMSUtilsVersioned.getMinBuildHeight(serverLevel), chunkWorldCoordZ, chunkWorldCoordX + 15, NMSUtilsVersioned.getMaxBuildHeight(serverLevel), chunkWorldCoordZ + 15); List worldEntities = new LinkedList<>(); serverLevel.getEntities().get(chunkBounds, worldEntities::add); worldEntities.forEach(nmsEntity -> { if (!(nmsEntity instanceof net.minecraft.world.entity.player.Player)) nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); }); } protected void removeBlockEntities(LevelChunk levelChunk) { levelChunk.blockEntities.values().forEach(BlockEntity::setRemoved); levelChunk.blockEntities.clear(); } } ================================================ FILE: NMS/src/main/templates/AbstractNMSEntities.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import org.bukkit.Material; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftAnimals; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftMinecartFurnace; import ${CRAFTBUKKIT_PACKAGE}.inventory.CraftItemStack; import org.bukkit.entity.Animals; import org.bukkit.entity.Steerable; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; public abstract class AbstractNMSEntities implements NMSEntities { @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { ItemStack[] itemStacks = new ItemStack[7]; itemStacks[0] = new ItemStack(Material.ARMOR_STAND); itemStacks[1] = entityEquipment.getItemInMainHand(); itemStacks[2] = entityEquipment.getItemInOffHand(); itemStacks[3] = entityEquipment.getHelmet(); itemStacks[4] = entityEquipment.getChestplate(); itemStacks[5] = entityEquipment.getLeggings(); itemStacks[6] = entityEquipment.getBoots(); return itemStacks; } @Override public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } @Override public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { Entity entity = ((CraftEntity) bukkitEntity).getHandle(); return getPortalTicks(entity); } protected abstract int getPortalTicks(Entity entity); @Override public boolean canShearSaddleFromEntity(org.bukkit.entity.Entity entity) { return entity instanceof Steerable steerable && steerable.hasSaddle(); } } ================================================ FILE: NMS/src/main/templates/AbstractNMSTags.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.mojang.serialization.Dynamic; import net.minecraft.nbt.NbtOps; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.Material; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.inventory.CraftItemStack; import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; public abstract class AbstractNMSTags implements NMSTags { @Override public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); return setTagAndGetCompoundTag(itemStack, "DataVersion", AbstractNMSAlgorithms.DATA_VERSION); } protected abstract CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value); @Override public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { if (compoundTag.containsKey("NBT")) { // Old compound version, deserialize it accordingly return deserializeItemOld(compoundTag); } net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); int itemVersion = getCompoundTagInt(tagCompound, "DataVersion", 0); if (itemVersion < AbstractNMSAlgorithms.DATA_VERSION) { tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, AbstractNMSAlgorithms.DATA_VERSION).getValue(); } ItemStack itemStack = parseItemStack(tagCompound); return CraftItemStack.asCraftMirror(itemStack); } protected abstract int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def); protected abstract ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag); private org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); int amount = compoundTag.getInt("amount").orElse(0); short data = (short) compoundTag.getShort("data").orElse(0); CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); if (nbtData != null) { setItemStackCompoundTag(itemStack, (net.minecraft.nbt.CompoundTag) nbtData.toNBT()); } return CraftItemStack.asCraftMirror(itemStack); } protected abstract void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag); @Override public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); if (compoundTag == null) compoundTag = new net.minecraft.nbt.CompoundTag(); if (!compoundTag.contains("id")) //noinspection deprecation compoundTag.putString("id", entityType.getName()); ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); loadEntity(compoundTag, serverLevel, location); } protected abstract void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location); @Override public Object parseList(ListTag listTag) { net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); for (Tag tag : listTag) nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); return nbtTagList; } @Override public Object getNBTCompoundTag(Object object, String key) { return ((net.minecraft.nbt.CompoundTag) object).get(key); } @Override public void setNBTCompoundTagValue(Object object, String key, Object value) { ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); } @Override public int getNBTTagListSize(Object object) { return ((net.minecraft.nbt.ListTag) object).size(); } } ================================================ FILE: NMS/src/main/templates/AbstractNMSWorld.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import com.bgsoftware.superiorskyblock.nms.NMSWorld; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import ${COMMON_NMS_PACKAGE}.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.spawners.TickingSpawnerBlockEntityNotifier; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.CaveVinesPlant; import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallSign; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.block.CraftBlock; import ${CRAFTBUKKIT_PACKAGE}.block.CraftBlockState; import ${CRAFTBUKKIT_PACKAGE}.block.CraftSign; import ${CRAFTBUKKIT_PACKAGE}.block.data.CraftBlockData; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; import ${CRAFTBUKKIT_PACKAGE}.generator.CustomChunkGenerator; import org.bukkit.entity.Player; import java.lang.reflect.Modifier; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public abstract class AbstractNMSWorld implements NMSWorld { private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") .removeFinal(); private static final ReflectField CUSTOM_CHUNK_GENERATOR_DELEGATE = new ReflectField( CustomChunkGenerator.class, ChunkGenerator.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField NOISE_GENERATOR_SETTINGS_SEA_LEVEL = new ReflectField( NoiseGeneratorSettings.class, Integer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); protected final SuperiorSkyblockPlugin plugin; protected AbstractNMSWorld(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { try { return getBlockKeyInternal(chunkSnapshot, x, y, z); } catch (ArrayIndexOutOfBoundsException error) { return ConstantKeys.AIR; } } private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); Location location = new Location( Bukkit.getWorld(chunkSnapshot.getWorldName()), (chunkSnapshot.getX() << 4) + x, y, (chunkSnapshot.getZ() << 4) + z ); return Keys.of(KeyBlocksCache.getBlockKey(block), location); } @Override public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) { try { return canPlayerSuffocateInternal(chunkSnapshot, x, y, z); } catch (ArrayIndexOutOfBoundsException error) { return true; } } private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { BlockState blockState = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState(); return !blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty(); } @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); if (spawnerBlockEntity == null) return; ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel); Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); } } if (!tickersToAdd.isEmpty()) blockEntityTickers.addAll(tickersToAdd); } @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) return; Player player = superiorPlayer.asPlayer(); World world = superiorPlayer.getWorld(); if (world == null || player == null) return; int islandSize = island == null ? 0 : island.getIslandSize(); boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; ServerLevel serverLevel = ((CraftWorld) world).getHandle(); WorldBorder worldBorder; if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { worldBorder = serverLevel.getWorldBorder(); } else { Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); if (dimension == null) return; Location center = island.getCenter(dimension); worldBorder = new WorldBorder(); try { worldBorder.world = serverLevel; } catch (Throwable ignored) { } worldBorder.setWarningBlocks(0); worldBorder.setCenter(center.getX(), center.getZ()); switch (superiorPlayer.getBorderColor()) { case BLUE: worldBorder.setSize((islandSize * 2) + 1D); break; case GREEN: worldBorder.setSize((islandSize * 2) + 1.001D); lerpSizeBetween(worldBorder, worldBorder.getSize() - 0.001D, worldBorder.getSize()); break; case RED: worldBorder.setSize((islandSize * 2) + 1D); lerpSizeBetween(worldBorder, worldBorder.getSize(), worldBorder.getSize() - 0.001D); break; } } ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); } protected abstract void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize); @Override public Object getBlockData(org.bukkit.block.Block block) { return block.getBlockData(); } @Override public void setBlock(Location location, int combinedId) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); BlockState blockState = NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); } } } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) return true; BlockData blockData = block.getBlockData(); return blockData instanceof BubbleColumn || (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } @Override public SignType getSignType(Object sign) { if (sign instanceof WallSign) return SignType.WALL_SIGN; else if (sign instanceof Sign) return SignType.STANDING_SIGN; else return SignType.UNKNOWN; } @Override public boolean hasBerries(org.bukkit.block.Block block) { return ((CaveVinesPlant) block.getBlockData()).isBerries(); } @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = NMSUtilsVersioned.getBlockState(block); return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; } @Override public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { ServerLevel serverLevel = ((CraftWorld) bukkitBlock.getWorld()).getHandle(); BlockState blockState; try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); blockPos.set(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); blockState = serverLevel.getBlockState(blockPos); } return getDefaultAmountInternal(blockState); } @Override public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { return getDefaultAmountInternal(((CraftBlockState) bukkitBlockState).getHandle()); } private int getDefaultAmountInternal(BlockState blockState) { Block block = blockState.getBlock(); return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } @Override public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { return !bukkitBlock.isPassable(); } @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); if (signBlockEntity == null) return; String[] lines = new String[4]; Component[] messages = getSignBlockEntityText(signBlockEntity); System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); String[] strippedLines = new String[4]; for (int i = 0; i < 4; i++) strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); Component[] newLines; IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); if (result.isCancelEvent()) { newLines = CraftSign.sanitizeLines(strippedLines); } else { newLines = CraftSign.sanitizeLines(lines); } System.arraycopy(newLines, 0, messages, 0, 4); } protected abstract Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity); @Override public void playGeneratorSound(Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); serverLevel.levelEvent(1501, blockPos, 0); } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); blockPos.set(block.getX(), block.getY(), block.getZ()); serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); } } @Override public void playPlaceSound(Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); } } @Override public int getMinHeight(World world) { return world.getMinHeight(); } @Override public void removeAntiXray(org.bukkit.World bukkitWorld) { if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ${PAPER_CHUNK_BLOCK_CONTROLLER_CLASS}.NO_OPERATION_INSTANCE); } @Override public void setOceanLevel(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); if (!(serverLevel.getChunkSource().getGenerator() instanceof CustomChunkGenerator chunkGenerator)) return; ChunkGenerator delegateChunkGenerator = getChunkGeneratorDelegate(chunkGenerator); if (delegateChunkGenerator instanceof FlatLevelSource flatLevelSource) { FlatLevelSource newLevelSource = createFlatLevelSource(flatLevelSource, plugin.getSettings().getWorlds().getSeaLevelHeight()); CUSTOM_CHUNK_GENERATOR_DELEGATE.set(chunkGenerator, newLevelSource); } else if(delegateChunkGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { NoiseGeneratorSettings settings = getNoiseGeneratorSettings(noiseBasedChunkGenerator); NOISE_GENERATOR_SETTINGS_SEA_LEVEL.set(settings, plugin.getSettings().getWorlds().getSeaLevelHeight()); } else { throw new IllegalStateException("Cannot set ocean level for chunk generator of type " + delegateChunkGenerator); } } protected abstract ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator); protected abstract FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel); protected abstract NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator); @Override public IslandsGenerator createGenerator(Dimension dimension) { return new IslandsGeneratorImpl(dimension); } @Override public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } @Override public WorldEditSession createPartialEditSession(Dimension dimension) { return WorldEditSessionImpl.obtain(dimension); } @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } private static ReflectField> initializeLevelBlockEntityTickersField() { ReflectField> field = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); if (!field.isValid()) field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); return field; } } ================================================ FILE: NMS/src/main/templates/NMSDragonFightImpl.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndDragonFightWrapper; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnderDragon; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.SpikesCache; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.google.common.cache.LoadingCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS}; import net.minecraft.world.level.levelgen.feature.${SPIKE_FEATURE_CLASS}; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.advancement.Advancement; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import org.bukkit.entity.Player; import java.lang.reflect.Modifier; import java.util.List; public class NMSDragonFightImpl implements NMSDragonFight { private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) .removeFinal(); private static final ReflectField<${END_DRAGON_FIGHT_CLASS}> WORLD_DRAGON_BATTLE = new ReflectField<>( ServerLevel.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE, 1); private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( ${SPIKE_FEATURE_CLASS}.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) .removeFinal(); private static boolean firstWorldPreparation = true; static { ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); } @Override public void prepareEndWorld(World bukkitWorld) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); WORLD_DRAGON_BATTLE.set(serverLevel, new EndDragonFightWrapper(serverLevel)); if (firstWorldPreparation) { firstWorldPreparation = false; SPIKE_CACHE.set(null, SpikesCache.getInstance()); } } @Nullable @Override public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { World bukkitWorld = island.getCenter(dimension).getWorld(); if (bukkitWorld == null) return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight)) return null; IslandEndDragonFight enderDragonBattle = dragonFight.HANDLER.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @Override public void startDragonBattle(Island island, Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight)) return; dragonFight.HANDLER.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override public void removeDragonBattle(Island island, Dimension dimension) { World bukkitWorld = island.getCenter(dimension).getWorld(); if (bukkitWorld == null) return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight)) return; ${END_DRAGON_FIGHT_CLASS} endDragonFight = dragonFight.HANDLER.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); } } @Override public void awardTheEndAchievement(Player player) { Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); if (advancement != null) player.getAdvancementProgress(advancement).awardCriteria(""); } } ================================================ FILE: NMS/src/main/templates/NMSHologramsImpl.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import com.bgsoftware.superiorskyblock.nms.NMSHolograms; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.hologram.EntityHologram; import com.google.common.base.Preconditions; import net.minecraft.server.level.ServerLevel; import org.bukkit.Location; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity; import org.bukkit.entity.Entity; public class NMSHologramsImpl implements NMSHolograms { @Override public Hologram createHologram(Location location) { Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); serverLevel.addFreshEntity(entityHologram); return entityHologram; } @Override public boolean isHologram(Entity entity) { return ((CraftEntity) entity).getHandle() instanceof Hologram; } } ================================================ FILE: NMS/src/main/templates/NMSPlayersImpl.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import net.minecraft.server.level.ServerPlayer; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); @Override public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { return OfflinePlayerDataImpl.create(offlinePlayer); } @Override public void setSkinTexture(SuperiorPlayer superiorPlayer) { Player player = superiorPlayer.asPlayer(); if (player == null) return; ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); NMSUtilsVersioned.getProfileProperties(serverPlayer.getGameProfile()).get("textures").stream().findFirst() .ifPresent(property -> setSkinTexture(superiorPlayer, property)); } @Override public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { superiorPlayer.setTextureValue(NMSUtilsVersioned.getPropertyValue(property)); } @SuppressWarnings("deprecation") @Override public void sendActionBar(Player player, String message) { player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); } @Override public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); bossBar.addPlayer(player); return bossBar; } @SuppressWarnings("deprecation") @Override public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); } @Override public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { return superiorPlayer.getUniqueId().equals(item.getThrower()); } @Nullable @Override public Locale getPlayerLocale(Player player) { if (PLAYER_LOCALE.isValid()) { return player.locale(); } else try { //noinspection deprecation return PlayerLocales.getLocale(player.getLocale()); } catch (IllegalArgumentException error) { return null; } } private static class BossBarImpl implements BossBar { private final org.bukkit.boss.BossBar bossBar; private final BossBarTask bossBarTask; public BossBarImpl(String message, BarColor color, double ticksToRun) { bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); this.bossBarTask = BossBarTask.create(this, ticksToRun); } @Override public void addPlayer(Player player) { this.bossBar.addPlayer(player); this.bossBarTask.registerTask(player); } @Override public void removeAll() { this.bossBar.removeAll(); this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); } @Override public void setProgress(double progress) { this.bossBar.setProgress(progress); } @Override public double getProgress() { return this.bossBar.getProgress(); } } } ================================================ FILE: NMS/src/main/templates/NMSUtils.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.SetBlockContext; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.BlockTags; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SlabBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.levelgen.Heightmap; import org.bukkit.Location; import org.bukkit.World; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); public static final ObjectsPool> BLOCK_POS_POOL = ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); private NMSUtils() { } @Nullable public static T getBlockEntityAt(Location location, Class type) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); } } public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); } public static void runActionOnChunks(Collection chunksCoords, boolean saveChunks, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); } private static void runActionOnChunksInternal(Collection chunksCoords, ChunkCallback chunkCallback, Consumer> onUnloadChunkAction) { List unloadedChunks = new LinkedList<>(); List loadedChunks = new LinkedList<>(); chunksCoords.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); ChunkAccess chunkAccess; try { chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); } catch (Throwable ex) { chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); } if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { unloadedChunks.add(chunkPosition.copy()); } }); boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); if (!loadedChunks.isEmpty()) runActionOnLoadedChunks(loadedChunks, chunkCallback); if (hasUnloadedChunks) { onUnloadChunkAction.accept(unloadedChunks); } else { chunkCallback.onFinish(); } } private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { chunks.forEach(chunkCallback::onLoadedChunk); } private static void runActionOnUnloadedChunks(Collection chunks, boolean saveChunks, ChunkCallback chunkCallback) { if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { Iterator chunksIterator = chunks.iterator(); while (chunksIterator.hasNext()) { ChunkPosition chunkPosition = chunksIterator.next(); ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( chunkPosition.getX(), chunkPosition.getZ()); if (cachedUnloadedChunk != null) { chunkCallback.onLoadedChunk(cachedUnloadedChunk); chunksIterator.remove(); } } if (chunks.isEmpty()) { chunkCallback.onFinish(); return; } } CompletableFuture pendingTask = new CompletableFuture<>(); PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { CountDownLatch countDownLatch; if (chunkCallback.isWaitForChunkLoad) { countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); } else { countDownLatch = null; } List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); boolean calledCountdown = false; try { net.minecraft.nbt.CompoundTag chunkCompound = NMSUtilsVersioned.readChunk(chunkMap, chunkPos); if (chunkCompound == null) { chunkCallback.onChunkNotExist(chunkPosition); return; } net.minecraft.nbt.CompoundTag chunkDataCompound = NMSUtilsVersioned.getChunkData( chunkMap, chunkCompound, serverLevel, chunkPos); UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { if (!calledCountdown && countDownLatch != null) countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); if (countDownLatch != null) { try { countDownLatch.await(); } catch (InterruptedException error) { throw new RuntimeException(error); } } return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); try { NMSUtilsVersioned.saveChunkData(chunkMap, unloadedChunkCompound.chunkCompound, chunkPos); } catch (Exception error) { Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); } }); chunkCallback.onFinish(); pendingTask.complete(null); PENDING_CHUNK_ACTIONS.remove(pendingTask); }); } private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); NMSUtilsVersioned.runActionOnUnloadedEntityChunks(chunks, chunkCallback, countDownLatch).runAsync(v -> { try { countDownLatch.await(); } catch (InterruptedException error) { throw new RuntimeException(error); } }).runSync(v -> { chunkCallback.onFinish(); }); } public static List> getPendingChunkActions() { return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return NMSUtilsVersioned.createProtoChunk(chunkPos, serverLevel); } public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; SetBlockContext setBlockContext = new SetBlockContext() { @Override public LevelHeightAccessor levelHeightAccessor() { return serverLevel; } @Override public void prepareChunkAccess(int chunkX, int chunkZ) { // Do nothing } @Override public LevelChunkSection getChunkSection(int i) { return levelChunk.getSections()[i]; } @Override public Map getHeightmaps() { return levelChunk.heightmaps; } @Override public void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState) { serverLevel.setBlock(blockPos, blockState, 3); } @Override public void onPostSetBlock(BlockPos blockPos, BlockState blockState) { NMSUtilsVersioned.markUnsaved(levelChunk); } @Override public void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty) { if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); serverLevel.getLightEngine().checkBlock(blockPos); } @Override public void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag) { net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); if (tileEntityCompound != null) { tileEntityCompound.putInt("x", blockPos.getX()); tileEntityCompound.putInt("y", blockPos.getY()); tileEntityCompound.putInt("z", blockPos.getZ()); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) { NMSUtilsVersioned.loadBlockEntity(worldBlockEntity, tileEntityCompound); } } } }; return setBlock(setBlockContext, blockPos, combinedId, statesTag, tileEntity); } public static BlockState setBlock(SetBlockContext setBlockContext, BlockPos blockPos, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) { if (!isValidPosition(setBlockContext, blockPos)) return null; BlockState blockState = Block.stateById(combinedId); if (statesTag != null) { for (Map.Entry> entry : statesTag.entrySet()) { try { // noinspection rawtypes Property property = PropertiesMapper.getProperty(entry.getKey()); if (property != null) { if (entry.getValue() instanceof ByteTag) { // noinspection unchecked blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); } else if (entry.getValue() instanceof IntArrayTag) { int[] data = ((IntArrayTag) entry.getValue()).getValue(); // noinspection unchecked blockState = blockState.setValue(property, data[0]); } else if (entry.getValue() instanceof StringTag) { String data = ((StringTag) entry.getValue()).getValue(); // noinspection unchecked blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); } } } catch (Exception ignored) { } } } if ((NMSUtilsVersioned.isBlockStateLiquid(blockState) && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { setBlockContext.onSetBlockWithUpdate(blockPos, blockState); return blockState; } setBlockContext.prepareChunkAccess(blockPos.getX() >> 4, blockPos.getZ() >> 4); int indexY = setBlockContext.levelHeightAccessor().getSectionIndex(blockPos.getY()); LevelChunkSection levelChunkSection = setBlockContext.getChunkSection(indexY); int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); int blockZ = blockPos.getZ() & 15; boolean isOriginallyChunkSectionEmpty = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection); levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); Map heightmaps = setBlockContext.getHeightmaps(); heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); setBlockContext.onPostSetBlock(blockPos, blockState); boolean isChunkSectionEmpty = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection); setBlockContext.onLightUpdate(blockPos, blockState, isOriginallyChunkSectionEmpty, isChunkSectionEmpty); if (tileEntity != null) { setBlockContext.onBlockEntityUpdate(blockPos, tileEntity); } return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; } public static long getChunkPackedPos(int chunkX, int chunkZ) { return (long) chunkX & 4294967295L | ((long) chunkZ & 4294967295L) << 32; } public record UnloadedChunkCompound(ChunkPosition chunkPosition, net.minecraft.nbt.CompoundTag chunkCompound) { public ServerLevel serverLevel () { return ((CraftWorld) chunkPosition.getWorld()).getHandle(); } public ChunkPos chunkPos () { return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); } } private static boolean isValidPosition(SetBlockContext setBlockContext, BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && !setBlockContext.levelHeightAccessor().isOutsideBuildHeight(blockPos.getY()); } public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; } public abstract void onLoadedChunk(LevelChunk levelChunk); public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); public abstract void onFinish(); protected final void latchCountDown() { if (this.chunkLoadLatch != null) this.chunkLoadLatch.countDown(); } public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) { latchCountDown(); return; } ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null).whenComplete((bukkitChunk, error) -> { if (error == null) { BukkitExecutor.ensureMain(() -> { ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); onLoadedChunk(levelChunk); }); } else { latchCountDown(); throw new RuntimeException(error); } }); } } } ================================================ FILE: NMS/src/main/templates/crops/CropsBlockEntity.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import java.lang.ref.WeakReference; import java.util.List; import java.util.function.Consumer; public class CropsBlockEntity extends BlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Chunk2ObjectMap tickingChunks = new Chunk2ObjectMap<>(); private final WeakReference island; private final WeakReference chunk; private int currentTick = 0; private double cachedCropGrowthMultiplier; private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(levelChunk); setLevel(levelChunk.level); levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; } public static void create(Island island, String worldName, LevelChunk levelChunk) { int chunkX = levelChunk.locX; int chunkZ = levelChunk.locZ; long packedPos = NMSUtils.getChunkPackedPos(chunkX, chunkZ); tickingChunks.computeIfAbsent(worldName, packedPos, () -> { BlockPos blockPos = new BlockPos(chunkX << 4, 1, chunkZ << 4); return new CropsBlockEntity(island, levelChunk, blockPos); }); } public static CropsBlockEntity remove(String worldName, long chunkPos) { return tickingChunks.remove(worldName, chunkPos); } public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { if (tickingChunks.isEmpty()) return; chunkPositions.forEach(chunkPosition -> { long chunkKey = chunkPosition.asPair(); CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); if (cropsBlockEntity != null) cropsBlockEntityConsumer.accept(cropsBlockEntity); }); } public boolean isValidBlockState(BlockState state) { return true; } private net.minecraft.world.level.ChunkPos getPos() { LevelChunk levelChunk = this.chunk.get(); return levelChunk == null ? null : levelChunk.getPos(); } public void remove() { this.remove = true; } public void tick() { if (++currentTick <= plugin.getSettings().getCropsInterval()) return; LevelChunk levelChunk = this.chunk.get(); Island island = this.island.get(); ServerLevel serverLevel = (ServerLevel) getLevel(); if (levelChunk == null || island == null || serverLevel == null) { remove(); return; } currentTick = 0; int worldRandomTick = serverLevel.getGameRules().${GET_RANDOM_TICK_SPEED_METHOD}; int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); if (chunkRandomTickSpeed > 0) CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { this.cachedCropGrowthMultiplier = cropGrowthMultiplier; } } ================================================ FILE: NMS/src/main/templates/crops/CropsTickingBlockEntity.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.TickingBlockEntity; public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { @Override public void tick() { cropsBlockEntity.tick(); } @Override public boolean isRemoved() { return cropsBlockEntity.isRemoved(); } @Override public BlockPos getPos() { return cropsBlockEntity.getBlockPos(); } @Override public String getType() { return NMSUtilsVersioned.getBlockEntityTypeKey(cropsBlockEntity.getType()) + ""; } } ================================================ FILE: NMS/src/main/templates/crops/CropsTickingMethod.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.TickingBlockList; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { private static final ReflectField<${SERVER_LEVEL_RANDOM_TYPE}> SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( ServerLevel.class, ${SERVER_LEVEL_RANDOM_TYPE}.class, "simpleRandom"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); private static Set CROPS_TO_GROW_CACHE; static { plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } protected CropsTickingMethod() { } public static void register() { // Calls the static initializer which registers the callback. } public static void tick(LevelChunk levelChunk, int tickSpeed) { INSTANCE.doTick(levelChunk, tickSpeed); } protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); private static void onSettingsUpdate() { CROPS_TO_GROW_CACHE = new HashSet<>(); plugin.getSettings().getCropsToGrow().forEach(cropName -> { Key key = Keys.ofMaterialAndData(cropName); if (key instanceof MaterialKey materialKey) { Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); if (block != null && block.defaultBlockState().isRandomlyTicking()) CROPS_TO_GROW_CACHE.add(block); } }); } private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override protected void doTick(LevelChunk levelChunk, int tickSpeed) { ServerLevel serverLevel = levelChunk.level; LevelChunkSection[] sections = levelChunk.getSections(); int minSection = NMSUtilsVersioned.getMinSection(serverLevel); int chunkOffsetX = levelChunk.locX << 4; int chunkOffsetZ = levelChunk.locZ << 4; ${SERVER_LEVEL_RANDOM_TYPE} simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { LevelChunkSection levelChunkSection = sections[sectionIndex]; if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { continue; } TickingBlockList tickList = NMSUtilsVersioned.getTickingBlockList(levelChunkSection); int tickingBlocks = tickList.size(); if (tickingBlocks <= 0) { continue; } PalettedContainer states = levelChunkSection.states; int offsetY = (sectionIndex + minSection) << 4; for (int i = 0; i < tickSpeed; ++i) { int index = simpleRandom.nextInt() & 0xFFF; if (index >= tickingBlocks) { continue; } int location = (int) tickList.getRaw(index) & 0xFFFF; BlockState blockState = states.get(location); if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, ((location >>> 8) & 15) | offsetY, ((location >>> 4) & 15) | chunkOffsetZ); blockState.randomTick(serverLevel, blockPos, simpleRandom); } } } } private static class SpigotCropsTickingMethod extends CropsTickingMethod { private static int random = ThreadLocalRandom.current().nextInt(); @Override protected void doTick(LevelChunk levelChunk, int tickSpeed) { LevelChunkSection[] sections = levelChunk.getSections(); ServerLevel serverLevel = levelChunk.level; int chunkOffsetX = levelChunk.locX << 4; int chunkOffsetZ = levelChunk.locZ << 4; for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { LevelChunkSection levelChunkSection = sections[sectionIndex]; if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { continue; } int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; for (int i = 0; i < tickSpeed; i++) { random = random * 3 + 1013904223; int factor = random >> 2; int x = factor & 15; int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); } } } } } } ================================================ FILE: NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnderDragon; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.DragonUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndDragonFightWrapper; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import org.bukkit.Location; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEnderDragon; public class AbstractIslandEntityEnderDragon extends EnderDragon { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @NotNull public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : new EnderDragon(entityTypes, level); } protected final ServerLevel serverLevel; protected final Dimension dimension; protected BlockPos islandBlockPos; protected AbstractIslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { this(level); this.islandBlockPos = islandBlockPos; } protected AbstractIslandEntityEnderDragon(Level level) { super(EntityType.ENDER_DRAGON, level); this.serverLevel = (ServerLevel) level; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } @Override public void aiStep() { DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); } @Override @NotNull public CraftEnderDragon getBukkitEntity() { return (CraftEnderDragon) super.getBukkitEntity(); } protected void finalizeIslandEnderDragon() { if (!(NMSUtilsVersioned.getEndDragonFight(this.serverLevel) instanceof EndDragonFightWrapper dragonFight)) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); } if (island == null) return; Location middleBlock = island.getCenter(dimension); SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); if (dimensionConfig instanceof SettingsManager.Worlds.End) { middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); } this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, (IslandEntityEnderDragon) this); dragonFight.HANDLER.addDragonFight(island.getCache(), dragonBattle); } } ================================================ FILE: NMS/src/main/templates/dragon/DragonUtils.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.core.BlockPos; import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; import java.lang.reflect.Modifier; public class DragonUtils { private static final ReflectField END_PODIUM_LOCATION = new ReflectField( EndPodiumFeature.class, BlockPos.class, Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) .removeFinal(); private static BlockPos currentPodiumPosition = BlockPos.ZERO; private DragonUtils() { } public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { try { END_PODIUM_LOCATION.set(null, podiumPosition); currentPodiumPosition = podiumPosition; runnable.run(); } finally { END_PODIUM_LOCATION.set(null, BlockPos.ZERO); currentPodiumPosition = BlockPos.ZERO; } } public static BlockPos getCurrentPodiumPosition() { return currentPodiumPosition; } } ================================================ FILE: NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS}; import java.util.LinkedList; import java.util.List; public class EndWorldEndDragonFightHandler { private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); private final List worldDragonFightsList = new LinkedList<>(); EndWorldEndDragonFightHandler() { } public void tick() { this.worldDragonFightsList.forEach(IslandEndDragonFight::tick); } public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable public IslandEndDragonFight getDragonFight(IslandCache islandCache) { return islandCache.get(CACHE_KEY); } @Nullable public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; } } ================================================ FILE: NMS/src/main/templates/dragon/IslandEndDragonFight.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.DragonUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; import net.minecraft.world.level.block.state.pattern.BlockInWorld; import net.minecraft.world.level.block.state.pattern.BlockPattern; import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; import net.minecraft.world.level.block.state.predicate.BlockPredicate; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS}; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; public class IslandEndDragonFight extends EndDragonFightWrapper { private static final ReflectField<${END_DRAGON_FIGHT_CLASS}> DRAGON_BATTLE = initializeDragonBattleField(); private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( ${END_DRAGON_FIGHT_CLASS}.class, boolean.class, Modifier.PRIVATE, 3); private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( ${END_DRAGON_FIGHT_CLASS}.class, boolean.class, Modifier.PRIVATE, 1); private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( ${END_DRAGON_FIGHT_CLASS}.class, int.class, Modifier.PRIVATE, 4); private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() .aisle(" ", " ", " ", " # ", " ", " ", " ") .aisle(" ", " ", " ", " # ", " ", " ", " ") .aisle(" ", " ", " ", " # ", " ", " ", " ") .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) .build(); private final Island island; private final BlockPos islandBlockPos; private final Vec3 islandBlockVectored; private final ServerLevel serverLevel; private final IslandEntityEnderDragon entityEnderDragon; private byte currentTick = 0; public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); } public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { super(serverLevel); this.island = island; this.islandBlockPos = islandBlockPos; this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); this.serverLevel = serverLevel; this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; SCAN_FOR_LEGACY_PORTALS.set(this, false); WAS_DRAGON_KILLED.set(this, false); DRAGON_BATTLE.set(this.entityEnderDragon, this); TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); } @Override public void tick() { // doServerTick DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); } if (++currentTick >= 20) { updateBattlePlayers(); currentTick = 0; TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); } } @Nullable @Override public BlockPattern.BlockPatternMatch findExitPortal() { int chunkX = this.islandBlockPos.getX() >> 4; int chunkZ = this.islandBlockPos.getZ() >> 4; for (int x = -8; x <= 8; ++x) { for (int z = -8; z <= 8; ++z) { LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { if (blockEntity instanceof TheEndPortalBlockEntity) { BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( this.serverLevel, blockEntity.getBlockPos()); if (blockPatternMatch != null) { if(getPortalPos() == null) setPortalPos(blockPatternMatch.getBlock(3, 3, 3).getPos()); return blockPatternMatch; } } } } } int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); for (int y = highestBlock; y >= NMSUtilsVersioned.getMinBuildHeight(this.serverLevel); --y) { currentPosition.setY(y); BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); if (blockPatternMatch != null) { if(getPortalPos() == null) setPortalPos(blockPatternMatch.getBlock(3, 3, 3).getPos()); return blockPatternMatch; } } } return null; } @Override public void resetSpikeCrystals() { DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); } public void removeBattlePlayers() { List dragonEventPlayers = new SequentialListBuilder() .build(this.dragonEvent.getPlayers()); for (ServerPlayer serverPlayer : dragonEventPlayers) this.dragonEvent.removePlayer(serverPlayer); } public IslandEntityEnderDragon getEnderDragon() { return this.entityEnderDragon; } private void updateBattlePlayers() { Set nearbyPlayers = new HashSet<>(); WorldInfo worldInfo = WorldInfo.of(this.serverLevel.getWorld()); try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { strategy.getPlayers(worldInfo).forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); this.dragonEvent.addPlayer(serverPlayer); nearbyPlayers.add(serverPlayer.getUUID()); }); } List dragonEventPlayers = new SequentialListBuilder() .build(this.dragonEvent.getPlayers()); dragonEventPlayers.stream() .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) .forEach(this.dragonEvent::removePlayer); } private IslandEntityEnderDragon spawnEnderDragon() { IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); NMSUtilsVersioned.moveEntity(entityEnderDragon, this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); NMSUtilsVersioned.addEntity(this.serverLevel, entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); this.dragonUUID = entityEnderDragon.getUUID(); this.resetSpikeCrystals(); return entityEnderDragon; } private static ReflectField<${END_DRAGON_FIGHT_CLASS}> initializeDragonBattleField() { ReflectField<${END_DRAGON_FIGHT_CLASS}> dragonBattleField = new ReflectField<${END_DRAGON_FIGHT_CLASS}>( EnderDragon.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE | Modifier.FINAL, 1); if(dragonBattleField.isValid()) { dragonBattleField = dragonBattleField.removeFinal(); } else { dragonBattleField = new ReflectField<${END_DRAGON_FIGHT_CLASS}>( EnderDragon.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE, 1); } return dragonBattleField; } } ================================================ FILE: NMS/src/main/templates/dragon/SpikesCache.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheStats; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; import net.minecraft.world.level.levelgen.feature.${SPIKE_FEATURE_CLASS}; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; public class SpikesCache implements LoadingCache> { private static final SpikesCache INSTANCE = new SpikesCache(); private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); private long worldSeed; public static SpikesCache getInstance() { return INSTANCE; } private SpikesCache() { } @Override public @NotNull List<${SPIKE_FEATURE_CLASS}.EndSpike> get(@NotNull Long worldSeed) throws ExecutionException { try { this.worldSeed = worldSeed; return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); } finally { this.worldSeed = 0; } } @Override public @NotNull List<${SPIKE_FEATURE_CLASS}.EndSpike> getUnchecked(@NotNull Long worldSeed) { try { this.worldSeed = worldSeed; return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); } finally { this.worldSeed = 0; } } @Override public @NotNull ImmutableMap> getAll(@NotNull Iterable keys) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public List<${SPIKE_FEATURE_CLASS}.EndSpike> apply(@NotNull Long worldSeed) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public void refresh(@NotNull Long worldSeed) { try { this.worldSeed = worldSeed; cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); } finally { this.worldSeed = 0; } } @Override public @NotNull ConcurrentMap> asMap() { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Nullable @Override public List<${SPIKE_FEATURE_CLASS}.EndSpike> getIfPresent(@NotNull Object worldSeed) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public @NotNull List<${SPIKE_FEATURE_CLASS}.EndSpike> get(@NotNull Long worldSeed, @NotNull Callable> loader) throws ExecutionException { try { this.worldSeed = worldSeed; return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); } finally { this.worldSeed = 0; } } @Override public @NotNull ImmutableMap> getAllPresent(@NotNull Iterable keys) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public void put(@NotNull Long worldSeed, @NotNull List<${SPIKE_FEATURE_CLASS}.EndSpike> spikes) { try { this.worldSeed = worldSeed; cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); } finally { this.worldSeed = 0; } } @Override public void putAll(Map> spikesMap) { spikesMap.forEach(this::put); } @Override public void invalidate(@NotNull Object worldSeed) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public void invalidateAll(@NotNull Iterable keys) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public void invalidateAll() { this.cachedSpikes.invalidateAll(); } @Override public long size() { return this.cachedSpikes.size(); } @Override public @NotNull CacheStats stats() { return this.cachedSpikes.stats(); } @Override public void cleanUp() { this.cachedSpikes.cleanUp(); } private class InternalCacheLoader extends CacheLoader> { @Override public @NotNull List<${SPIKE_FEATURE_CLASS}.EndSpike> load(@NotNull BlockPos blockPos) { List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); Collections.shuffle(list, new Random(worldSeed)); List<${SPIKE_FEATURE_CLASS}.EndSpike> spikesList = Lists.newArrayList(); for (int i = 0; i < 10; ++i) { int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); int l = list.get(i); int radius = 2 + l / 3; int height = 76 + l * 3; boolean guarded = l == 1 || l == 2; spikesList.add(new ${SPIKE_FEATURE_CLASS}.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); } return spikesList; } } } ================================================ FILE: NMS/src/main/templates/generator/IslandsGeneratorImpl.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.generator; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.WorldInfo; import java.util.Collections; import java.util.List; import java.util.Random; public class IslandsGeneratorImpl extends IslandsGenerator { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Dimension dimension; public IslandsGeneratorImpl(Dimension dimension) { this.dimension = dimension; } @Override public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, @NotNull ChunkData chunkData) { if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { chunkData.setBlock(0, 99, 0, Material.BEDROCK); } } @Override public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { return new BiomeProvider() { @Override public @NotNull Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); } @Override public @NotNull List getBiomes(@NotNull WorldInfo worldInfo) { return IslandUtils.getDefaultWorldBiomes(); } }; } @Override public List getDefaultPopulators(World world) { return Collections.emptyList(); } @Override public Location getFixedSpawnLocation(World world, Random random) { return new Location(world, 0, 100, 0); } } ================================================ FILE: NMS/src/main/templates/hologram/AbstractEntityHologram.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.hologram; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.bukkit.Bukkit; import ${CRAFTBUKKIT_PACKAGE}.CraftServer; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftArmorStand; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity; import ${CRAFTBUKKIT_PACKAGE}.util.CraftChatMessage; public class AbstractEntityHologram extends ArmorStand implements Hologram { private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); private CraftEntity bukkitEntity; protected AbstractEntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); setInvisible(true); setSmall(true); setShowArms(false); setNoGravity(true); setNoBasePlate(true); setMarker(true); forceSetBoundingBox(EMPTY_BOUND); super.collides = false; super.setCustomNameVisible(true); } @Override public void setHologramName(String name) { super.setCustomName(CraftChatMessage.fromStringOrNull(name)); } @Override public void removeHologram() { super.remove(RemovalReason.DISCARDED); } @Override public org.bukkit.entity.ArmorStand getHandle() { return this.getBukkitEntity(); } @Override public void inactiveTick() { // Disable normal ticking for this entity. // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. if (this.onGround) { this.onGround = false; } } @Override public boolean repositionEntityAfterLoad() { return false; } public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { // Prevent stand being equipped } public void setSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { // Prevent stand being equipped } @Override public void tick() { // Disable normal ticking for this entity. // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. if (this.onGround) { this.onGround = false; } } public void forceSetBoundingBox(AABB boundingBox) { super.setBoundingBox(boundingBox); } @Override public CraftArmorStand getBukkitEntity() { if (bukkitEntity == null) { bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); } return (CraftArmorStand) bukkitEntity; } @Override public void remove(RemovalReason removalReason) { // Prevent being killed. } @Override public void playSound(SoundEvent soundEvent, float volume, float pitch) { // Remove sounds. } /* * The field Entity.invulnerable is private. * It's only used while saving NBTTags, but since the entity would be killed * on chunk unload, we prefer to override isInvulnerable(). */ public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { return true; } public boolean isInvulnerableTo(DamageSource damageSource) { return true; } @Override public void setCustomName(Component component) { // Locks the custom name. } @Override public void setCustomNameVisible(boolean isCustomNameVisible) { // Locks the custom name. } } ================================================ FILE: NMS/src/main/templates/menu/MenuBrewingStandBlockEntity.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; import org.bukkit.inventory.InventoryHolder; public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { private final InventoryHolder holder; public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); this.holder = holder; this.name = Component.nullToEmpty(title); } @Override public InventoryHolder getOwner() { return holder; } } ================================================ FILE: NMS/src/main/templates/menu/MenuDispenserBlockEntity.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.DispenserBlockEntity; import org.bukkit.inventory.InventoryHolder; public class MenuDispenserBlockEntity extends DispenserBlockEntity { private final InventoryHolder holder; public MenuDispenserBlockEntity(InventoryHolder holder, String title) { super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); this.holder = holder; this.name = Component.nullToEmpty(title); } @Override public InventoryHolder getOwner() { return holder; } } ================================================ FILE: NMS/src/main/templates/menu/MenuFurnaceBlockEntity.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.FurnaceBlockEntity; import org.bukkit.inventory.InventoryHolder; public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { private final InventoryHolder holder; public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); this.holder = holder; this.name = Component.nullToEmpty(title); } @Override public InventoryHolder getOwner() { return holder; } } ================================================ FILE: NMS/src/main/templates/menu/MenuHopperBlockEntity.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.HopperBlock; import net.minecraft.world.level.block.entity.HopperBlockEntity; import org.bukkit.inventory.InventoryHolder; public class MenuHopperBlockEntity extends HopperBlockEntity { private final InventoryHolder holder; public MenuHopperBlockEntity(InventoryHolder holder, String title) { super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); this.holder = holder; this.name = Component.nullToEmpty(title); } @Override public InventoryHolder getOwner() { return holder; } } ================================================ FILE: NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.player; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.mojang.authlib.GameProfile; import com.mojang.serialization.Dynamic; import net.minecraft.nbt.NbtOps; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; import ${CRAFTBUKKIT_PACKAGE}.CraftServer; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.Optional; import java.util.UUID; public class OfflinePlayerDataImpl implements OfflinePlayerData { private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>(Entity.class, 1, Level.class); private Player fakePlayer; public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { return POOL.obtain().initialize(offlinePlayer); } private OfflinePlayerDataImpl() { } private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); if (serverLevel == null) return null; ServerPlayer serverPlayer = NMSUtilsVersioned.createServerPlayer(serverLevel, profile); NMSUtilsVersioned.loadPlayerData(serverPlayer).ifPresent(playerData -> { ResourceKey resourceKey; if (playerData.contains("WorldUUIDMost") && playerData.contains("WorldUUIDLeast")) { long worldUUIDMost = NMSUtilsVersioned.getCompoundTagLong(playerData, "WorldUUIDMost", 0L); long worldUUIDLeast = NMSUtilsVersioned.getCompoundTagLong(playerData, "WorldUUIDLeast", 0L); UUID uid = new UUID(worldUUIDMost, worldUUIDLeast); World bukkitWorld = Bukkit.getServer().getWorld(uid); if (bukkitWorld != null) { resourceKey = ((CraftWorld) bukkitWorld).getHandle().dimension(); } else { resourceKey = Level.OVERWORLD; } } else { resourceKey = Level.OVERWORLD; } ServerLevel worldServer = server.getLevel(resourceKey); if (worldServer == null) { worldServer = server.overworld(); } serverPlayer.setLevel(worldServer); }); this.fakePlayer = serverPlayer.getBukkitEntity(); return this; } @Override public Player getFakeOnlinePlayer() { return this.fakePlayer; } @Override public void setLocation(Location location) { ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); NMSUtilsVersioned.moveEntity(serverPlayer, location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } @Override public void applyChanges() { this.fakePlayer.saveData(); } @Override public void release() { this.fakePlayer = null; POOL.release(this); } } ================================================ FILE: NMS/src/main/templates/spawners/TickingSpawnerBlockEntityNotifier.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.spawners; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BaseSpawner; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import java.util.function.IntFunction; public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { private final SpawnerBlockEntity spawnerBlockEntity; private final TickingBlockEntity tickingBlockEntity; private final IntFunction delayChangeCallback; public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, IntFunction delayChangeCallback) { this.spawnerBlockEntity = spawnerBlockEntity; this.tickingBlockEntity = tickingBlockEntity; this.delayChangeCallback = delayChangeCallback; updateDelay(); } @Override public void tick() { BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); int startDelay = baseSpawner.spawnDelay; try { tickingBlockEntity.tick(); } finally { int newDelay = baseSpawner.spawnDelay; if (newDelay > startDelay) updateDelay(); } } @Override public boolean isRemoved() { return tickingBlockEntity.isRemoved(); } @Override public BlockPos getPos() { return tickingBlockEntity.getPos(); } @Override public String getType() { return tickingBlockEntity.getType(); } public void updateDelay() { BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); } } ================================================ FILE: NMS/src/main/templates/utils/SetBlockContext.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.core.BlockPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.levelgen.Heightmap; import java.util.Map; public interface SetBlockContext { LevelHeightAccessor levelHeightAccessor(); void prepareChunkAccess(int chunkX, int chunkZ); LevelChunkSection getChunkSection(int i); Map getHeightmaps(); void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState); void onPostSetBlock(BlockPos blockPos, BlockState blockState); void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty); void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag); } ================================================ FILE: NMS/src/main/templates/utils/TickingBlockList.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils; public interface TickingBlockList { int size(); int getRaw(int index); } ================================================ FILE: NMS/src/main/templates/world/BlockEntityCache.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import java.util.IdentityHashMap; import java.util.Map; public class BlockEntityCache { private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); private BlockEntityCache() { } public static String getBlockEntityId(BlockState blockState) { return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { for (BlockEntityType blockEntityType : ${REGISTRY_CLASS}.BLOCK_ENTITY_TYPE) { if (blockEntityType.isValid(blockState)) { Object resourceLocation = NMSUtilsVersioned.getBlockEntityTypeKey(blockEntityType); if (resourceLocation != null) return resourceLocation.toString(); } } return ""; }); } } ================================================ FILE: NMS/src/main/templates/world/ChunkReaderImpl.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.chunk.DataLayer; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity; import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; import org.bukkit.inventory.InventoryHolder; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = NMSUtilsVersioned.createEmptyPlattedContainerStates(); private static final byte[] FULL_LIGHT = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; static { Arrays.fill(FULL_LIGHT, (byte) 0xFF); } private final ServerLevel serverLevel; private final int x; private final int z; private final Map blockEntities = new HashMap<>(); private final List entities = new LinkedList<>(); private final PalettedContainer[] blockids; private final byte[][] skylight; private final byte[][] emitlight; public ChunkReaderImpl(Chunk bukkitChunk) { this.serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); LevelChunk levelChunk = this.serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); this.x = levelChunk.locX; this.z = levelChunk.locZ; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainer[levelChunkSections.length]; this.skylight = new byte[levelChunkSections.length][]; this.emitlight = new byte[levelChunkSections.length][]; LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); for (int i = 0; i < this.blockids.length; ++i) { LevelChunkSection levelChunkSection = levelChunkSections[i]; this.blockids[i] = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection) ? EMPTY_STATES : NMSUtilsVersioned.copyPalettedContainer(levelChunkSection.getStates()); DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) .getDataLayerData(SectionPos.of(this.x, this.serverLevel.getSectionYFromSectionIndex(i), this.z)); if (skyLightArray == null) { this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; } else { this.skylight[i] = new byte[2048]; System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); } DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) .getDataLayerData(SectionPos.of(this.x, this.serverLevel.getSectionYFromSectionIndex(i), this.z)); if (emitLightArray == null) { this.emitlight[i] = EMPTY_LIGHT; } else { this.emitlight[i] = new byte[2048]; System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); } } levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { net.minecraft.nbt.CompoundTag compoundTag = NMSUtilsVersioned.saveBlockEntity(blockEntity); compoundTag.remove("x"); compoundTag.remove("y"); compoundTag.remove("z"); InventoryHolder inventoryHolder = blockEntity.getOwner(); if (inventoryHolder != null) compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); }); for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); } @Override public int getX() { return this.x; } @Override public int getZ() { return this.z; } @Override public Material getType(int x, int y, int z) { return NMSUtilsVersioned.getMaterialFromBlock(getBlockState(x, y, z).getBlock()); } @Override public short getData(int x, int y, int z) { return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); } @Override @Nullable public CompoundTag getTileEntity(int x, int y, int z) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); return this.blockEntities.get(blockPos); } } @Override @Nullable public CompoundTag readBlockStates(int x, int y, int z) { BlockState blockState = getBlockState(x, y, z); CompoundTag compoundTag = CompoundTag.of(); boolean processedAny = NMSUtilsVersioned.forEachProperty(blockState, (property, value) -> { String name = PropertiesMapper.getPropertyName(property); if (property instanceof BooleanProperty) { compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); } else if (property instanceof IntegerProperty integerProperty) { compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); } else if (property instanceof EnumProperty) { compoundTag.setString(name, ((Enum) value).name()); } }); return processedAny ? compoundTag : null; } @Override public byte[] getLightLevels(int x, int y, int z) { int off = (y & 15) << 7 | z << 3 | x >> 1; int skyLightLevel = this.skylight[this.serverLevel.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; int emitLightLevel = this.emitlight[this.serverLevel.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; } @Override public void forEachEntity(EntityConsumer consumer) { if (entities.isEmpty()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = wrapper.getHandle(); for (CachedEntity cachedEntity : entities) { location.setX(cachedEntity.x); location.setY(cachedEntity.y); location.setZ(cachedEntity.z); location.setYaw(cachedEntity.yaw); location.setPitch(cachedEntity.pitch); consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); } } } private BlockState getBlockState(int x, int y, int z) { return this.blockids[this.serverLevel.getSectionIndex(y)].get(x, y & 15, z); } private static class CachedEntity { private final double x; private final double y; private final double z; private final float yaw; private final float pitch; private final EntityType entityType; private final CompoundTag entityTag; CachedEntity(Entity entity) { this.x = entity.getX(); this.y = entity.getY(); this.z = entity.getZ(); this.yaw = entity.getBukkitYaw(); this.pitch = entity.getXRot(); this.entityType = entity.getBukkitEntity().getType(); net.minecraft.nbt.CompoundTag compoundTag = NMSUtilsVersioned.saveEntity(entity); compoundTag.putFloat("Yaw", entity.getYRot()); compoundTag.putFloat("Pitch", entity.getXRot()); this.entityTag = CompoundTag.fromNBT(compoundTag); } } } ================================================ FILE: NMS/src/main/templates/world/KeyBlocksCache.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.key.Keys; import net.minecraft.world.level.block.Block; import org.bukkit.Material; import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; import java.util.IdentityHashMap; import java.util.Map; public class KeyBlocksCache { private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); private KeyBlocksCache() { } public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } public static void cacheAllBlocks() { ${REGISTRY_CLASS}.BLOCK.forEach(KeyBlocksCache::getBlockKey); } } ================================================ FILE: NMS/src/main/templates/world/PropertiesMapper.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.superiorskyblock.core.logging.Log; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.Property; import java.lang.reflect.Field; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Map; public class PropertiesMapper { private static final Map> nameToProperty = new HashMap<>(); private static final Map, String> propertyToName = new HashMap<>(); static { Map fieldsToNames = new IdentityHashMap<>(); fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); PropertiesMapperVersioned.initializeFields(fieldsToNames); try { for (Field field : BlockStateProperties.class.getFields()) { field.setAccessible(true); Object value = field.get(null); if (value instanceof Property) { Property property = (Property) value; register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); } } } catch (Exception error) { Log.error(error, "An unexpected error occurred while loading properties mapper:"); } } private static void register(String key, String fieldName, Property property) { if (nameToProperty.containsKey(key)) { Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); } else { nameToProperty.put(key, property); propertyToName.put(property, key); } } public static Property getProperty(String name) { return nameToProperty.get(name); } public static String getPropertyName(Property property) { return propertyToName.get(property); } } ================================================ FILE: NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.core.BlockPos; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.phys.Vec2; import org.bukkit.Location; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Supplier; public class WorldEditSessionDataImpl implements WorldEditSession.Data { private static final boolean isStarLightInterface = ((Supplier) () -> { try { Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); return true; } catch (ClassNotFoundException error) { return false; } }).get(); private final List> chunks = new LinkedList<>(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, List> blocksToUpdate, List> blockEntities, Set lightenChunks) { int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); int baseChunkPosXAxis = baseBlockPosXAxis >> 4; int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // Convert chunk data Iterator> chunksIterator = chunks.entryIterator(); while (chunksIterator.hasNext()) { Long2ObjectMapView.Entry entry = chunksIterator.next(); int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); List> lights; if (isStarLightInterface || chunkData.lights().isEmpty()) { lights = Collections.emptyList(); } else { lights = new LinkedList<>(); chunkData.lights().forEach(lightPosition -> { lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, null)); }); } PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), chunkData.heightmaps(), lights); this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); } // Convert blocksToUpdate blocksToUpdate.forEach(blockToUpdate -> { BlockPos blockPos = blockToUpdate.getKey(); this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, blockToUpdate.getValue())); }); // Convert blockEntities blockEntities.forEach(blockEntity -> { BlockPos blockPos = blockEntity.getKey(); this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, blockEntity.getValue())); }); // Convert lights lightenChunks.forEach(lightPosition -> { this.lightenChunks.add(new PositionedObject<>((int)lightPosition.x - baseChunkPosXAxis, (int)lightPosition.y - baseChunkPosZAxis, null)); }); } public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, Long2ObjectMapView chunks) { this.chunks.forEach(chunkDataPositioned -> { long newPos = NMSUtils.getChunkPackedPos(baseChunkPosXAxis + chunkDataPositioned.xOffset, baseChunkPosZAxis + chunkDataPositioned.zOffset); List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); chunkDataPositioned.object.lights.forEach(lightPositioned -> { lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, baseBlockPosYAxis + lightPositioned.yOffset, baseBlockPosZAxis + lightPositioned.zOffset)); }); chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, chunkDataPositioned.object.heightmaps, lights)); }); } public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { this.blocksToUpdate.forEach(blockToUpdatePositioned -> { BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, baseBlockPosYAxis + blockToUpdatePositioned.yOffset, baseBlockPosZAxis + blockToUpdatePositioned.zOffset); blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); }); } public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { this.blockEntities.forEach(blockEntityPositioned -> { BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, baseBlockPosYAxis + blockEntityPositioned.yOffset, baseBlockPosZAxis + blockEntityPositioned.zOffset); blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); }); } public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { this.lightenChunks.forEach(lightPositioned -> { ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, baseChunkPosZAxis + lightPositioned.zOffset); lightenChunks.add(newPos); }); } private static class PositionedObject { private final int xOffset; private final int yOffset; private final int zOffset; private final V object; PositionedObject(int xOffset, int zOffset, V object) { this(xOffset, 0, zOffset, object); } PositionedObject(int xOffset, int yOffset, int zOffset, V object) { this.xOffset = xOffset; this.yOffset = yOffset; this.zOffset = zOffset; this.object = object; } } private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List> lights) { } } ================================================ FILE: NMS/src/main/templates/world/WorldEditSessionImpl.java.template ================================================ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.SetBlockContext; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.google.common.base.Preconditions; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.phys.Vec2; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import org.bukkit.generator.ChunkGenerator; import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Supplier; public class WorldEditSessionImpl implements WorldEditSession { private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { Class.forName("${STAR_LIGHT_INTERFACE_CLASS}"); return true; } catch (ClassNotFoundException error) { return false; } }).get(); private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); private final Set lightenChunksPositions = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); private Dimension dimension; private LevelHeightAccessor levelHeightAccessor; @Nullable private ServerLevel serverLevel; private final SetBlockContext SET_BLOCK_CONTEXT = new SetBlockContext() { ChunkData chunkData; @Override public LevelHeightAccessor levelHeightAccessor() { return levelHeightAccessor; } @Override public void prepareChunkAccess(int chunkX, int chunkZ) { long packedPos = NMSUtils.getChunkPackedPos(chunkX, chunkZ); chunkData = chunks.computeIfAbsent(packedPos, pos -> new ChunkData(new ChunkPos(chunkX, chunkZ))); } @Override public LevelChunkSection getChunkSection(int i) { return chunkData.chunkSections[i]; } @Override public Map getHeightmaps() { return chunkData.heightmaps; } @Override public void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState) { blocksToUpdate.add(new Pair<>(blockPos, blockState)); } @Override public void onPostSetBlock(BlockPos blockPos, BlockState blockState) { // Do nothing } @Override public void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty) { if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); } @Override public void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag) { blockEntities.add(new Pair<>(blockPos, blockEntityTag)); } }; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } public static WorldEditSessionImpl obtain(Dimension dimension) { return POOL.obtain().initialize(dimension); } private WorldEditSessionImpl() { } private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); this.levelHeightAccessor = serverLevel; return this; } private WorldEditSessionImpl initialize(Dimension dimension) { DimensionType dimensionType = NMSUtilsVersioned.getDimensionTypeFromDimension(dimension); this.serverLevel = null; this.dimension = dimension; this.levelHeightAccessor = createLevelHeightAccessor(dimensionType.minY(), dimensionType.height()); return this; } @Override public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData) { BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); NMSUtils.setBlock(SET_BLOCK_CONTEXT, blockPos, combinedId, statesTag, blockEntityData); } @Override public List getAffectedChunks() { Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); if (chunks.isEmpty()) return Collections.emptyList(); List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); int chunkX = (int) chunkKey; int chunkZ = (int) (chunkKey >> 32); chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @Override public void applyBlocks(Chunk bukkitChunk) { Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); int chunkX = bukkitChunk.getX(); int chunkZ = bukkitChunk.getZ(); ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); LevelChunk levelChunk = serverLevel.getChunk(chunkX, chunkZ); long chunkKey = NMSUtils.getChunkPackedPos(chunkX, chunkZ); ChunkData chunkData = this.chunks.remove(chunkKey); if (chunkData == null) return; int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); for (int i = 0; i < chunkSectionsCount; ++i) { levelChunk.getSections()[i] = chunkData.chunkSections[i]; } chunkData.heightmaps.forEach(((type, heightmap) -> { levelChunk.setHeightmap(type, heightmap.getRawData()); })); if (plugin.getSettings().isLightsUpdate()) { if (isStarLightInterface) { this.lightenChunks.add(new Vec2(chunkX, chunkZ)); this.lightenChunksPositions.add(levelChunk.getPos()); } else { ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); // Queues chunk light for this chunk. threadedLevelLightEngine.lightChunk(levelChunk, false); } } NMSUtilsVersioned.markUnsaved(levelChunk); } @Override public void finish(Island island) { Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); // Update block entities blockEntities.forEach(data -> { net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); if (blockEntityCompound != null) { BlockPos blockPos = data.getKey(); blockEntityCompound.putInt("x", blockPos.getX()); blockEntityCompound.putInt("y", blockPos.getY()); blockEntityCompound.putInt("z", blockPos.getZ()); NMSUtilsVersioned.rewriteSignLines(blockEntityCompound); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) { NMSUtilsVersioned.loadBlockEntity(worldBlockEntity, blockEntityCompound); } } }); if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); NMSUtilsVersioned.relightChunks(threadedLevelLightEngine, lightenChunksPositions); this.lightenChunks.clear(); this.lightenChunksPositions.clear(); } release(); } @Override public Data readData(Location baseLocation) { return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override public void applyData(Data data, Location baseLocation) { WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); int baseChunkPosXAxis = baseBlockPosXAxis >> 4; int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this, this.chunks); dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunksPositions); } @Override public void release() { this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.lightenChunksPositions.clear(); this.serverLevel = null; this.dimension = null; this.levelHeightAccessor = null; POOL.release(this); } public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { return new ChunkData(chunkSections, heightmaps, lights); } private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); } private static LevelHeightAccessor createLevelHeightAccessor(int minY, int height) { return new LevelHeightAccessor() { @Override public int getHeight() { return height; } public int getMinBuildHeight() { return minY; } public int getMinY() { return minY; } }; } public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; private ChunkData(ChunkPos chunkPos) { this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); NMSUtilsVersioned.createChunkSections(serverLevel, levelHeightAccessor, this.chunkSections, dimension); ProtoChunk tempChunk = NMSUtilsVersioned.createProtoChunk( chunkPos, this.chunkSections, levelHeightAccessor, serverLevel); createHeightmaps(tempChunk); if (serverLevel != null) runCustomWorldGenerator(tempChunk); } private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } public LevelChunkSection[] chunkSections() { return this.chunkSections; } public Map heightmaps() { return this.heightmaps; } public List lights() { return this.lights; } private void runCustomWorldGenerator(ProtoChunk tempChunk) { ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, tempChunk); // We want to copy the level chunk sections back LevelChunkSection[] tempChunkSections = tempChunk.getSections(); for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { LevelChunkSection chunkSection = tempChunkSections[i]; if (chunkSection != null) this.chunkSections[i] = chunkSection; } } private void createHeightmaps(ProtoChunk tempChunk) { for (Heightmap.Types heightmapType : Heightmap.Types.values()) { if (${CHUNK_STATUS_CLASS}.FULL.heightmapsAfter().contains(heightmapType)) { this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); } } } } } ================================================ FILE: NMS/v1_12_R1/build.gradle ================================================ group 'NMS:v1_12_R1' dependencies { compileOnly "org.spigotmc:v1_12_R1-Paper:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('nms.compile_v1_12') && !Boolean.valueOf(project.findProperty("nms.compile_v1_12").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.EntityFallingBlock; import net.minecraft.server.v1_12_R1.EntityMinecartAbstract; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.IChatBaseComponent; import net.minecraft.server.v1_12_R1.Item; import net.minecraft.server.v1_12_R1.MinecraftKey; import net.minecraft.server.v1_12_R1.MinecraftServer; import net.minecraft.server.v1_12_R1.World; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_12_R1.CraftServer; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftFallingBlock; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecart; import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_12_R1.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.entity.FallingBlock; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; import java.lang.reflect.Field; import java.util.Locale; import java.util.Optional; public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); private final SuperiorSkyblockPlugin plugin; public NMSAlgorithmsImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public void registerCommand(BukkitCommand command) { ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); } @Override public String parseSignLine(String original) { return IChatBaseComponent.ChatSerializer.a(CraftChatMessage.fromString(original)[0]); } @Override public int getCombinedId(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); IBlockData blockData; try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { wrapper.getHandle().c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); blockData = world.getType(wrapper.getHandle()); } return Block.getCombinedId(blockData); } @Override public int getCombinedId(Material material, byte data) { //noinspection deprecation return material.getId() + (data << 12); } @Override public Optional getTileEntityIdFromCombinedId(int combinedId) { IBlockData blockData = Block.getByCombinedId(combinedId); if (!blockData.getBlock().isTileEntity()) return Optional.empty(); String id = BlockEntityCache.getTileEntityId(blockData); return Text.isBlank(id) ? Optional.empty() : Optional.of(id); } @Override public int compareMaterials(Material o1, Material o2) { return Integer.compare(o1.ordinal(), o2.ordinal()); } @Override public short getBlockDataValue(BlockState blockState) { return blockState.getRawData(); } @Override public short getBlockDataValue(org.bukkit.block.Block block) { return block.getData(); } @Override public short getMaxBlockDataValue(Material material) { return 0; } @Override public Key getBlockKey(int combinedId) { IBlockData blockData = Block.getByCombinedId(combinedId); return KeyBlocksCache.getBlockKey(blockData); } @Override public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { EntityMinecartAbstract minecart = ((CraftMinecart) bukkitMinecart).getHandle(); return KeyBlocksCache.getBlockKey(minecart.getDisplayBlock()); } @Override public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { EntityFallingBlock fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); return Optional.ofNullable(fallingBlock.getBlock()).map(KeyBlocksCache::getBlockKey).orElse(ConstantKeys.AIR); } @Override public void setCustomModel(ItemMeta itemMeta, int customModel) { // Doesn't exist } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { // Doesn't exist } @Override public void setRarity(ItemMeta itemMeta, String rarity) { // Doesn't exist } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { // Doesn't exist } @Override public void setHideTooltip(ItemMeta itemMeta) { // Doesn't exist } @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) potionMeta.setColor(potionEffect.getType().getColor()); potionMeta.addCustomEffect(potionEffect, true); } @Override public String getMinecraftKey(org.bukkit.inventory.ItemStack itemStack) { MinecraftKey minecraftKey = Item.REGISTRY.b(CraftItemStack.asNMSCopy(itemStack).getItem()); return minecraftKey == null ? "minecraft:air" : minecraftKey.toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override public int getMaxWorldSize() { MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); return server.getPropertyManager().getInt("max-world-size", 29999984); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public int getDataVersion() { return -1; } @Override public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { return defaultHolder; } @Override public Biome getBiome(String biomeName) { try { return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException e) { return null; } } private static Enchantment initializeGlowEnchantment() { int enchantId = 100; while (Enchantment.getById(enchantId) != null) ++enchantId; Enchantment glowEnchant = new Enchantment(enchantId) { @Override public String getName() { return "WildBusterGlow"; } @Override public int getMaxLevel() { return 1; } @Override public int getStartLevel() { return 0; } @Override public EnchantmentTarget getItemTarget() { return null; } @Override public boolean isTreasure() { return false; } @Override public boolean isCursed() { return false; } @Override public boolean conflictsWith(Enchantment enchantment) { return false; } @Override public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) { return true; } }; try { Field field = Enchantment.class.getDeclaredField("acceptingNew"); field.setAccessible(true); field.set(null, true); field.setAccessible(false); } catch (Exception ignored) { } try { Enchantment.registerEnchantment(glowEnchant); } catch (Exception ignored) { } return glowEnchant; } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSCachedBlock.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; public class NMSCachedBlock implements ICachedBlock { private static final ObjectsPool POOL = new ObjectsPool<>(NMSCachedBlock::new); private Material blockType; private byte blockData; public static NMSCachedBlock obtain(Block block) { return POOL.obtain().initialize(block); } private NMSCachedBlock() { } private NMSCachedBlock initialize(Block block) { this.blockType = block.getType(); this.blockData = block.getData(); return this; } @Override public void setBlock(Location location) { Block block = location.getWorld().getBlockAt(location); block.setType(blockType); block.setData(blockData); } @Override public void release() { this.blockType = null; POOL.release(this); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks.CropsTickingTileEntity; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks.EmptyCounterChunkSection; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_12_R1.BiomeBase; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockDoubleStep; import net.minecraft.server.v1_12_R1.BlockDoubleStepAbstract; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.Blocks; import net.minecraft.server.v1_12_R1.Chunk; import net.minecraft.server.v1_12_R1.ChunkCoordIntPair; import net.minecraft.server.v1_12_R1.ChunkSection; import net.minecraft.server.v1_12_R1.EntityHuman; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.MinecraftKey; import net.minecraft.server.v1_12_R1.PacketPlayOutMapChunk; import net.minecraft.server.v1_12_R1.PacketPlayOutUnloadChunk; import net.minecraft.server.v1_12_R1.PlayerConnection; import net.minecraft.server.v1_12_R1.TileEntity; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_12_R1.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_12_R1.util.UnsafeList; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl implements NMSChunks { private final SuperiorSkyblockPlugin plugin; public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); CropsTickingTileEntity.register(); } @Override public void setBiome(List chunkPositions, Biome biome, Collection playersToUpdate) { if (chunkPositions.isEmpty()) return; byte biomeBase = (byte) BiomeBase.REGISTRY_ID.a(CraftBlock.biomeToBiomeBase(biome)); NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { Arrays.fill(chunk.getBiomeIndex(), biomeBase); chunk.markDirty(); } @Override public void onUpdateChunk(Chunk chunk) { PacketPlayOutUnloadChunk unloadChunkPacket = new PacketPlayOutUnloadChunk(chunk.locX, chunk.locZ); PacketPlayOutMapChunk mapChunkPacket = new PacketPlayOutMapChunk(chunk, 65535); playersToUpdate.forEach(player -> { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(unloadChunkPacket); playerConnection.sendPacket(mapChunkPacket); }); } @Override public void onFinish() { // Do nothing. } }); } @Override public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { if (chunkPositions.isEmpty()) return; chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { Arrays.fill(chunk.getSections(), Chunk.a); removeEntities(chunk); removeTileEntities(chunk); removeBlocks(chunk); } @Override public void onUpdateChunk(Chunk chunk) { // Do nothing. } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }); } private static boolean isChunkSectionEmpty(ChunkSection chunkSection) { return chunkSection instanceof EmptyCounterChunkSection && ((EmptyCounterChunkSection) chunkSection).isEmpty(); } @Override public CompletableFuture> calculateChunks(List chunkPositions, Synchronized> unloadedChunksCache) { List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); Iterator chunkPositionsIterator = chunkPositions.iterator(); while (chunkPositionsIterator.hasNext()) { ChunkPosition chunkPosition = chunkPositionsIterator.next(); CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); if (cachedCalculatedChunk != null) { allCalculatedChunks.add(cachedCalculatedChunk); chunkPositionsIterator.remove(); } else { chunkPositionsToCalculate.add(chunkPosition); } } if (chunkPositions.isEmpty()) return CompletableFuture.completedFuture(allCalculatedChunks); CompletableFuture> completableFuture = new CompletableFuture<>(); NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { World bukkitWorld = chunk.world.getWorld(); ChunkPosition chunkPosition = ChunkPosition.of(bukkitWorld, chunk.locX, chunk.locZ, false); KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); List spawnersLocations = new LinkedList<>(); for (ChunkSection chunkSection : chunk.getSections()) { if (chunkSection != null && chunkSection != Chunk.a && !isChunkSectionEmpty(chunkSection)) { for (BlockPosition bp : BlockPosition.b(0, 0, 0, 15, 15, 15)) { IBlockData blockData = chunkSection.getType(bp.getX(), bp.getY(), bp.getZ()); Block block = blockData.getBlock(); if (block != Blocks.AIR) { Location location = new Location(bukkitWorld, (chunkPosition.getX() << 4) + bp.getX(), chunkSection.getYPosition() + bp.getY(), (chunkPosition.getZ() << 4) + bp.getZ()); int blockAmount = 1; if (block instanceof BlockDoubleStep) { blockAmount = 2; // Converts the block data to a regular slab MinecraftKey blockKey = Block.REGISTRY.b(block); blockData = Block.REGISTRY.get(new MinecraftKey(blockKey.getKey() .replace("double_", ""))).getBlockData() .set(BlockDoubleStepAbstract.VARIANT, blockData.get(BlockDoubleStepAbstract.VARIANT)); } Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockData), location); blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); if (block == Blocks.MOB_SPAWNER) { spawnersLocations.add(location); } } } } } CalculatedChunk.Blocks calculatedChunk = new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations); allCalculatedChunks.add(calculatedChunk); if (!isLoaded) unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); } @Override public void onUpdateChunk(Chunk chunk) { // Do nothing. } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }); return completableFuture; } @Override public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { if (chunkPositions.isEmpty()) return CompletableFuture.completedFuture(Collections.emptyList()); CompletableFuture> completableFuture = new CompletableFuture<>(); List allCalculatedChunks = new LinkedList<>(); NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); for (org.bukkit.entity.Entity bukkitEntity : chunk.bukkitChunk.getEntities()) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false); CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities); allCalculatedChunks.add(calculatedChunk); } @Override public void onUpdateChunk(Chunk chunk) { // Do nothing } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }); return completableFuture; } @Override public void injectChunkSections(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); for (int i = 0; i < 16; i++) chunk.getSections()[i] = EmptyCounterChunkSection.of(chunk.getSections()[i]); } @Override public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); return Arrays.stream(chunk.getSections()).allMatch(chunkSection -> chunkSection == null || chunkSection.a()); } @Override public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { Chunk chunk = ((CraftWorld) chunkPosition.getWorld()).getHandle().getChunkProviderServer() .getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); return chunk == null ? null : chunk.bukkitChunk; } @Override public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { if (chunkPositions.isEmpty()) return; CropsTickingTileEntity.forEachChunk(chunkPositions, cropsTickingTileEntity -> cropsTickingTileEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); } @Override public void shutdown() { List> pendingTasks = NMSUtils.getPendingChunkActions(); if (pendingTasks.isEmpty()) return; Log.info("Waiting for chunk tasks to complete."); CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); } @Override public List getBlockEntities(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); List blockEntities = new LinkedList<>(); World bukkitWorld = bukkitChunk.getWorld(); chunk.getTileEntities().keySet().forEach(blockPosition -> blockEntities.add(new Location(bukkitWorld, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()))); return blockEntities; } @Override public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) { if (plugin.getSettings().getCropsInterval() <= 0) return; if (stop) { CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove( chunk.getWorld().getName(), ChunkCoordIntPair.a(chunk.getX(), chunk.getZ())); if (cropsTickingTileEntity != null) cropsTickingTileEntity.getWorld().tileEntityListTick.remove(cropsTickingTileEntity); } else { CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle()); } } private static void removeEntities(Chunk chunk) { for (int i = 0; i < chunk.entitySlices.length; i++) { chunk.entitySlices[i].forEach(entity -> { if (!(entity instanceof EntityHuman)) entity.dead = true; }); chunk.entitySlices[i] = new UnsafeList<>(); } } private static void removeTileEntities(Chunk chunk) { chunk.tileEntities.forEach(((blockPosition, tileEntity) -> { chunk.world.tileEntityListTick.remove(tileEntity); chunk.world.capturedTileEntities.remove(blockPosition); })); chunk.tileEntities.clear(); } private static void removeBlocks(Chunk chunk) { WorldServer worldServer = (WorldServer) chunk.world; if (worldServer.generator != null && !(worldServer.generator instanceof IslandsGenerator)) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(worldServer, 0L, worldServer.generator); Chunk generatedChunk = customChunkGenerator.getOrCreateChunk(chunk.locX, chunk.locZ); for (int i = 0; i < 16; i++) chunk.getSections()[i] = generatedChunk.getSections()[i]; for (Map.Entry entry : generatedChunk.getTileEntities().entrySet()) worldServer.setTileEntity(entry.getKey(), entry.getValue()); } } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSDragonFightImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon.EndWorldEnderDragonBattleHandler; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon.IslandEnderDragonBattle; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon.IslandEntityEnderDragon; import net.minecraft.server.v1_12_R1.EnderDragonBattle; import net.minecraft.server.v1_12_R1.EntityTypes; import net.minecraft.server.v1_12_R1.MinecraftKey; import net.minecraft.server.v1_12_R1.WorldProviderTheEnd; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.advancement.Advancement; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.entity.EnderDragon; import org.bukkit.entity.Player; import java.lang.reflect.Modifier; public class NMSDragonFightImpl implements NMSDragonFight { private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( WorldProviderTheEnd.class, EnderDragonBattle.class, Modifier.PRIVATE, 1); static { EntityTypes.b.a(63, new MinecraftKey("ender_dragon"), IslandEntityEnderDragon.class); } @Override public void prepareEndWorld(World bukkitWorld) { WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); WORLD_DRAGON_BATTLE.set(worldServer.worldProvider, new EndWorldEnderDragonBattleHandler(worldServer)); } @Nullable @Override public EnderDragon getEnderDragon(Island island, Dimension dimension) { WorldServer worldServer = ((CraftWorld) island.getCenter(dimension).getWorld()).getHandle(); EnderDragonBattle worldEnderDragonBattle = ((WorldProviderTheEnd) worldServer.worldProvider).t(); if (!(worldEnderDragonBattle instanceof EndWorldEnderDragonBattleHandler)) return null; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldEnderDragonBattle; IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.getDragonBattle(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @Override public void startDragonBattle(Island island, Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return; WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); if (!(worldServer.worldProvider instanceof WorldProviderTheEnd)) return; EnderDragonBattle enderDragonBattle = ((WorldProviderTheEnd) worldServer.worldProvider).t(); if (!(enderDragonBattle instanceof EndWorldEnderDragonBattleHandler)) return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) enderDragonBattle; dragonBattleHandler.addDragonBattle(island.getCache(), new IslandEnderDragonBattle(island, worldServer, location)); } @Override public void removeDragonBattle(Island island, Dimension dimension) { World bukkitWorld = island.getCenter(dimension).getWorld(); if (bukkitWorld == null) return; WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); if (!(worldServer.worldProvider instanceof WorldProviderTheEnd)) return; EnderDragonBattle worldEnderDragonBattle = ((WorldProviderTheEnd) worldServer.worldProvider).t(); if (!(worldEnderDragonBattle instanceof EndWorldEnderDragonBattleHandler)) return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldEnderDragonBattle; IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.removeDragonBattle(island.getCache()); if (enderDragonBattle != null) { enderDragonBattle.removeBattlePlayers(); enderDragonBattle.getEnderDragon().die(); } } @Override public void awardTheEndAchievement(Player player) { Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); if (advancement != null) player.getAdvancementProgress(advancement).awardCriteria(""); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.server.v1_12_R1.Entity; import net.minecraft.server.v1_12_R1.EntityMinecartFurnace; import net.minecraft.server.v1_12_R1.Items; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>(Entity.class, int.class, "al"); private static final ReflectField MINECART_FURNACE_FUEL = new ReflectField<>( EntityMinecartFurnace.class, int.class, "d"); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { ItemStack[] itemStacks = new ItemStack[7]; itemStacks[0] = new ItemStack(Material.ARMOR_STAND); itemStacks[1] = entityEquipment.getItemInMainHand(); itemStacks[2] = entityEquipment.getItemInOffHand(); itemStacks[3] = entityEquipment.getHelmet(); itemStacks[4] = entityEquipment.getChestplate(); itemStacks[5] = entityEquipment.getLeggings(); itemStacks[6] = entityEquipment.getBoots(); return itemStacks; } @Override public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().e(CraftItemStack.asNMSCopy(itemStack)); } @Override public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { EntityMinecartFurnace minecartFurnace = (EntityMinecartFurnace) ((CraftMinecartFurnace) minecart).getHandle(); return MINECART_FURNACE_FUEL.get(minecartFurnace) + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).getItem() == Items.COAL; } @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSHologramsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import com.bgsoftware.superiorskyblock.nms.NMSHolograms; import net.minecraft.server.v1_12_R1.AxisAlignedBB; import net.minecraft.server.v1_12_R1.DamageSource; import net.minecraft.server.v1_12_R1.EntityArmorStand; import net.minecraft.server.v1_12_R1.EntityHuman; import net.minecraft.server.v1_12_R1.EnumHand; import net.minecraft.server.v1_12_R1.EnumInteractionResult; import net.minecraft.server.v1_12_R1.EnumItemSlot; import net.minecraft.server.v1_12_R1.ItemStack; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.SoundEffect; import net.minecraft.server.v1_12_R1.Vec3D; import net.minecraft.server.v1_12_R1.World; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftArmorStand; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; @SuppressWarnings("unused") public class NMSHologramsImpl implements NMSHolograms { @Override public Hologram createHologram(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); EntityHologram entityHologram = new EntityHologram(world, location.getX(), location.getY(), location.getZ()); world.addEntity(entityHologram); return entityHologram; } @Override public boolean isHologram(Entity entity) { return ((CraftEntity) entity).getHandle() instanceof Hologram; } public static class EntityHologram extends EntityArmorStand implements Hologram { EntityHologram(World world, double x, double y, double z) { super(world, x, y, z); setInvisible(true); setSmall(true); setArms(false); setNoGravity(true); setBasePlate(true); setMarker(true); super.collides = false; super.setCustomNameVisible(true); super.a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D)); } @Override public void setHologramName(String name) { super.setCustomName(name); } @Override public void removeHologram() { super.die(); } @Override public ArmorStand getHandle() { return this.getBukkitEntity(); } @Override public void inactiveTick() { // Disable normal ticking for this entity. // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. if (this.onGround) { this.onGround = false; } } @Override public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { // Prevent stand being equipped } @Override public boolean c(int i, ItemStack item) { // Prevent stand being equipped return false; } @Override public void b(NBTTagCompound nbttagcompound) { // Do not save NBT. } @Override public void a(NBTTagCompound nbttagcompound) { // Do not load NBT. } @Override public boolean isCollidable() { return false; } @Override public EnumInteractionResult a(EntityHuman human, Vec3D vec3d, EnumHand enumhand) { // Prevent stand being equipped return EnumInteractionResult.PASS; } @Override public void B_() { // Disable normal ticking for this entity. // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. if (this.onGround) { this.onGround = false; } } public void forceSetBoundingBox(AxisAlignedBB boundingBox) { super.a(boundingBox); } @Override public CraftArmorStand getBukkitEntity() { if (super.bukkitEntity == null) { super.bukkitEntity = new CraftArmorStand(super.world.getServer(), this); } return (CraftArmorStand) super.bukkitEntity; } @Override public void die() { // Prevent being killed. } @Override public void a(SoundEffect soundeffect, float f, float f1) { // Remove sounds. } @Override public boolean c(NBTTagCompound nbttagcompound) { // Do not save NBT. return false; } @Override public boolean d(NBTTagCompound nbttagcompound) { // Do not save NBT. return false; } @Override public NBTTagCompound save(NBTTagCompound nbttagcompound) { // Do not save NBT. return nbttagcompound; } @Override public void f(NBTTagCompound nbttagcompound) { // Do not load NBT. } @Override public boolean isInvulnerable(DamageSource source) { /* * The field Entity.invulnerable is private. * It's only used while saving NBTTags, but since the entity would be killed * on chunk unload, we prefer to override isInvulnerable(). */ return true; } @Override public void setCustomName(String customName) { // Locks the custom name. } @Override public void setCustomNameVisible(boolean visible) { // Locks the custom name. } @Override public void a(AxisAlignedBB boundingBox) { // Do not change it! } } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import net.minecraft.server.v1_12_R1.Entity; import net.minecraft.server.v1_12_R1.EntityItem; import net.minecraft.server.v1_12_R1.EntityPlayer; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftItem; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.Locale; import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { @Override public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { return OfflinePlayerDataImpl.create(offlinePlayer); } @Override public void setSkinTexture(SuperiorPlayer superiorPlayer) { superiorPlayer.runIfOnline(player -> { EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); Optional optional = entityPlayer.getProfile().getProperties().get("textures").stream().findFirst(); optional.ifPresent(property -> setSkinTexture(superiorPlayer, property)); }); } @Override public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { superiorPlayer.setTextureValue(property.getValue()); } @Override public void sendActionBar(Player player, String message) { //noinspection deprecation player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); } @Override public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); bossBar.addPlayer(player); return bossBar; } @Override public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); } @Override public boolean wasThrownByPlayer(org.bukkit.entity.Item item, SuperiorPlayer superiorPlayer) { Entity entity = ((CraftItem) item).getHandle(); return entity instanceof EntityItem && superiorPlayer.getName().equals(((EntityItem) entity).n()); } @Nullable @Override public Locale getPlayerLocale(Player player) { try { return PlayerLocales.getLocale(player.getLocale()); } catch (IllegalArgumentException error) { return null; } } private static class BossBarImpl implements BossBar { private final org.bukkit.boss.BossBar bossBar; private final BossBarTask bossBarTask; public BossBarImpl(String message, BarColor color, double ticksToRun) { bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); this.bossBarTask = BossBarTask.create(this, ticksToRun); } @Override public void addPlayer(Player player) { this.bossBar.addPlayer(player); this.bossBarTask.registerTask(player); } @Override public void removeAll() { this.bossBar.removeAll(); this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); } @Override public void setProgress(double progress) { this.bossBar.setProgress(progress); } @Override public double getProgress() { return this.bossBar.getProgress(); } } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.Tag; import net.minecraft.server.v1_12_R1.ChunkRegionLoader; import net.minecraft.server.v1_12_R1.ItemStack; import net.minecraft.server.v1_12_R1.MinecraftKey; import net.minecraft.server.v1_12_R1.NBTBase; import net.minecraft.server.v1_12_R1.NBTTagByte; import net.minecraft.server.v1_12_R1.NBTTagByteArray; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.NBTTagDouble; import net.minecraft.server.v1_12_R1.NBTTagFloat; import net.minecraft.server.v1_12_R1.NBTTagInt; import net.minecraft.server.v1_12_R1.NBTTagIntArray; import net.minecraft.server.v1_12_R1.NBTTagList; import net.minecraft.server.v1_12_R1.NBTTagLong; import net.minecraft.server.v1_12_R1.NBTTagShort; import net.minecraft.server.v1_12_R1.NBTTagString; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; import org.bukkit.entity.EntityType; import org.bukkit.event.entity.CreatureSpawnEvent; import java.util.Set; @SuppressWarnings({"unused"}) public class NMSTagsImpl implements NMSTags { @Override public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); NBTTagCompound tagCompound = itemStack.save(new NBTTagCompound()); return CompoundTag.fromNBT(tagCompound); } @Override public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { if (compoundTag.containsKey("NBT")) { // Old compound version, deserialize it accordingly return deserializeItemOld(compoundTag); } NBTTagCompound tagCompound = (NBTTagCompound) compoundTag.toNBT(); ItemStack itemStack = new ItemStack(tagCompound); return CraftItemStack.asCraftMirror(itemStack); } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); int amount = compoundTag.getInt("amount").orElse(0); short data = (short) compoundTag.getShort("data").orElse(0); CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); if (nbtData != null) itemStack.setTag((NBTTagCompound) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } @Override public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) { CraftWorld craftWorld = (CraftWorld) location.getWorld(); NBTTagCompound nbtTagCompound = (NBTTagCompound) compoundTag.toNBT(); if (nbtTagCompound == null) nbtTagCompound = new NBTTagCompound(); if (!nbtTagCompound.hasKey("id")) //noinspection deprecation nbtTagCompound.setString("id", new MinecraftKey(entityType.getName()).getKey()); ChunkRegionLoader.spawnEntity(nbtTagCompound, craftWorld.getHandle(), location.getX(), location.getY(), location.getZ(), true, CreatureSpawnEvent.SpawnReason.CUSTOM); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((NBTTagByteArray) object).c(); } @Override public byte getNBTByteValue(Object object) { return ((NBTTagByte) object).g(); } @Override public Set getNBTCompoundValue(Object object) { return ((NBTTagCompound) object).c(); } @Override public double getNBTDoubleValue(Object object) { return ((NBTTagDouble) object).asDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NBTTagFloat) object).i(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((NBTTagIntArray) object).d(); } @Override public int getNBTIntValue(Object object) { return ((NBTTagInt) object).e(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((NBTTagList) object).i(index); } @Override public long getNBTLongValue(Object object) { return ((NBTTagLong) object).d(); } @Override public short getNBTShortValue(Object object) { return ((NBTTagShort) object).f(); } @Override public String getNBTStringValue(Object object) { return ((NBTTagString) object).c_(); } @Override public Object parseList(ListTag listTag) { NBTTagList nbtTagList = new NBTTagList(); for (Tag tag : listTag) nbtTagList.add((NBTBase) tag.toNBT()); return nbtTagList; } @Override public Object getNBTCompoundTag(Object object, String key) { return ((NBTTagCompound) object).get(key); } @Override public void setNBTCompoundTagValue(Object object, String key, Object value) { ((NBTTagCompound) object).set(key, (NBTBase) value); } @Override public int getNBTTagListSize(Object object) { return ((NBTTagList) object).size(); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.google.common.collect.Maps; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.Chunk; import net.minecraft.server.v1_12_R1.ChunkProviderServer; import net.minecraft.server.v1_12_R1.ChunkSection; import net.minecraft.server.v1_12_R1.EntityHuman; import net.minecraft.server.v1_12_R1.EntityPlayer; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.IChunkLoader; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.Packet; import net.minecraft.server.v1_12_R1.PlayerChunkMap; import net.minecraft.server.v1_12_R1.TileEntity; import net.minecraft.server.v1_12_R1.World; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final ReflectField CHUNK_LOADER = new ReflectField<>( ChunkProviderServer.class, IChunkLoader.class, "chunkLoader"); private static final ReflectMethod SAVE_CHUNK = new ReflectMethod<>( IChunkLoader.class, "a", World.class, Chunk.class); private static final ReflectMethod TILE_ENTITY_LOAD = new ReflectMethod<>( TileEntity.class, "a", NBTTagCompound.class); private static final Map chunkLoadersMap = Maps.newConcurrentMap(); private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); public static final ObjectsPool> BLOCK_POS_POOL = ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0)); private NMSUtils() { } @Nullable public static T getTileEntityAt(Location location, Class type) { org.bukkit.World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return null; WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); TileEntity tileEntity = worldServer.getTileEntity(blockPosition); return !type.isInstance(tileEntity) ? null : type.cast(tileEntity); } } public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); } public static void runActionOnChunks(Collection chunksCoords, boolean saveChunks, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); } private static void runActionOnChunksInternal(Collection chunksCoords, ChunkCallback chunkCallback, Consumer> onUnloadChunkAction) { List unloadedChunks = new LinkedList<>(); List loadedChunks = new LinkedList<>(); chunksCoords.forEach(chunkPosition -> { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); Chunk chunk = worldServer.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); if (chunk != null) { loadedChunks.add(chunk); } else { unloadedChunks.add(chunkPosition.copy()); } }); boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); loadedChunks.forEach(loadedChunk -> { chunkCallback.onChunk(loadedChunk, true); chunkCallback.onUpdateChunk(loadedChunk); }); if (hasUnloadedChunks) { onUnloadChunkAction.accept(unloadedChunks); } else { chunkCallback.onFinish(); } } public static void runActionOnUnloadedChunks(Collection chunks, boolean saveChunks, ChunkCallback chunkCallback) { CompletableFuture pendingTask = new CompletableFuture<>(); PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); IChunkLoader chunkLoader = chunkLoadersMap.computeIfAbsent(worldServer.getDataManager().getUUID(), uuid -> CHUNK_LOADER.get(worldServer.getChunkProvider())); if (!chunkLoader.chunkExists(chunkPosition.getX(), chunkPosition.getZ())) return; try { Chunk loadedChunk = chunkLoader.a(worldServer, chunkPosition.getX(), chunkPosition.getZ()); if (loadedChunk != null) { chunkCallback.onChunk(loadedChunk, false); if (saveChunks) { if (SAVE_CHUNK.isValid()) SAVE_CHUNK.invoke(chunkLoader, worldServer, loadedChunk); else { chunkLoader.saveChunk(worldServer, loadedChunk, false); } } } } catch (Exception error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }).runSync(v -> { chunkCallback.onFinish(); pendingTask.complete(null); PENDING_CHUNK_ACTIONS.remove(pendingTask); }); } private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { } public static List> getPendingChunkActions() { return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); } public static void sendPacketToRelevantPlayers(WorldServer worldServer, int chunkX, int chunkZ, Packet packet) { PlayerChunkMap playerChunkMap = worldServer.getPlayerChunkMap(); for (EntityHuman entityHuman : worldServer.players) { if (entityHuman instanceof EntityPlayer && playerChunkMap.a((EntityPlayer) entityHuman, chunkX, chunkZ)) ((EntityPlayer) entityHuman).playerConnection.sendPacket(packet); } } public static void setBlock(Chunk chunk, BlockPosition blockPosition, int combinedId, CompoundTag tileEntity) { if (!isValidPosition(chunk.world, blockPosition)) return; IBlockData blockData = Block.getByCombinedId(combinedId); if (blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) { chunk.world.setTypeAndData(blockPosition, blockData, 3); return; } int blockX = blockPosition.getX() & 15; int blockY = blockPosition.getY(); int blockZ = blockPosition.getZ() & 15; int highestBlockLight = chunk.b(blockX, blockZ); boolean initLight = false; int indexY = blockY >> 4; ChunkSection chunkSection = chunk.getSections()[indexY]; if (chunkSection == null) { chunkSection = chunk.getSections()[indexY] = new ChunkSection(indexY << 4, chunk.world.worldProvider.m()); initLight = blockY > highestBlockLight; } chunkSection.setType(blockX, blockY & 15, blockZ, blockData); chunk.markDirty(); if (initLight) chunk.initLighting(); if (tileEntity != null) { NBTTagCompound tileEntityCompound = (NBTTagCompound) tileEntity.toNBT(); if (tileEntityCompound != null) { tileEntityCompound.setInt("x", blockPosition.getX()); tileEntityCompound.setInt("y", blockPosition.getY()); tileEntityCompound.setInt("z", blockPosition.getZ()); TileEntity worldTileEntity = chunk.world.getTileEntity(blockPosition); if (worldTileEntity != null) { if (TILE_ENTITY_LOAD.isValid()) TILE_ENTITY_LOAD.invoke(worldTileEntity, tileEntityCompound); else worldTileEntity.load(tileEntityCompound); } } } } private static boolean isValidPosition(World world, BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && blockPosition.getY() >= 0 && blockPosition.getY() < world.getHeight(); } public interface ChunkCallback { void onChunk(Chunk chunk, boolean isLoaded); void onUpdateChunk(Chunk chunk); void onFinish(); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import com.bgsoftware.superiorskyblock.nms.NMSWorld; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.spawners.MobSpawnerAbstractNotifier; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockDoubleStep; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.EnumParticle; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.IChatBaseComponent; import net.minecraft.server.v1_12_R1.MobSpawnerAbstract; import net.minecraft.server.v1_12_R1.PacketPlayOutBlockChange; import net.minecraft.server.v1_12_R1.PacketPlayOutWorldBorder; import net.minecraft.server.v1_12_R1.SoundCategory; import net.minecraft.server.v1_12_R1.SoundEffectType; import net.minecraft.server.v1_12_R1.SoundEffects; import net.minecraft.server.v1_12_R1.TileEntityMobSpawner; import net.minecraft.server.v1_12_R1.TileEntitySign; import net.minecraft.server.v1_12_R1.WorldBorder; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.block.CraftSign; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.material.MaterialData; import java.lang.reflect.Modifier; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { private static final ReflectField MOB_SPAWNER_ABSTRACT = new ReflectField( TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static boolean alreadyWarned = false; private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { try { return getBlockKeyInternal(chunkSnapshot, x, y, z); } catch (ArrayIndexOutOfBoundsException error) { return ConstantKeys.AIR; } } @SuppressWarnings("deprecation") private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { int blockId = chunkSnapshot.getBlockTypeId(x, y, z); int blockData = chunkSnapshot.getBlockData(x, y, z); int combinedId = blockId + (blockData << 12); Location location = new Location( Bukkit.getWorld(chunkSnapshot.getWorldName()), (chunkSnapshot.getX() << 4) + x, y, (chunkSnapshot.getZ() << 4) + z ); return Keys.of(KeyBlocksCache.getBlockKey(Block.getByCombinedId(combinedId)), location); } @Override public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) { try { return canPlayerSuffocateInternal(chunkSnapshot, x, y, z); } catch (ArrayIndexOutOfBoundsException error) { return true; } } @SuppressWarnings("deprecation") private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { int blockId = chunkSnapshot.getBlockTypeId(x, y, z); int blockData = chunkSnapshot.getBlockData(x, y, z); int combinedId = blockId + (blockData << 12); return Block.getByCombinedId(combinedId).r(); } @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); if (mobSpawner == null) return; MobSpawnerAbstract mobSpawnerAbstract = mobSpawner.getSpawner(); if (mobSpawnerAbstract instanceof MobSpawnerAbstractNotifier) return; MobSpawnerAbstractNotifier mobSpawnerAbstractNotifier = new MobSpawnerAbstractNotifier(mobSpawnerAbstract, delayChangeCallback); MOB_SPAWNER_ABSTRACT.set(mobSpawner, mobSpawnerAbstractNotifier); mobSpawnerAbstractNotifier.updateDelay(); } @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) return; Player player = superiorPlayer.asPlayer(); World world = superiorPlayer.getWorld(); if (world == null || player == null) return; int islandSize = island == null ? 0 : island.getIslandSize(); boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; WorldServer worldServer = ((CraftWorld) superiorPlayer.getWorld()).getHandle(); WorldBorder worldBorder; if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { worldBorder = worldServer.getWorldBorder(); } else { Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); if (dimension == null) return; Location center = island.getCenter(dimension); worldBorder = new WorldBorder(); worldBorder.world = worldServer; worldBorder.setWarningDistance(0); worldBorder.setCenter(center.getX(), center.getZ()); switch (superiorPlayer.getBorderColor()) { case BLUE: { worldBorder.setSize((islandSize * 2) + 1D); break; } case GREEN: { worldBorder.setSize((islandSize * 2) + 1.001D); worldBorder.transitionSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); break; } case RED: { worldBorder.setSize((islandSize * 2) + 1D); worldBorder.transitionSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); break; } } } PacketPlayOutWorldBorder packetPlayOutWorldBorder = new PacketPlayOutWorldBorder(worldBorder, PacketPlayOutWorldBorder.EnumWorldBorderAction.INITIALIZE); ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutWorldBorder); } @Override public Object getBlockData(org.bukkit.block.Block block) { throw new UnsupportedOperationException(); } @Override public void setBlock(Location location, int combinedId) { WorldServer world = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null); NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, new PacketPlayOutBlockChange(world, blockPosition)); } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } @Override public boolean isWaterLogged(org.bukkit.block.Block block) { Material blockType = block.getType(); return blockType == Material.WATER || blockType == Material.STATIONARY_WATER; } @Override public SignType getSignType(org.bukkit.block.Block block) { Material blockType = block.getType(); return blockType == Material.SIGN_POST ? SignType.STANDING_SIGN : blockType == Material.WALL_SIGN ? SignType.WALL_SIGN : SignType.UNKNOWN; } @Override public SignType getSignType(Object sign) { throw new UnsupportedOperationException("Not supported"); } @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); IBlockData blockData = worldServer.getType(blockPosition); return PistonPushReaction.values()[blockData.o().ordinal()]; } @Override public int getDefaultAmount(org.bukkit.block.Block block) { WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); IBlockData blockData = worldServer.getType(new BlockPosition(block.getX(), block.getY(), block.getZ())); return getDefaultAmount(blockData); } @Override public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { MaterialData materialData = bukkitBlockState.getData(); // noinspection deprecation int combinedId = materialData.getItemType().getId() + (materialData.getData() << 12); return getDefaultAmount(Block.getByCombinedId(combinedId)); } private int getDefaultAmount(IBlockData blockData) { Block nmsBlock = blockData.getBlock(); // Checks for double slabs if (nmsBlock instanceof BlockDoubleStep) { return 2; } return 1; } @Override public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { WorldServer worldServer = ((CraftWorld) bukkitBlock.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); return worldServer.getType(blockPosition).r(); } } @Override public void placeSign(Island island, Location location) { TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); if (tileEntitySign == null) return; String[] lines = new String[4]; System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); String[] strippedLines = new String[4]; for (int i = 0; i < 4; i++) strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); IChatBaseComponent[] newLines; IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); if (result.isCancelEvent()) { newLines = CraftSign.sanitizeLines(strippedLines); } else { newLines = CraftSign.sanitizeLines(lines); } System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } @Override public void playGeneratorSound(Location location) { WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); double x = location.getX(); double y = location.getY(); double z = location.getZ(); blockPosition.c(x, y, z); worldServer.a(null, blockPosition, SoundEffects.dE, SoundCategory.BLOCKS, 0.5F, 2.6F + (worldServer.random.nextFloat() - worldServer.random.nextFloat()) * 0.8F); for (int i = 0; i < 8; i++) { worldServer.addParticle(EnumParticle.SMOKE_LARGE, x + Math.random(), y + 1.2D, z + Math.random(), 0.0D, 0.0D, 0.0D); } } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(block.getX(), block.getY(), block.getZ()); worldServer.a(null, 2001, blockPosition, Block.getCombinedId(worldServer.getType(blockPosition))); } } @Override public void playPlaceSound(Location location) { WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); SoundEffectType soundEffectType = worldServer.getType(blockPosition).getBlock().getStepSound(); worldServer.a(null, blockPosition, soundEffectType.e(), SoundCategory.BLOCKS, (soundEffectType.a() + 1.0F) / 2.0F, soundEffectType.b() * 0.8F); } } @Override public int getMinHeight(World world) { return 0; } @Override public void removeAntiXray(World world) { // Doesn't exist in this version. } @Override public void setOceanLevel(World world) { ((CraftWorld) world).getHandle().b(plugin.getSettings().getWorlds().getSeaLevelHeight()); } @Override public IslandsGenerator createGenerator(Dimension dimension) { return new IslandsGeneratorImpl(dimension); } @Override public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } @Override public WorldEditSession createPartialEditSession(Dimension dimension) { return WorldEditSessionImpl.obtain(dimension); } @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } @Override public void listenBlockStateChanges(org.bukkit.World world) { if (!alreadyWarned) { Log.warn("This version is old and you may experience issues with block changes detection"); alreadyWarned = true; } } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.Chunk; import net.minecraft.server.v1_12_R1.ChunkCoordIntPair; import net.minecraft.server.v1_12_R1.ChunkSection; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.ITickable; import net.minecraft.server.v1_12_R1.TileEntity; import org.bukkit.craftbukkit.v1_12_R1.util.CraftMagicNumbers; import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; public class CropsTickingTileEntity extends TileEntity implements ITickable { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static Set CROPS_TO_GROW_CACHE; static { plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingTileEntity::onSettingsUpdate); } private static final Chunk2ObjectMap tickingChunks = new Chunk2ObjectMap<>(); private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; private final WeakReference chunk; private final int chunkX; private final int chunkZ; private int currentTick = 0; private double cachedCropGrowthMultiplier; public static void register() { // Calls the static initializer which registers the callback. } public static void create(Island island, String worldName, Chunk chunk) { long chunkKey = ChunkCoordIntPair.a(chunk.locX, chunk.locZ); tickingChunks.computeIfAbsent(worldName, chunkKey, () -> new CropsTickingTileEntity(island, chunk)); } public static CropsTickingTileEntity remove(String worldName, long chunkCoords) { return tickingChunks.remove(worldName, chunkCoords); } public static void forEachChunk(List chunkPositions, Consumer cropsTickingTileEntityConsumer) { if (tickingChunks.isEmpty()) return; chunkPositions.forEach(chunkPosition -> { long chunkKey = chunkPosition.asPair(); CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey); if (cropsTickingTileEntity != null) cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity); }); } private CropsTickingTileEntity(Island island, Chunk chunk) { this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(chunk); this.chunkX = chunk.locX; this.chunkZ = chunk.locZ; a(chunk.getWorld()); setPosition(new BlockPosition(chunkX << 4, 1, chunkZ << 4)); world.tileEntityListTick.add(this); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; } @Override public void e() { if (++currentTick <= plugin.getSettings().getCropsInterval()) return; Chunk chunk = this.chunk.get(); Island island = this.island.get(); if (chunk == null || island == null) { world.tileEntityListTick.remove(this); return; } currentTick = 0; int worldRandomTick = world.getGameRules().c("randomTickSpeed"); int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); if (chunkRandomTickSpeed > 0) { for (ChunkSection chunkSection : chunk.getSections()) { if (chunkSection != Chunk.a && chunkSection.shouldTick()) { for (int i = 0; i < chunkRandomTickSpeed; i++) { random = random * 3 + 1013904223; int factor = random >> 2; int x = factor & 15; int z = factor >> 8 & 15; int y = factor >> 16 & 15; IBlockData blockData = chunkSection.getType(x, y, z); Block block = blockData.getBlock(); if (block.isTicking() && CROPS_TO_GROW_CACHE.contains(block)) { block.a(world, new BlockPosition(x + (chunkX << 4), y + chunkSection.getYPosition(), z + (chunkZ << 4)), blockData, ThreadLocalRandom.current()); } } } } } } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { this.cachedCropGrowthMultiplier = cropGrowthMultiplier; } private static void onSettingsUpdate() { CROPS_TO_GROW_CACHE = new HashSet<>(); plugin.getSettings().getCropsToGrow().forEach(cropName -> { Key key = Keys.ofMaterialAndData(cropName); if (key instanceof MaterialKey) { Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial()); if (block != null && block.isTicking()) CROPS_TO_GROW_CACHE.add(block); } }); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/EmptyCounterChunkSection.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.Blocks; import net.minecraft.server.v1_12_R1.ChunkSection; import net.minecraft.server.v1_12_R1.DataPaletteBlock; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.NibbleArray; public class EmptyCounterChunkSection extends ChunkSection { private static final ReflectField NON_EMPTY_BLOCK_COUNT = new ReflectField<>(ChunkSection.class, int.class, "nonEmptyBlockCount"); private static final ReflectField TICKING_BLOCK_COUNT = new ReflectField<>(ChunkSection.class, int.class, "tickingBlockCount"); private static final ReflectField BLOCK_IDS = new ReflectField( ChunkSection.class, DataPaletteBlock.class, "blockIds").removeFinal(); private static final ReflectField EMITTED_LIGHT = new ReflectField<>(ChunkSection.class, NibbleArray.class, "emittedLight"); private static final ReflectField SKY_LIGHT = new ReflectField<>(ChunkSection.class, NibbleArray.class, "skyLight"); private int nonEmptyBlockCount; private int tickingBlockCount; private EmptyCounterChunkSection(ChunkSection chunkSection) { super(chunkSection.getYPosition(), chunkSection.getSkyLightArray() != null); nonEmptyBlockCount = NON_EMPTY_BLOCK_COUNT.get(chunkSection, 0); tickingBlockCount = TICKING_BLOCK_COUNT.get(chunkSection, 0); BLOCK_IDS.set(this, chunkSection.getBlocks()); EMITTED_LIGHT.set(this, chunkSection.getEmittedLightArray()); SKY_LIGHT.set(this, chunkSection.getSkyLightArray()); } public static EmptyCounterChunkSection of(ChunkSection chunkSection) { return chunkSection == null ? null : new EmptyCounterChunkSection(chunkSection); } @Override public void setType(int i, int j, int k, IBlockData iblockdata) { Block currentBlock = getType(i, j, k).getBlock(); Block placedBlock = iblockdata.getBlock(); if (currentBlock != Blocks.AIR) { nonEmptyBlockCount--; if (currentBlock.isTicking()) { tickingBlockCount--; } } if (placedBlock != Blocks.AIR) { nonEmptyBlockCount++; if (placedBlock.isTicking()) { tickingBlockCount++; } } super.setType(i, j, k, iblockdata); } @Override public boolean a() { return this.isEmpty(); } public boolean isEmpty() { return nonEmptyBlockCount == 0; } @Override public boolean shouldTick() { return tickingBlockCount > 0; } public void recalcBlockCounts() { nonEmptyBlockCount = 0; tickingBlockCount = 0; for (int i = 0; i < 16; ++i) { for (int j = 0; j < 16; ++j) { for (int k = 0; k < 16; ++k) { Block block = getType(i, j, k).getBlock(); if (block != Blocks.AIR) { nonEmptyBlockCount++; if (block.isTicking()) { tickingBlockCount++; } } } } } } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/DragonUtils.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.WorldGenEndTrophy; import java.lang.reflect.Modifier; public class DragonUtils { private static final ReflectField END_PODIUM_LOCATION = new ReflectField( WorldGenEndTrophy.class, BlockPosition.class, Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) .removeFinal(); private static BlockPosition currentPodiumPosition = BlockPosition.ZERO; private DragonUtils() { } public static void runWithPodiumPosition(BlockPosition podiumPosition, Runnable runnable) { try { END_PODIUM_LOCATION.set(null, podiumPosition); currentPodiumPosition = podiumPosition; runnable.run(); } finally { END_PODIUM_LOCATION.set(null, BlockPosition.ZERO); currentPodiumPosition = BlockPosition.ZERO; } } public static BlockPosition getCurrentPodiumPosition() { return currentPodiumPosition; } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/EndWorldEnderDragonBattleHandler.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.v1_12_R1.EnderDragonBattle; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.WorldServer; import java.util.LinkedList; import java.util.List; public class EndWorldEnderDragonBattleHandler extends EnderDragonBattle { private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_BATTLE", IslandEnderDragonBattle.class); private final List worldDragonBattlesList = new LinkedList<>(); public EndWorldEnderDragonBattleHandler(WorldServer worldServer) { super(worldServer, new NBTTagCompound()); } @Override public void b() { this.worldDragonBattlesList.forEach(EnderDragonBattle::b); } public void addDragonBattle(IslandCache islandCache, IslandEnderDragonBattle enderDragonBattle) { IslandEnderDragonBattle oldBattle = islandCache.store(CACHE_KEY, enderDragonBattle); if (oldBattle != null) this.worldDragonBattlesList.remove(oldBattle); this.worldDragonBattlesList.add(enderDragonBattle); } @Nullable public IslandEnderDragonBattle getDragonBattle(IslandCache islandCache) { return islandCache.get(CACHE_KEY); } @Nullable public IslandEnderDragonBattle removeDragonBattle(IslandCache islandCache) { IslandEnderDragonBattle enderDragonBattle = islandCache.remove(CACHE_KEY); if (enderDragonBattle != null) this.worldDragonBattlesList.remove(enderDragonBattle); return enderDragonBattle; } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEnderDragonBattle.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.google.common.collect.Sets; import net.minecraft.server.v1_12_R1.AxisAlignedBB; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.Blocks; import net.minecraft.server.v1_12_R1.BossBattleServer; import net.minecraft.server.v1_12_R1.CriterionTriggers; import net.minecraft.server.v1_12_R1.DamageSource; import net.minecraft.server.v1_12_R1.DragonControllerPhase; import net.minecraft.server.v1_12_R1.EnderDragonBattle; import net.minecraft.server.v1_12_R1.Entity; import net.minecraft.server.v1_12_R1.EntityEnderCrystal; import net.minecraft.server.v1_12_R1.EntityEnderDragon; import net.minecraft.server.v1_12_R1.EntityPlayer; import net.minecraft.server.v1_12_R1.EnumDragonRespawn; import net.minecraft.server.v1_12_R1.GameProfileSerializer; import net.minecraft.server.v1_12_R1.IDragonController; import net.minecraft.server.v1_12_R1.MathHelper; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.NBTTagInt; import net.minecraft.server.v1_12_R1.NBTTagList; import net.minecraft.server.v1_12_R1.Vec3D; import net.minecraft.server.v1_12_R1.WorldGenEndGateway; import net.minecraft.server.v1_12_R1.WorldGenEndTrophy; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Random; import java.util.Set; import java.util.UUID; public class IslandEnderDragonBattle extends EnderDragonBattle { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final ReflectField DRAGON_BATTLE = new ReflectField( EntityEnderDragon.class, EnderDragonBattle.class, Modifier.PRIVATE | Modifier.FINAL, 1) .removeFinal(); private static final ReflectField BATTLE_BOSS_SERVER = new ReflectField<>( EnderDragonBattle.class, BossBattleServer.class, Modifier.PRIVATE | Modifier.FINAL, 1); private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( EnderDragonBattle.class, boolean.class, Modifier.PRIVATE, 3); private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( EnderDragonBattle.class, boolean.class, Modifier.PRIVATE, 1); private static final Vec3D ORIGINAL_END_PODIUM = new Vec3D(0.5, 0, 0.5); private final Island island; private final BlockPosition islandBlockPosition; private final WorldServer worldServer; private final IslandEntityEnderDragon entityEnderDragon; private final BossBattleServer bossBattleServer; private final AxisAlignedBB borderArea; private final LinkedList gateways = new LinkedList<>(); private UUID dragonUUID; private BlockPosition exitPortalLocation; private EnumDragonRespawn respawnPhase; private List crystalsList; private int currentTick = 0; private int crystalsCountTick = 0; private int respawnTick = 0; private int crystalsCount = 0; private boolean dragonKilled = false; private boolean previouslyKilled = false; public IslandEnderDragonBattle(Island island, WorldServer worldServer, Location location) { this(island, worldServer, new BlockPosition(location.getX(), location.getY(), location.getZ()), null); } public IslandEnderDragonBattle(Island island, WorldServer worldServer, BlockPosition islandBlockPosition, @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { super(worldServer, new NBTTagCompound()); SCAN_FOR_LEGACY_PORTALS.set(this, false); WAS_DRAGON_KILLED.set(this, false); this.island = island; this.islandBlockPosition = islandBlockPosition; this.worldServer = worldServer; this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; this.bossBattleServer = BATTLE_BOSS_SERVER.get(this); int radius = plugin.getSettings().getMaxIslandSize(); this.borderArea = new AxisAlignedBB(islandBlockPosition.a(-radius, -radius, -radius), islandBlockPosition.a(radius, radius, radius)); DRAGON_BATTLE.set(this.entityEnderDragon, this); } @Override public NBTTagCompound a() { NBTTagCompound nbtTagCompound = new NBTTagCompound(); if (dragonUUID != null) { nbtTagCompound.a("Dragon", dragonUUID); } nbtTagCompound.setBoolean("DragonKilled", this.dragonKilled); nbtTagCompound.setBoolean("PreviouslyKilled", this.previouslyKilled); if (exitPortalLocation != null) { nbtTagCompound.set("ExitPortalLocation", GameProfileSerializer.a(exitPortalLocation)); } NBTTagList nbtTagList = new NBTTagList(); for (int gateway : this.gateways) nbtTagList.add(new NBTTagInt(gateway)); nbtTagCompound.set("Gateways", nbtTagList); return nbtTagCompound; } @Override public void b() { DragonUtils.runWithPodiumPosition(this.islandBlockPosition, this::doTick); IDragonController currentController = this.entityEnderDragon.getDragonControllerManager().a(); if (currentController != null && ORIGINAL_END_PODIUM.equals(currentController.g())) { currentController.d(); } } @Override public void a(EnumDragonRespawn dragonRespawn) { if (respawnPhase == null) throw new IllegalStateException("Dragon respawn isn't in progress, can't skip ahead in the animation."); respawnTick = 0; if (dragonRespawn != EnumDragonRespawn.END) { respawnPhase = dragonRespawn; } else { respawnPhase = null; dragonKilled = false; EntityEnderDragon entityEnderDragon = spawnEnderDragon(); for (EntityPlayer entityPlayer : this.bossBattleServer.getPlayers()) CriterionTriggers.m.a(entityPlayer, entityEnderDragon); } } @Override public void a(EntityEnderDragon entityEnderDragon) { if (!entityEnderDragon.getUniqueID().equals(dragonUUID)) return; this.bossBattleServer.setProgress(0.0F); this.bossBattleServer.setVisible(false); this.generateExitPortal(true); if (!gateways.isEmpty()) { int i = gateways.removeLast(); int j = MathHelper.floor(96.0D * Math.cos(2.0D * (-3.141592653589793D + 0.15707963267948966D * (double) i))); int k = MathHelper.floor(96.0D * Math.sin(2.0D * (-3.141592653589793D + 0.15707963267948966D * (double) i))); BlockPosition blockPosition = new BlockPosition(j, 75, k); this.worldServer.triggerEffect(3000, blockPosition, 0); new WorldGenEndGateway().generate(this.worldServer, new Random(), blockPosition); } if (!previouslyKilled) { this.worldServer.setTypeUpdate(this.worldServer.getHighestBlockYAt(islandBlockPosition), Blocks.DRAGON_EGG.getBlockData()); } previouslyKilled = true; dragonKilled = true; } @Override public void b(EntityEnderDragon entityEnderDragon) { if (!entityEnderDragon.getUniqueID().equals(dragonUUID)) return; this.bossBattleServer.setProgress(entityEnderDragon.getHealth() / entityEnderDragon.getMaxHealth()); if (entityEnderDragon.hasCustomName()) this.bossBattleServer.a(entityEnderDragon.getScoreboardDisplayName()); } @Override public int c() { return this.crystalsCount; } @Override public void a(EntityEnderCrystal entityEnderCrystal, DamageSource damageSource) { if (respawnPhase != null && crystalsList.contains(entityEnderCrystal)) { respawnPhase = null; respawnTick = 0; f(); generateExitPortal(true); } else { this.countCrystals(); Entity entity = this.worldServer.getEntity(dragonUUID); if (entity instanceof EntityEnderDragon) ((EntityEnderDragon) entity).a(entityEnderCrystal, entityEnderCrystal.getChunkCoordinates(), damageSource); } } @Override public boolean d() { return previouslyKilled; } @Override public void e() { if (!dragonKilled || respawnPhase != null) return; crystalsList = this.worldServer.a(EntityEnderCrystal.class, borderArea); respawnPhase = EnumDragonRespawn.START; respawnTick = 0; this.generateExitPortal(false); } @Override public void f() { for (EntityEnderCrystal entityEnderCrystal : this.worldServer.a(EntityEnderCrystal.class, borderArea)) { entityEnderCrystal.setInvulnerable(false); entityEnderCrystal.setBeamTarget(null); } } public void removeBattlePlayers() { this.bossBattleServer.getPlayers().forEach(this.bossBattleServer::removePlayer); } public IslandEntityEnderDragon getEnderDragon() { return this.entityEnderDragon; } private IslandEntityEnderDragon spawnEnderDragon() { IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.worldServer, islandBlockPosition); entityEnderDragon.getDragonControllerManager().setControllerPhase(DragonControllerPhase.a); entityEnderDragon.setPositionRotation(islandBlockPosition.getX(), 128, islandBlockPosition.getZ(), this.worldServer.random.nextFloat() * 360.0F, 0.0F); this.worldServer.addEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); this.dragonUUID = entityEnderDragon.getUniqueID(); //this.f(); // scan for crystals return entityEnderDragon; } private void doTick() { this.bossBattleServer.setVisible(!dragonKilled); // Update battle players if (++currentTick >= 20) { updateBattlePlayers(); currentTick = 0; } if (this.bossBattleServer.getPlayers().isEmpty()) { return; } if (respawnPhase != null) { if (crystalsList == null) { respawnPhase = null; e(); } if (++crystalsCountTick >= 100) { this.countCrystals(); crystalsCountTick = 0; } respawnPhase.a(this.worldServer, this, crystalsList, respawnTick++, exitPortalLocation); } } private void countCrystals() { this.crystalsCount = this.worldServer.a(EntityEnderCrystal.class, borderArea).size(); } private void generateExitPortal(boolean flag) { WorldGenEndTrophy worldGenEndTrophy = new WorldGenEndTrophy(flag); if (exitPortalLocation == null) { exitPortalLocation = this.worldServer.q(islandBlockPosition).down(); while (this.worldServer.getType(exitPortalLocation).getBlock() == Blocks.BEDROCK && exitPortalLocation.getY() > this.worldServer.getSeaLevel()) exitPortalLocation = exitPortalLocation.down(); } worldGenEndTrophy.generate(this.worldServer, new Random(), exitPortalLocation.up(2)); } private void updateBattlePlayers() { Set nearbyPlayers = Sets.newHashSet(); WorldInfo worldInfo = WorldInfo.of(this.worldServer.getWorld()); try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { strategy.getPlayers(worldInfo).forEach(player -> { EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); this.bossBattleServer.addPlayer(entityPlayer); nearbyPlayers.add(entityPlayer); }); } new HashSet<>(this.bossBattleServer.getPlayers()).stream() .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer)) .forEach(this.bossBattleServer::removePlayer); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.DifficultyDamageScaler; import net.minecraft.server.v1_12_R1.EnderDragonBattle; import net.minecraft.server.v1_12_R1.EntityEnderDragon; import net.minecraft.server.v1_12_R1.GroupDataEntity; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.World; import net.minecraft.server.v1_12_R1.WorldProviderTheEnd; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEnderDragon; public class IslandEntityEnderDragon extends EntityEnderDragon { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Dimension dimension; private BlockPosition islandBlockPosition; public IslandEntityEnderDragon(World world) { // Used when loading entities to the world. super(world); this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world.getWorld()); } public IslandEntityEnderDragon(WorldServer worldServer, BlockPosition islandBlockPosition) { this(worldServer); this.islandBlockPosition = islandBlockPosition; } @Nullable @Override public GroupDataEntity prepare(DifficultyDamageScaler difficultydamagescaler, @Nullable GroupDataEntity groupdataentity) { if (this.islandBlockPosition == null) finalizeIslandEnderDragon(); return super.prepare(difficultydamagescaler, groupdataentity); } @Override public void a(NBTTagCompound nbtTagCompound) { super.a(nbtTagCompound); finalizeIslandEnderDragon(); } @Override public void n() { DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::n); } @Override public CraftEnderDragon getBukkitEntity() { return (CraftEnderDragon) super.getBukkitEntity(); } private void finalizeIslandEnderDragon() { if (!(world.worldProvider instanceof WorldProviderTheEnd) || !plugin.getGrid().isIslandsWorld(world.getWorld())) return; EnderDragonBattle enderDragonBattle = ((WorldProviderTheEnd) world.worldProvider).t(); if (!(enderDragonBattle instanceof EndWorldEnderDragonBattleHandler)) return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) enderDragonBattle; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); } if (island == null) return; Location middleBlock = island.getCenter(dimension); SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); if (dimensionConfig instanceof SettingsManager.Worlds.End) { middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); } this.islandBlockPosition = new BlockPosition(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ()); IslandEnderDragonBattle dragonBattle = new IslandEnderDragonBattle(island, (WorldServer) world, this.islandBlockPosition, this); dragonBattleHandler.addDragonBattle(island.getCache(), dragonBattle); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/generator/IslandsGeneratorImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.generator; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_12_R1.BiomeBase; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_12_R1.block.CraftBlock; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random; @SuppressWarnings("unused") public class IslandsGeneratorImpl extends IslandsGenerator { private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( new ClassInfo("generator.CustomChunkGenerator$CustomBiomeGrid", ClassInfo.PackageType.CRAFTBUKKIT), BiomeBase[].class, "biome"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Dimension dimension; public IslandsGeneratorImpl(Dimension dimension) { this.dimension = dimension; } @Override public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) { ChunkData chunkData = createChunkData(world); Biome targetBiome = IslandUtils.getDefaultWorldBiome(this.dimension); setBiome(biomeGrid, targetBiome); if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { chunkData.setBlock(0, 99, 0, Material.BEDROCK); } return chunkData; } @Override public List getDefaultPopulators(World world) { return Collections.emptyList(); } @Override public Location getFixedSpawnLocation(World world, Random random) { return new Location(world, 0, 100, 0); } private static void setBiome(ChunkGenerator.BiomeGrid biomeGrid, Biome biome) { BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(biome); BiomeBase[] biomeBases = BIOME_BASE_ARRAY.get(biomeGrid); if (biomeBases == null) return; Arrays.fill(biomeBases, biomeBase); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/player/OfflinePlayerDataImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.player; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.mojang.authlib.GameProfile; import net.minecraft.server.v1_12_R1.EntityPlayer; import net.minecraft.server.v1_12_R1.MinecraftServer; import net.minecraft.server.v1_12_R1.PlayerInteractManager; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.craftbukkit.v1_12_R1.CraftServer; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.Optional; public class OfflinePlayerDataImpl implements OfflinePlayerData { private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); private Player fakePlayer; public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { return POOL.obtain().initialize(offlinePlayer); } private OfflinePlayerDataImpl() { } private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); WorldServer worldServer = server.getWorldServer(0); EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); this.fakePlayer = entityPlayer.getBukkitEntity(); this.fakePlayer.loadData(); return this; } @Override public Player getFakeOnlinePlayer() { return this.fakePlayer; } @Override public void setLocation(Location location) { EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle(); entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } @Override public void applyChanges() { this.fakePlayer.saveData(); } @Override public void release() { this.fakePlayer = null; POOL.release(this); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/spawners/MobSpawnerAbstractNotifier.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.spawners; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.MinecraftKey; import net.minecraft.server.v1_12_R1.MobSpawnerAbstract; import net.minecraft.server.v1_12_R1.MobSpawnerData; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.World; import java.util.function.IntFunction; public class MobSpawnerAbstractNotifier extends MobSpawnerAbstract { private final MobSpawnerAbstract mobSpawnerAbstract; private final IntFunction delayChangeCallback; public MobSpawnerAbstractNotifier(MobSpawnerAbstract mobSpawnerAbstract, IntFunction delayChangeCallback) { this.mobSpawnerAbstract = mobSpawnerAbstract; this.delayChangeCallback = delayChangeCallback; // Copy data from original spawner to this NBTTagCompound spawnerCompound = mobSpawnerAbstract.b(new NBTTagCompound()); this.a(spawnerCompound); } @Nullable @Override public MinecraftKey getMobName() { return mobSpawnerAbstract.getMobName(); } @Override public void setMobName(@Nullable MinecraftKey minecraftkey) { mobSpawnerAbstract.setMobName(minecraftkey); } @Override public void c() { int startDelay = mobSpawnerAbstract.spawnDelay; try { mobSpawnerAbstract.c(); } finally { int newDelay = mobSpawnerAbstract.spawnDelay; if (newDelay > startDelay) updateDelay(); } } @Override public void a(NBTTagCompound nbttagcompound) { mobSpawnerAbstract.a(nbttagcompound); } @Override public NBTTagCompound b(NBTTagCompound nbttagcompound) { return mobSpawnerAbstract.b(nbttagcompound); } @Override public boolean b(int i) { return mobSpawnerAbstract.b(i); } @Override public void a(MobSpawnerData mobspawnerdata) { mobSpawnerAbstract.a(mobspawnerdata); } @Override public void a(int i) { mobSpawnerAbstract.a(i); } @Override public World a() { return mobSpawnerAbstract.a(); } @Override public BlockPosition b() { return mobSpawnerAbstract.b(); } public void updateDelay() { mobSpawnerAbstract.spawnDelay = delayChangeCallback.apply(mobSpawnerAbstract.spawnDelay); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/BlockEntityCache.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.ITileEntity; import net.minecraft.server.v1_12_R1.MinecraftServer; import net.minecraft.server.v1_12_R1.TileEntity; import net.minecraft.server.v1_12_R1.World; import java.util.IdentityHashMap; import java.util.Map; public class BlockEntityCache { private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); private BlockEntityCache() { } public static String getTileEntityId(IBlockData blockData) { return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> { if (block instanceof ITileEntity) { World world = MinecraftServer.getServer().getWorld(); TileEntity tileEntity = ((ITileEntity) block).a(world, block.toLegacyData(blockData)); if (tileEntity != null) return tileEntity.getMinecraftKeyString(); } return ""; }); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.NMSUtils; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.Chunk; import net.minecraft.server.v1_12_R1.ChunkSection; import net.minecraft.server.v1_12_R1.DataPaletteBlock; import net.minecraft.server.v1_12_R1.Entity; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.NBTTagFloat; import net.minecraft.server.v1_12_R1.NibbleArray; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity; import org.bukkit.entity.EntityType; import org.bukkit.inventory.InventoryHolder; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class ChunkReaderImpl implements ChunkReader { private static final short[] EMPTY_BLOCKS = new short[4096]; private static final byte[] EMPTY_DATA = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; private final int x; private final int z; private final Map tileEntities = new HashMap<>(); private final List entities = new LinkedList<>(); private final short[][] blockids; private final byte[][] blockdata; private final byte[][] skylight; private final byte[][] emitlight; public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); this.x = chunk.locX; this.z = chunk.locZ; ChunkSection[] chunkSections = chunk.getSections(); this.blockids = new short[chunkSections.length][]; this.blockdata = new byte[chunkSections.length][]; this.skylight = new byte[chunkSections.length][]; this.emitlight = new byte[chunkSections.length][]; for (int i = 0; i < this.blockids.length; ++i) { ChunkSection chunkSection = chunkSections[i]; if (chunkSection == null) { this.blockids[i] = EMPTY_BLOCKS; this.blockdata[i] = EMPTY_DATA; this.skylight[i] = EMPTY_LIGHT; this.emitlight[i] = EMPTY_LIGHT; } else { copyBlockIds(chunkSection.getBlocks(), i); if (chunkSection.getSkyLightArray() == null) { skylight[i] = EMPTY_LIGHT; } else { skylight[i] = new byte[2048]; System.arraycopy(chunkSection.getSkyLightArray().asBytes(), 0, skylight[i], 0, 2048); } emitlight[i] = new byte[2048]; System.arraycopy(chunkSection.getEmittedLightArray().asBytes(), 0, emitlight[i], 0, 2048); } } chunk.getTileEntities().forEach((blockPosition, tileEntity) -> { NBTTagCompound tileEntityCompound = tileEntity.save(new NBTTagCompound()); tileEntityCompound.remove("x"); tileEntityCompound.remove("y"); tileEntityCompound.remove("z"); InventoryHolder inventoryHolder = tileEntity.getOwner(); if (inventoryHolder != null) tileEntityCompound.setString("inventoryType", inventoryHolder.getInventory().getType().name()); tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound)); }); for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); } @Override public int getX() { return this.x; } @Override public int getZ() { return this.z; } @Override public Material getType(int x, int y, int z) { return Material.getMaterial(this.getBlockId(x, y, z)); } @Override public short getData(int x, int y, int z) { int off = (y & 15) << 7 | z << 3 | x >> 1; return (short) (this.blockdata[y >> 4][off] >> ((x & 1) << 2) & 15); } @Override @Nullable public CompoundTag getTileEntity(int x, int y, int z) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c((this.x << 4) + x, y, (this.z << 4) + z); return this.tileEntities.get(blockPosition); } } @Override @Nullable public CompoundTag readBlockStates(int x, int y, int z) { // Doesn't exist return null; } @Override public byte[] getLightLevels(int x, int y, int z) { int off = (y & 15) << 7 | z << 3 | x >> 1; int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15; int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15; return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; } @Override public void forEachEntity(EntityConsumer consumer) { if (entities.isEmpty()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = wrapper.getHandle(); for (CachedEntity cachedEntity : entities) { location.setX(cachedEntity.x); location.setY(cachedEntity.y); location.setZ(cachedEntity.z); location.setYaw(cachedEntity.yaw); location.setPitch(cachedEntity.pitch); consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); } } } private int getBlockId(int x, int y, int z) { return this.blockids[y >> 4][(y & 15) << 8 | z << 4 | x]; } private void copyBlockIds(DataPaletteBlock palette, int i) { byte[] rawIds = new byte[4096]; NibbleArray data = new NibbleArray(); palette.exportData(rawIds, data); short[] blockids = this.blockids[i] = new short[4096]; this.blockdata[i] = data.asBytes(); for (int j = 0; j < 4096; ++j) { blockids[j] = (short) (rawIds[j] & 255); } } private static class CachedEntity { private final double x; private final double y; private final double z; private final float yaw; private final float pitch; private final EntityType entityType; private final CompoundTag entityTag; CachedEntity(Entity entity) { this.x = entity.locX; this.y = entity.locY; this.z = entity.locZ; this.yaw = entity.yaw; this.pitch = entity.pitch; this.entityType = entity.getBukkitEntity().getType(); NBTTagCompound nbtTagCompound = new NBTTagCompound(); entity.c(nbtTagCompound); nbtTagCompound.set("Yaw", new NBTTagFloat(entity.yaw)); nbtTagCompound.set("Pitch", new NBTTagFloat(entity.pitch)); this.entityTag = CompoundTag.fromNBT(nbtTagCompound); } } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/KeyBlocksCache.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.key.Keys; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.IBlockData; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.util.CraftMagicNumbers; import java.util.IdentityHashMap; import java.util.Map; public class KeyBlocksCache { private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); private KeyBlocksCache() { } public static Key getBlockKey(IBlockData blockData) { return BLOCK_TO_KEY.computeIfAbsent(blockData, unused -> { Block block = blockData.getBlock(); Material blockType = CraftMagicNumbers.getMaterial(block); if (blockType == null) return null; byte data = (byte) block.toLegacyData(blockData); return Keys.of(blockType, data); }); } public static void cacheAllBlocks() { Block.REGISTRY_ID.forEach(KeyBlocksCache::getBlockKey); } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionDataImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.ChunkCoordIntPair; import net.minecraft.server.v1_12_R1.IBlockData; import org.bukkit.Location; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class WorldEditSessionDataImpl implements WorldEditSession.Data { private final List> chunks = new LinkedList<>(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List> lights = new LinkedList<>(); public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, List> blocksToUpdate, List> blockEntities, List lights) { int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); int baseChunkPosXAxis = baseBlockPosXAxis >> 4; int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // Convert chunk data Iterator> chunksIterator = chunks.entryIterator(); while (chunksIterator.hasNext()) { Long2ObjectMapView.Entry entry = chunksIterator.next(); int currChunkPosXAxis = getChunkCoordX(entry.getKey()); int currChunkPosZAxis = getChunkCoordZ(entry.getKey()); this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, currChunkPosZAxis - baseChunkPosZAxis, entry.getValue())); } // Convert blocksToUpdate blocksToUpdate.forEach(blockToUpdate -> { BlockPosition blockPosition = blockToUpdate.getKey(); this.blocksToUpdate.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis, blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis, blockToUpdate.getValue())); }); // Convert blockEntities blockEntities.forEach(blockEntity -> { BlockPosition blockPosition = blockEntity.getKey(); this.blockEntities.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis, blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis, blockEntity.getValue())); }); // Convert lights lights.forEach(lightPosition -> { this.lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, null)); }); } public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, Long2ObjectMapView chunks) { this.chunks.forEach(chunkDataPositioned -> { long newPos = ChunkCoordIntPair.a(baseChunkPosXAxis + chunkDataPositioned.xOffset, baseChunkPosZAxis + chunkDataPositioned.zOffset); chunks.put(newPos, chunkDataPositioned.object); }); } public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { this.blocksToUpdate.forEach(blockToUpdatePositioned -> { BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, baseBlockPosYAxis + blockToUpdatePositioned.yOffset, baseBlockPosZAxis + blockToUpdatePositioned.zOffset); blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); }); } public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { this.blockEntities.forEach(blockEntityPositioned -> { BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset, baseBlockPosYAxis + blockEntityPositioned.yOffset, baseBlockPosZAxis + blockEntityPositioned.zOffset); blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); }); } public void readLights(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List lights) { this.lights.forEach(lightPositioned -> { BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset, baseBlockPosYAxis + lightPositioned.yOffset, baseBlockPosZAxis + lightPositioned.zOffset); lights.add(newPos); }); } private static int getChunkCoordX(long i) { return (int) (i & 4294967295L); } private static int getChunkCoordZ(long i) { return (int) (i >>> 32 & 4294967295L); } private static class PositionedObject { private final int xOffset; private final int yOffset; private final int zOffset; private final V object; PositionedObject(int xOffset, int zOffset, V object) { this(xOffset, 0, zOffset, object); } PositionedObject(int xOffset, int yOffset, int zOffset, V object) { this.xOffset = xOffset; this.yOffset = yOffset; this.zOffset = zOffset; this.object = object; } } } ================================================ FILE: NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.chunks.EmptyCounterChunkSection; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.google.common.base.Preconditions; import net.minecraft.server.v1_12_R1.BiomeBase; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockBed; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.Chunk; import net.minecraft.server.v1_12_R1.ChunkCoordIntPair; import net.minecraft.server.v1_12_R1.ChunkSection; import net.minecraft.server.v1_12_R1.EnumSkyBlock; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.PacketPlayOutMapChunk; import net.minecraft.server.v1_12_R1.TileEntity; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; import org.bukkit.craftbukkit.v1_12_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_12_R1.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class WorldEditSessionImpl implements WorldEditSession { private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); private static final ReflectMethod TILE_ENTITY_LOAD = new ReflectMethod<>(TileEntity.class, "a", NBTTagCompound.class); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List lights = new LinkedList<>(); private Dimension dimension; @Nullable private WorldServer worldServer; public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } public static WorldEditSessionImpl obtain(Dimension dimension) { return POOL.obtain().initialize(dimension); } private WorldEditSessionImpl() { } private WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); return this; } private WorldEditSessionImpl initialize(Dimension dimension) { this.worldServer = null; this.dimension = dimension; return this; } @Override public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData) { BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); if (!isValidPosition(blockPosition)) return; IBlockData blockData = Block.getByCombinedId(combinedId); if ((blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || blockData.getBlock() instanceof BlockBed) { blocksToUpdate.add(new Pair<>(blockPosition, blockData)); return; } ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(blockPosition); if (blockEntityData != null) blockEntities.add(new Pair<>(blockPosition, blockEntityData)); if (plugin.getSettings().isLightsUpdate() && blockData.d() > 0) lights.add(blockPosition); ChunkData chunkData = this.chunks.computeIfAbsent(ChunkCoordIntPair.a(chunkCoord.x, chunkCoord.z), ChunkData::new); ChunkSection chunkSection = chunkData.chunkSections[blockPosition.getY() >> 4]; int blockX = blockPosition.getX() & 15; int blockY = blockPosition.getY(); int blockZ = blockPosition.getZ() & 15; chunkSection.setType(blockX, blockY & 15, blockZ, blockData); } @Override public List getAffectedChunks() { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); if (chunks.isEmpty()) return Collections.emptyList(); List chunkPositions = new LinkedList<>(); World bukkitWorld = worldServer.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); int chunkX = (int) chunkKey; int chunkZ = (int) (chunkKey >> 32); chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkData chunkData = this.chunks.get(chunk.chunkKey); if (chunkData == null) return; int chunkSectionsCount = Math.min(chunkData.chunkSections.length, chunk.getSections().length); for (int i = 0; i < chunkSectionsCount; ++i) { chunk.getSections()[i] = chunkData.chunkSections[i]; } // Update the biome for the chunk BiomeBase biome = CraftBlock.biomeToBiomeBase(IslandUtils.getDefaultWorldBiome(this.dimension)); Arrays.fill(chunk.getBiomeIndex(), (byte) BiomeBase.REGISTRY_ID.a(biome)); if (plugin.getSettings().isLightsUpdate()) { // initLightning calculates the light emitted from sky to the chunk. chunk.initLighting(); } chunk.markDirty(); } @Override public void finish(Island island) { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); // Update block entities blockEntities.forEach(data -> { NBTTagCompound blockEntityCompound = (NBTTagCompound) data.getValue().toNBT(); if (blockEntityCompound != null) { BlockPosition blockPosition = data.getKey(); blockEntityCompound.setInt("x", blockPosition.getX()); blockEntityCompound.setInt("y", blockPosition.getY()); blockEntityCompound.setInt("z", blockPosition.getZ()); TileEntity worldTileEntity = worldServer.getTileEntity(blockPosition); if (worldTileEntity != null) { if (TILE_ENTITY_LOAD.isValid()) { TILE_ENTITY_LOAD.invoke(worldTileEntity, blockEntityCompound); } else { worldTileEntity.load(blockEntityCompound); } } } }); if (plugin.getSettings().isLightsUpdate() && !lights.isEmpty()) { // For each light block, we calculate its light // We only update the lights after all the chunks were loaded. BukkitExecutor.sync(() -> { lights.forEach(blockPosition -> worldServer.c(EnumSkyBlock.BLOCK, blockPosition)); LongIterator iterator = this.chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); NMSUtils.sendPacketToRelevantPlayers(worldServer, chunkCoord.x, chunkCoord.z, new PacketPlayOutMapChunk(worldServer.getChunkAt(chunkCoord.x, chunkCoord.z), 65535)); } }, 5L); } release(); } @Override public Data readData(Location baseLocation) { return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lights); } @Override public void applyData(Data data, Location baseLocation) { WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); int baseChunkPosXAxis = baseBlockPosXAxis >> 4; int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, this.chunks); dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); dataImpl.readLights(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.lights); } @Override public void release() { this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lights.clear(); this.worldServer = null; this.dimension = null; POOL.release(this); } private boolean isValidPosition(BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && blockPosition.getY() >= 0 && blockPosition.getY() < 256; } public class ChunkData { private final ChunkSection[] chunkSections = new ChunkSection[16]; private ChunkData(long chunkKey) { ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); createChunkSections(); if (worldServer != null) runCustomWorldGenerator(chunkCoord); } private void createChunkSections() { boolean hasSkyLight = dimension.getEnvironment() != World.Environment.THE_END; for (int i = 0; i < this.chunkSections.length; ++i) { int chunkSectionPos = i << 4; this.chunkSections[i] = EmptyCounterChunkSection.of(new ChunkSection(chunkSectionPos, hasSkyLight)); } } private void runCustomWorldGenerator(ChunkCoordIntPair chunkCoord) { ChunkGenerator bukkitGenerator = worldServer.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(worldServer, worldServer.getSeed(), bukkitGenerator); Chunk generatedChunk = chunkGenerator.getOrCreateChunk(chunkCoord.x, chunkCoord.z); for (int i = 0; i < this.chunkSections.length; ++i) { ChunkSection generatorChunkSection = generatedChunk.getSections()[i]; if (generatorChunkSection != null && generatorChunkSection != Chunk.a) this.chunkSections[i] = generatorChunkSection; } } } } ================================================ FILE: NMS/v1_16_R3/build.gradle ================================================ group 'NMS:v1_16_R3' dependencies { compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('nms.compile_v1_16') && !Boolean.valueOf(project.findProperty("nms.compile_v1_16").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityBrewing; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityDispenser; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityFurnace; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityHopper; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import io.papermc.paper.chat.ChatComposer; import io.papermc.paper.event.player.AsyncChatEvent; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.EntityFallingBlock; import net.minecraft.server.v1_16_R3.EntityMinecartAbstract; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.IChatBaseComponent; import net.minecraft.server.v1_16_R3.IInventory; import net.minecraft.server.v1_16_R3.IRegistry; import net.minecraft.server.v1_16_R3.MinecraftServer; import net.minecraft.server.v1_16_R3.World; import org.bukkit.block.Biome; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_16_R3.CraftServer; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftFallingBlock; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftMinecart; import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.lang.reflect.Field; import java.util.EnumMap; import java.util.Locale; import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuTileEntityDispenser::new); MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuTileEntityDispenser::new); MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuTileEntityFurnace::new); MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuTileEntityBrewing::new); MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuTileEntityHopper::new); MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuTileEntityFurnace::new); MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuTileEntityFurnace::new); } private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { @Override public byte[] processClass(byte[] classBytes, String path) { return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); } }; @Override public void registerCommand(BukkitCommand command) { ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); } @Override public String parseSignLine(String original) { return IChatBaseComponent.ChatSerializer.a(CraftChatMessage.fromString(original)[0]); } @Override public int getCombinedId(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); IBlockData blockData; try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { wrapper.getHandle().d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); blockData = world.getType(wrapper.getHandle()); } return Block.getCombinedId(blockData); } @Override public int getCombinedId(Material material, byte data) { IBlockData blockData; if (data == 0) { Block block = CraftMagicNumbers.getBlock(material); if (block == null) return -1; blockData = block.getBlockData(); } else { blockData = CraftMagicNumbers.getBlock(material, data); } return blockData == null ? -1 : Block.getCombinedId(blockData); } @Override public Optional getTileEntityIdFromCombinedId(int combinedId) { IBlockData blockData = Block.getByCombinedId(combinedId); if (!blockData.getBlock().isTileEntity()) return Optional.empty(); String id = BlockEntityCache.getTileEntityId(blockData); return Text.isBlank(id) ? Optional.empty() : Optional.of(id); } @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getCombinedId(CraftMagicNumbers.getBlock(o1).getBlockData()) : o1.ordinal(); int secondMaterial = o2.isBlock() ? Block.getCombinedId(CraftMagicNumbers.getBlock(o2).getBlockData()) : o2.ordinal(); return Integer.compare(firstMaterial, secondMaterial); } @Override public short getBlockDataValue(BlockState blockState) { BlockData blockData = blockState.getBlockData(); return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); } @Override public short getBlockDataValue(org.bukkit.block.Block block) { BlockData blockData = block.getBlockData(); return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); } @Override public short getMaxBlockDataValue(Material material) { if (!material.isBlock()) return 0; BlockData blockData = Bukkit.createBlockData(material); return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); } @Override public Key getBlockKey(int combinedId) { Block block = Block.getByCombinedId(combinedId).getBlock(); return KeyBlocksCache.getBlockKey(block); } @Override public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { EntityMinecartAbstract minecart = ((CraftMinecart) bukkitMinecart).getHandle(); Block block = minecart.getDisplayBlock().getBlock(); return KeyBlocksCache.getBlockKey(block); } @Override public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { EntityFallingBlock fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); Block block = fallingBlock.getBlock().getBlock(); return KeyBlocksCache.getBlockKey(block); } @Override public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { // Doesn't exist } @Override public void setRarity(ItemMeta itemMeta, String rarity) { // Doesn't exist } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { // Doesn't exist } @Override public void setHideTooltip(ItemMeta itemMeta) { // Doesn't exist } @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) potionMeta.setColor(potionEffect.getType().getColor()); potionMeta.addCustomEffect(potionEffect, true); } @Override public String getMinecraftKey(ItemStack itemStack) { return IRegistry.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override public int getMaxWorldSize() { return Bukkit.getMaxWorldSize(); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public int getDataVersion() { return CraftMagicNumbers.INSTANCE.getDataVersion(); } @Override public ClassProcessor getClassProcessor() { return CLASS_PROCESSOR; } @Override public void handlePaperChatRenderer(Object event) { if (!(event instanceof AsyncChatEvent)) return; ChatComposer originalComposer = ((AsyncChatEvent) event).composer(); ((AsyncChatEvent) event).composer(new ChatComposerWrapper(originalComposer).composer); } @Override public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); } @Override public Biome getBiome(String biomeName) { try { return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException e) { return null; } } private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; try { glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); } catch (Throwable error) { glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); } try { Field field = Enchantment.class.getDeclaredField("acceptingNew"); field.setAccessible(true); field.set(null, true); field.setAccessible(false); } catch (Exception ignored) { } try { Enchantment.registerEnchantment(glowEnchant); } catch (Exception ignored) { } return glowEnchant; } private interface MenuCreator extends BiFunction { } private static class ChatComposerWrapper { private final ChatComposer composer = new ChatComposer() { @Override public @NotNull Component composeChat(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message) { String originalFormat = LegacyComponentSerializer.legacyAmpersand().serialize( originalComposer.composeChat(source, sourceDisplayName, message)); SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); Island island = superiorPlayer.getIsland(); return LegacyComponentSerializer.legacyAmpersand().deserialize( Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))); } }; private final ChatComposer originalComposer; public ChatComposerWrapper(ChatComposer originalComposer) { this.originalComposer = originalComposer; } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops.CropsTickingTileEntity; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_16_R3.BiomeBase; import net.minecraft.server.v1_16_R3.BiomeStorage; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockPropertySlabType; import net.minecraft.server.v1_16_R3.BlockStepAbstract; import net.minecraft.server.v1_16_R3.Blocks; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; import net.minecraft.server.v1_16_R3.ChunkSection; import net.minecraft.server.v1_16_R3.Entity; import net.minecraft.server.v1_16_R3.EntityHuman; import net.minecraft.server.v1_16_R3.EntityTypes; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.IRegistry; import net.minecraft.server.v1_16_R3.LightEngineThreaded; import net.minecraft.server.v1_16_R3.NBTBase; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.NBTTagList; import net.minecraft.server.v1_16_R3.PacketPlayOutLightUpdate; import net.minecraft.server.v1_16_R3.PacketPlayOutMapChunk; import net.minecraft.server.v1_16_R3.PacketPlayOutUnloadChunk; import net.minecraft.server.v1_16_R3.PlayerConnection; import net.minecraft.server.v1_16_R3.ProtoChunk; import net.minecraft.server.v1_16_R3.TagsBlock; import net.minecraft.server.v1_16_R3.TileEntity; import net.minecraft.server.v1_16_R3.World; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Location; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_16_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_16_R3.util.CraftNamespacedKey; import org.bukkit.craftbukkit.v1_16_R3.util.UnsafeList; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.function.Function; public class NMSChunksImpl implements NMSChunks { private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( BiomeStorage.class, BiomeBase[].class, "h"); private static final ReflectField[]> ENTITY_SLICE_ARRAY = new ReflectField<>( Chunk.class, null, "entitySlices"); private final SuperiorSkyblockPlugin plugin; public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); CropsTickingMethod.register(); } @Override public void setBiome(List chunkPositions, Biome biome, Collection playersToUpdate) { if (chunkPositions.isEmpty()) return; NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(Chunk chunk) { ChunkCoordIntPair chunkCoords = chunk.getPos(); BiomeBase[] biomeBases = BIOME_BASE_ARRAY.get(chunk.getBiomeIndex()); if (biomeBases == null) throw new RuntimeException("Error while receiving biome bases of chunk (" + chunkCoords.x + "," + chunkCoords.z + ")."); IRegistry biomeBaseRegistry = chunk.world.r().b(IRegistry.ay); BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(biomeBaseRegistry, biome); Arrays.fill(biomeBases, biomeBase); chunk.markDirty(); LightEngineThreaded lightEngineThreaded = (LightEngineThreaded) chunk.world.e(); PacketPlayOutUnloadChunk unloadChunkPacket = new PacketPlayOutUnloadChunk(chunkCoords.x, chunkCoords.z); //noinspection deprecation PacketPlayOutMapChunk mapChunkPacket = new PacketPlayOutMapChunk(chunk, 65535); PacketPlayOutLightUpdate lightUpdatePacket = new PacketPlayOutLightUpdate(chunkCoords, lightEngineThreaded, true); playersToUpdate.forEach(player -> { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(unloadChunkPacket); playerConnection.sendPacket(lightUpdatePacket); playerConnection.sendPacket(mapChunkPacket); }); } @Override public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk) { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); IRegistry biomeBaseRegistry = worldServer.r().b(IRegistry.ay); BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(biomeBaseRegistry, biome); int[] biomes = unloadedChunk.hasKeyOfType("Biomes", 11) ? unloadedChunk.getIntArray("Biomes") : new int[256]; Arrays.fill(biomes, biomeBaseRegistry.a(biomeBase)); unloadedChunk.setIntArray("Biomes", biomes); } @Override public void onFinish() { // Do nothing. } }); } @Override public void deleteChunks(Island island, List chunkPositions, Runnable onFinish) { if (chunkPositions.isEmpty()) return; chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(Chunk chunk) { Arrays.fill(chunk.getSections(), Chunk.a); removeEntities(chunk); removeTileEntities(chunk); removeBlocks(chunk); } @Override public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk) { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); NBTTagList sectionsList = new NBTTagList(); NBTTagList tileEntities = new NBTTagList(); unloadedChunk.set("Sections", sectionsList); unloadedChunk.set("TileEntities", tileEntities); unloadedChunk.set("Entities", new NBTTagList()); if (!(worldServer.generator instanceof IslandsGenerator)) { ChunkCoordIntPair chunkCoords = new ChunkCoordIntPair(chunkPosition.getX(), chunkPosition.getZ()); ProtoChunk protoChunk = NMSUtils.createProtoChunk(chunkCoords, worldServer); try { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(worldServer, worldServer.getChunkProvider().chunkGenerator, worldServer.generator); customChunkGenerator.buildBase(null, protoChunk); } catch (Exception ignored) { } ChunkSection[] chunkSections = protoChunk.getSections(); for (int i = -1; i < 17; ++i) { int chunkSectionIndex = i; ChunkSection chunkSection = Arrays.stream(chunkSections).filter(_chunkPosition -> _chunkPosition != null && _chunkPosition.getYPosition() >> 4 == chunkSectionIndex) .findFirst().orElse(Chunk.a); if (chunkSection != Chunk.a) { NBTTagCompound sectionCompound = new NBTTagCompound(); sectionCompound.setByte("Y", (byte) (i & 255)); chunkSection.getBlocks().a(sectionCompound, "Palette", "BlockStates"); sectionsList.add(sectionCompound); } } for (BlockPosition tilePosition : protoChunk.c()) { NBTTagCompound tileCompound = protoChunk.i(tilePosition); if (tileCompound != null) tileEntities.add(tileCompound); } } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }); } @Override public CompletableFuture> calculateChunks(List chunkPositions, Synchronized> unloadedChunksCache) { List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); Iterator chunkPositionsIterator = chunkPositions.iterator(); while (chunkPositionsIterator.hasNext()) { ChunkPosition chunkPosition = chunkPositionsIterator.next(); CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); if (cachedCalculatedChunk != null) { allCalculatedChunks.add(cachedCalculatedChunk); chunkPositionsIterator.remove(); } else { chunkPositionsToCalculate.add(chunkPosition); } } if (chunkPositions.isEmpty()) return CompletableFuture.completedFuture(allCalculatedChunks); CompletableFuture> completableFuture = new CompletableFuture<>(); NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(Chunk chunk) { ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.getPos().x, chunk.getPos().z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, chunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk) { NBTTagList sectionsList = unloadedChunk.getList("Sections", 10); ChunkSection[] chunkSections = new ChunkSection[sectionsList.size()]; for (int i = 0; i < sectionsList.size(); ++i) { NBTTagCompound sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); if (sectionCompound.hasKeyOfType("Palette", 9) && sectionCompound.hasKeyOfType("BlockStates", 12)) { //noinspection deprecation ChunkSection chunkSection = chunkSections[i] = new ChunkSection(yPosition << 4); chunkSection.getBlocks().a(sectionCompound.getList("Palette", 10), sectionCompound.getLongArray("BlockStates")); chunkSection.recalcBlockCounts(); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }); return completableFuture; } @Override public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { if (chunkPositions.isEmpty()) return CompletableFuture.completedFuture(Collections.emptyList()); CompletableFuture> completableFuture = new CompletableFuture<>(); List allCalculatedChunks = new LinkedList<>(); List> unloadedEntityTags = new LinkedList<>(); NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback( ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(Chunk chunk) { KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); for (org.bukkit.entity.Entity bukkitEntity : chunk.getBukkitChunk().getEntities()) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false); CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities); allCalculatedChunks.add(calculatedChunk); latchCountDown(); } @Override public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound entityData) { unloadedEntityTags.add(new Pair<>(chunkPosition, entityData.getList("Entities", 10))); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.sync(() -> { for (Pair worldUnloadedEntityTagsPair : unloadedEntityTags) { WorldServer worldServer = ((CraftWorld) worldUnloadedEntityTagsPair.getKey().getWorld()).getHandle(); KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); for (NBTBase entityTag : worldUnloadedEntityTagsPair.getValue()) { EntityTypes entityType = EntityTypes.a((NBTTagCompound) entityTag).orElse(null); if (entityType == null) continue; Entity fakeEntity = EntityTypes.a((NBTTagCompound) entityTag, worldServer).orElse(null); if (fakeEntity != null) { fakeEntity.valid = false; if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) continue; } Key entityKey = Keys.of(Registry.ENTITY_TYPE.get( CraftNamespacedKey.fromMinecraft(EntityTypes.getName(entityType)))); chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(worldUnloadedEntityTagsPair.getKey(), chunkEntities); allCalculatedChunks.add(calculatedChunk); } completableFuture.complete(allCalculatedChunks); }); } }); return completableFuture; } @Override public void injectChunkSections(org.bukkit.Chunk chunk) { // No implementation } @Override public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); return Arrays.stream(chunk.getSections()).allMatch(chunkSection -> chunkSection == null || chunkSection.c()); } @Override public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { Chunk chunk = ((CraftWorld) chunkPosition.getWorld()).getHandle().getChunkProvider() .getChunkAt(chunkPosition.getX(), chunkPosition.getZ(), false); return chunk == null ? null : chunk.bukkitChunk; } @Override public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) { if (plugin.getSettings().getCropsInterval() <= 0) return; if (stop) { CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove( chunk.getWorld().getName(), ChunkCoordIntPair.pair(chunk.getX(), chunk.getZ())); World world = cropsTickingTileEntity == null ? null : cropsTickingTileEntity.getWorld(); if (cropsTickingTileEntity != null && world != null) world.tileEntityListTick.remove(cropsTickingTileEntity); } else { CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle()); } } @Override public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { if (chunkPositions.isEmpty()) return; CropsTickingTileEntity.forEachChunk(chunkPositions, cropsTickingTileEntity -> cropsTickingTileEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); } @Override public void shutdown() { List> pendingTasks = NMSUtils.getPendingChunkActions(); if (pendingTasks.isEmpty()) return; Log.info("Waiting for chunk tasks to complete."); CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); } @Override public List getBlockEntities(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); List blockEntities = new LinkedList<>(); org.bukkit.World bukkitWorld = bukkitChunk.getWorld(); chunk.getTileEntities().keySet().forEach(blockPosition -> blockEntities.add(new Location(bukkitWorld, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()))); return blockEntities; } private static CalculatedChunk.Blocks calculateChunk(ChunkPosition chunkPosition, ChunkSection[] chunkSections) { KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); List spawnersLocations = new LinkedList<>(); for (ChunkSection chunkSection : chunkSections) { if (chunkSection != null && !chunkSection.c()) { for (BlockPosition bp : BlockPosition.b(0, 0, 0, 15, 15, 15)) { IBlockData blockData = chunkSection.getType(bp.getX(), bp.getY(), bp.getZ()); Block block = blockData.getBlock(); if (block != Blocks.AIR) { Location location = new Location(chunkPosition.getWorld(), (chunkPosition.getX() << 4) + bp.getX(), chunkSection.getYPosition() + bp.getY(), (chunkPosition.getZ() << 4) + bp.getZ()); int blockAmount = 1; if ((blockData.getBlock().a(TagsBlock.SLABS) || blockData.getBlock().a(TagsBlock.WOODEN_SLABS)) && blockData.get(BlockStepAbstract.a) == BlockPropertySlabType.DOUBLE) { blockAmount = 2; blockData = blockData.set(BlockStepAbstract.a, BlockPropertySlabType.BOTTOM); } Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockData.getBlock()), location); blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); if (block == Blocks.SPAWNER) { spawnersLocations.add(location); } } } } } return new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations); } private static void removeEntities(Chunk chunk) { Collection[] entitySlices = null; Function> entitySliceCreationFunction = null; try { entitySlices = chunk.entitySlices; entitySliceCreationFunction = v -> new UnsafeList<>(); } catch (Throwable ex) { try { entitySlices = ENTITY_SLICE_ARRAY.get(chunk); entitySliceCreationFunction = v -> new net.minecraft.server.v1_16_R3.EntitySlice<>(Entity.class); } catch (Exception error) { Log.error(error, "An unexpected error occurred while removing entities from chunk ", chunk.getPos(), ":"); } } if (entitySlices != null) { for (int i = 0; i < entitySlices.length; i++) { entitySlices[i].forEach(entity -> { if (!(entity instanceof EntityHuman)) entity.dead = true; }); entitySlices[i] = entitySliceCreationFunction.apply(null); } } } private static void removeTileEntities(Chunk chunk) { new LinkedList<>(chunk.tileEntities.keySet()).forEach(chunk.world::removeTileEntity); chunk.tileEntities.clear(); } private static void removeBlocks(Chunk chunk) { ChunkCoordIntPair chunkCoords = chunk.getPos(); WorldServer worldServer = chunk.world; if (worldServer.generator != null && !(worldServer.generator instanceof IslandsGenerator)) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(worldServer, worldServer.getChunkProvider().chunkGenerator, worldServer.generator); ProtoChunk protoChunk = NMSUtils.createProtoChunk(chunkCoords, worldServer); customChunkGenerator.buildBase(null, protoChunk); for (int i = 0; i < 16; i++) chunk.getSections()[i] = protoChunk.getSections()[i]; for (Map.Entry entry : protoChunk.x().entrySet()) worldServer.setTileEntity(entry.getKey(), entry.getValue()); } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSDragonFightImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon.EndWorldEnderDragonBattleHandler; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon.IslandEnderDragonBattle; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon.IslandEntityEnderDragon; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon.SpikesCache; import com.google.common.cache.LoadingCache; import net.minecraft.server.v1_16_R3.EnderDragonBattle; import net.minecraft.server.v1_16_R3.EntityEnderDragon; import net.minecraft.server.v1_16_R3.EntityTypes; import net.minecraft.server.v1_16_R3.WorldGenEnder; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.advancement.Advancement; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.entity.EnderDragon; import org.bukkit.entity.Player; import java.lang.reflect.Modifier; import java.util.List; public class NMSDragonFightImpl implements NMSDragonFight { private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( EntityTypes.class, EntityTypes.b.class, Modifier.PRIVATE | Modifier.FINAL, 1) .removeFinal(); private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField( WorldServer.class, EnderDragonBattle.class, Modifier.PRIVATE | Modifier.FINAL, 1) .removeFinal(); private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( WorldGenEnder.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) .removeFinal(); private static boolean firstWorldPreparation = true; static { ENTITY_TYPES_BUILDER.set(EntityTypes.ENDER_DRAGON, (EntityTypes.b) IslandEntityEnderDragon::fromEntityTypes); } @Override public void prepareEndWorld(World bukkitWorld) { WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); WORLD_DRAGON_BATTLE.set(worldServer, new EndWorldEnderDragonBattleHandler(worldServer)); if (firstWorldPreparation) { firstWorldPreparation = false; SPIKE_CACHE.set(null, SpikesCache.getInstance()); } } @Nullable @Override public EnderDragon getEnderDragon(Island island, Dimension dimension) { WorldServer worldServer = ((CraftWorld) island.getCenter(dimension).getWorld()).getHandle(); if (!(worldServer.getDragonBattle() instanceof EndWorldEnderDragonBattleHandler)) return null; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle(); IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.getDragonBattle(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @Override public void startDragonBattle(Island island, Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return; WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); if (!(worldServer.getDragonBattle() instanceof EndWorldEnderDragonBattleHandler)) return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle(); dragonBattleHandler.addDragonBattle(island.getCache(), new IslandEnderDragonBattle(island, worldServer, location)); } @Override public void removeDragonBattle(Island island, Dimension dimension) { World bukkitWorld = island.getCenter(dimension).getWorld(); if (bukkitWorld == null) return; WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); if (!(worldServer.getDragonBattle() instanceof EndWorldEnderDragonBattleHandler)) return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle(); IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.removeDragonBattle(island.getCache()); if (enderDragonBattle != null) { enderDragonBattle.removeBattlePlayers(); enderDragonBattle.getEnderDragon().die(); } } @Override public void awardTheEndAchievement(Player player) { Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); if (advancement != null) player.getAdvancementProgress(advancement).awardCriteria(""); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.server.v1_16_R3.Entity; import net.minecraft.server.v1_16_R3.EntityMinecartFurnace; import net.minecraft.server.v1_16_R3.IMaterial; import net.minecraft.server.v1_16_R3.Items; import net.minecraft.server.v1_16_R3.RecipeItemStack; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>(Entity.class, int.class, "portalTicks"); private static final RecipeItemStack MINECART_FURNACE_FUEL_RECIPE = RecipeItemStack.a(Items.COAL, Items.CHARCOAL); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { ItemStack[] itemStacks = new ItemStack[7]; itemStacks[0] = new ItemStack(Material.ARMOR_STAND); itemStacks[1] = entityEquipment.getItemInMainHand(); itemStacks[2] = entityEquipment.getItemInOffHand(); itemStacks[3] = entityEquipment.getHelmet(); itemStacks[4] = entityEquipment.getChestplate(); itemStacks[5] = entityEquipment.getLeggings(); itemStacks[6] = entityEquipment.getBoots(); return itemStacks; } @Override public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().k(CraftItemStack.asNMSCopy(itemStack)); } @Override public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_FUEL_RECIPE.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSHologramsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import com.bgsoftware.superiorskyblock.nms.NMSHolograms; import net.minecraft.server.v1_16_R3.AxisAlignedBB; import net.minecraft.server.v1_16_R3.DamageSource; import net.minecraft.server.v1_16_R3.EntityArmorStand; import net.minecraft.server.v1_16_R3.EntityHuman; import net.minecraft.server.v1_16_R3.EnumHand; import net.minecraft.server.v1_16_R3.EnumInteractionResult; import net.minecraft.server.v1_16_R3.EnumItemSlot; import net.minecraft.server.v1_16_R3.IChatBaseComponent; import net.minecraft.server.v1_16_R3.ItemStack; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.SoundEffect; import net.minecraft.server.v1_16_R3.Vec3D; import net.minecraft.server.v1_16_R3.World; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftArmorStand; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; public class NMSHologramsImpl implements NMSHolograms { @Override public Hologram createHologram(Location location) { assert location.getWorld() != null; World world = ((CraftWorld) location.getWorld()).getHandle(); EntityHologram entityHologram = new EntityHologram(world, location.getX(), location.getY(), location.getZ()); world.addEntity(entityHologram); return entityHologram; } @Override public boolean isHologram(Entity entity) { return ((CraftEntity) entity).getHandle() instanceof Hologram; } public static class EntityHologram extends EntityArmorStand implements Hologram { private CraftEntity bukkitEntity; EntityHologram(World world, double x, double y, double z) { super(world, x, y, z); setInvisible(true); setSmall(true); setArms(false); setNoGravity(true); setBasePlate(true); setMarker(true); super.collides = false; super.setCustomNameVisible(true); super.a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D)); } @Override public void setHologramName(String name) { super.setCustomName(CraftChatMessage.fromString(name)[0]); } @Override public void removeHologram() { super.die(); } @Override public ArmorStand getHandle() { return this.getBukkitEntity(); } @Override public void inactiveTick() { // Disable normal ticking for this entity. // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. if (this.onGround) { this.onGround = false; } } @Override public boolean isCollidable() { return false; } @Override public void setSlot(EnumItemSlot enumitemslot, ItemStack itemstack) { // Prevent stand being equipped } @Override public boolean a_(int i, ItemStack item) { // Prevent stand being equipped return false; } @Override public void saveData(NBTTagCompound nbttagcompound) { // Do not save NBT. } @Override public void loadData(NBTTagCompound nbttagcompound) { // Do not load NBT. } @Override public EnumInteractionResult a(EntityHuman human, Vec3D vec3d, EnumHand enumhand) { // Prevent stand being equipped return EnumInteractionResult.PASS; } @Override public void tick() { // Disable normal ticking for this entity. // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. if (this.onGround) { this.onGround = false; } } public void forceSetBoundingBox(AxisAlignedBB boundingBox) { super.a(boundingBox); } @Override public CraftArmorStand getBukkitEntity() { if (bukkitEntity == null) { bukkitEntity = new CraftArmorStand(super.world.getServer(), this); } return (CraftArmorStand) bukkitEntity; } @Override public void die() { // Prevent being killed. } @Override public void playSound(SoundEffect soundeffect, float f, float f1) { // Remove sounds. } @Override public boolean a_(NBTTagCompound nbttagcompound) { // Do not save NBT. return false; } @Override public boolean d(NBTTagCompound nbttagcompound) { // Do not save NBT. return false; } @Override public NBTTagCompound save(NBTTagCompound nbttagcompound) { // Do not save NBT. return nbttagcompound; } @Override public void load(NBTTagCompound nbttagcompound) { // Do not load NBT. } @Override public boolean isInvulnerable(DamageSource source) { /* * The field Entity.invulnerable is private. * It's only used while saving NBTTags, but since the entity would be killed * on chunk unload, we prefer to override isInvulnerable(). */ return true; } @Override public void setCustomName(@Nullable IChatBaseComponent ichatbasecomponent) { // Locks the custom name. } @Override public void setCustomNameVisible(boolean flag) { // Locks the custom name. } @Override public void a(AxisAlignedBB boundingBox) { // Do not change it! } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import net.minecraft.server.v1_16_R3.EntityPlayer; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(Player.class, "locale"); @Override public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { return OfflinePlayerDataImpl.create(offlinePlayer); } @Override public void setSkinTexture(SuperiorPlayer superiorPlayer) { Player player = superiorPlayer.asPlayer(); if (player != null) { EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); Optional optional = entityPlayer.getProfile().getProperties().get("textures").stream().findFirst(); optional.ifPresent(property -> setSkinTexture(superiorPlayer, property)); } } @Override public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { superiorPlayer.setTextureValue(property.getValue()); } @Override public void sendActionBar(Player player, String message) { //noinspection deprecation player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); } @Override public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); bossBar.addPlayer(player); return bossBar; } @Override public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); } @Override public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { return superiorPlayer.getUniqueId().equals(item.getThrower()); } @Nullable @Override public Locale getPlayerLocale(Player player) { if (PLAYER_LOCALE.isValid()) { return player.locale(); } else try { //noinspection deprecation return PlayerLocales.getLocale(player.getLocale()); } catch (IllegalArgumentException error) { return null; } } private static class BossBarImpl implements BossBar { private final org.bukkit.boss.BossBar bossBar; private final BossBarTask bossBarTask; public BossBarImpl(String message, BarColor color, double ticksToRun) { bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); this.bossBarTask = BossBarTask.create(this, ticksToRun); } @Override public void addPlayer(Player player) { this.bossBar.addPlayer(player); this.bossBarTask.registerTask(player); } @Override public void removeAll() { this.bossBar.removeAll(); this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); } @Override public void setProgress(double progress) { this.bossBar.setProgress(progress); } @Override public double getProgress() { return this.bossBar.getProgress(); } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.mojang.serialization.Dynamic; import net.minecraft.server.v1_16_R3.DataConverterRegistry; import net.minecraft.server.v1_16_R3.DataConverterTypes; import net.minecraft.server.v1_16_R3.DynamicOpsNBT; import net.minecraft.server.v1_16_R3.Entity; import net.minecraft.server.v1_16_R3.EntityTypes; import net.minecraft.server.v1_16_R3.ItemStack; import net.minecraft.server.v1_16_R3.MinecraftKey; import net.minecraft.server.v1_16_R3.NBTBase; import net.minecraft.server.v1_16_R3.NBTTagByte; import net.minecraft.server.v1_16_R3.NBTTagByteArray; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.NBTTagDouble; import net.minecraft.server.v1_16_R3.NBTTagFloat; import net.minecraft.server.v1_16_R3.NBTTagInt; import net.minecraft.server.v1_16_R3.NBTTagIntArray; import net.minecraft.server.v1_16_R3.NBTTagList; import net.minecraft.server.v1_16_R3.NBTTagLong; import net.minecraft.server.v1_16_R3.NBTTagShort; import net.minecraft.server.v1_16_R3.NBTTagString; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; import java.util.Set; @SuppressWarnings({"unused"}) public class NMSTagsImpl implements NMSTags { @Override public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); NBTTagCompound tagCompound = itemStack.save(new NBTTagCompound()); tagCompound.setInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); return CompoundTag.fromNBT(tagCompound); } @Override public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { if (compoundTag.containsKey("NBT")) { // Old compound version, deserialize it accordingly return deserializeItemOld(compoundTag); } NBTTagCompound tagCompound = (NBTTagCompound) compoundTag.toNBT(); int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); int itemVersion = tagCompound.getInt("DataVersion"); if (itemVersion < currentVersion) { tagCompound = (NBTTagCompound) DataConverterRegistry.getDataFixer().update(DataConverterTypes.ITEM_STACK, new Dynamic<>(DynamicOpsNBT.a, tagCompound), itemVersion, currentVersion).getValue(); } ItemStack itemStack = ItemStack.a(tagCompound); return CraftItemStack.asCraftMirror(itemStack); } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); int amount = compoundTag.getInt("amount").orElse(0); short data = (short) compoundTag.getShort("data").orElse(0); CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); if (nbtData != null) itemStack.setTag((NBTTagCompound) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) { CraftWorld craftWorld = (CraftWorld) location.getWorld(); NBTTagCompound nbtTagCompound = (NBTTagCompound) compoundTag.toNBT(); if (nbtTagCompound == null) nbtTagCompound = new NBTTagCompound(); if (!nbtTagCompound.hasKey("id")) //noinspection deprecation nbtTagCompound.setString("id", new MinecraftKey(entityType.getName()).getKey()); Entity entity = EntityTypes.a(nbtTagCompound, craftWorld.getHandle(), (_entity) -> { _entity.setPositionRotation(location.getX(), location.getY(), location.getZ(), _entity.yaw, _entity.pitch); return !craftWorld.getHandle().addEntitySerialized(_entity) ? null : _entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((NBTTagByteArray) object).getBytes(); } @Override public byte getNBTByteValue(Object object) { return ((NBTTagByte) object).asByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((NBTTagCompound) object).getKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NBTTagDouble) object).asDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NBTTagFloat) object).asFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((NBTTagIntArray) object).getInts(); } @Override public int getNBTIntValue(Object object) { return ((NBTTagInt) object).asInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((NBTTagList) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NBTTagLong) object).asLong(); } @Override public short getNBTShortValue(Object object) { return ((NBTTagShort) object).asShort(); } @Override public String getNBTStringValue(Object object) { return ((NBTTagString) object).asString(); } @Override public Object parseList(ListTag listTag) { NBTTagList nbtTagList = new NBTTagList(); for (Tag tag : listTag) nbtTagList.add((NBTBase) tag.toNBT()); return nbtTagList; } @Override public Object getNBTCompoundTag(Object object, String key) { return ((NBTTagCompound) object).get(key); } @Override public void setNBTCompoundTagValue(Object object, String key, Object value) { ((NBTTagCompound) object).set(key, (NBTBase) value); } @Override public int getNBTTagListSize(Object object) { return ((NBTTagList) object).size(); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockStatesMapper; import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockBed; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.ChunkConverter; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; import net.minecraft.server.v1_16_R3.ChunkProviderServer; import net.minecraft.server.v1_16_R3.ChunkSection; import net.minecraft.server.v1_16_R3.HeightMap; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.IBlockState; import net.minecraft.server.v1_16_R3.IChunkAccess; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.PlayerChunkMap; import net.minecraft.server.v1_16_R3.ProtoChunk; import net.minecraft.server.v1_16_R3.TileEntity; import net.minecraft.server.v1_16_R3.World; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final ReflectMethod CHUNK_PROVIDER_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ChunkProviderServer.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); public static final ObjectsPool> BLOCK_POS_POOL = ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0)); private NMSUtils() { } @Nullable public static T getTileEntityAt(Location location, Class type) { org.bukkit.World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return null; WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); TileEntity tileEntity = worldServer.getTileEntity(blockPosition); return !type.isInstance(tileEntity) ? null : type.cast(tileEntity); } } public static void runActionOnChunks(Collection chunksCoords, boolean saveChunks, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, saveChunks, chunkCallback); } private static void runActionOnChunksInternal(Collection chunksCoords, boolean saveChunks, ChunkCallback chunkCallback) { List unloadedChunks = new LinkedList<>(); List loadedChunks = new LinkedList<>(); chunksCoords.forEach(chunkPosition -> { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); IChunkAccess chunkAccess; try { chunkAccess = worldServer.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); } catch (Throwable ex) { chunkAccess = worldServer.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); } if (chunkAccess instanceof Chunk) { loadedChunks.add((Chunk) chunkAccess); } else { unloadedChunks.add(chunkPosition.copy()); } }); boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); if (!loadedChunks.isEmpty()) runActionOnLoadedChunks(loadedChunks, chunkCallback); if (hasUnloadedChunks) { runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback); } else { chunkCallback.onFinish(); } } private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { chunks.forEach(chunkCallback::onLoadedChunk); } private static void runActionOnUnloadedChunks(Collection chunks, boolean saveChunks, ChunkCallback chunkCallback) { if (CHUNK_PROVIDER_SERVER_GET_CHUNK_IF_CACHED.isValid()) { Iterator chunksIterator = chunks.iterator(); while (chunksIterator.hasNext()) { ChunkPosition chunkPosition = chunksIterator.next(); WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); Chunk cachedUnloadedChunk = worldServer.getChunkProvider().getChunkAtIfCachedImmediately( chunkPosition.getX(), chunkPosition.getZ()); if (cachedUnloadedChunk != null) { chunkCallback.onLoadedChunk(cachedUnloadedChunk); chunksIterator.remove(); } } if (chunks.isEmpty()) { chunkCallback.onFinish(); return; } } CompletableFuture pendingTask = new CompletableFuture<>(); PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { CountDownLatch countDownLatch; if (chunkCallback.isWaitForChunkLoad) { countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); } else { countDownLatch = null; } chunks.forEach(chunkPosition -> { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PlayerChunkMap playerChunkMap = worldServer.getChunkProvider().playerChunkMap; ChunkCoordIntPair chunkCoords = new ChunkCoordIntPair(chunkPosition.getX(), chunkPosition.getZ()); boolean calledCountdown = false; try { NBTTagCompound chunkCompound = playerChunkMap.read(chunkCoords); if (chunkCompound == null) { chunkCallback.onChunkNotExist(chunkPosition); return; } NBTTagCompound chunkDataCompound = playerChunkMap.getChunkData(worldServer.getTypeKey(), Suppliers.ofInstance(worldServer.getWorldPersistentData()), chunkCompound, chunkCoords, worldServer); if (chunkDataCompound.hasKeyOfType("Level", 10)) { chunkCallback.onUnloadedChunk(chunkPosition, chunkDataCompound.getCompound("Level")); calledCountdown = true; if (saveChunks) playerChunkMap.a(chunkCoords, chunkDataCompound); } else { if (countDownLatch != null) countDownLatch.countDown(); } } catch (Exception error) { if (!calledCountdown && countDownLatch != null) countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); if (countDownLatch != null) { try { countDownLatch.await(); } catch (InterruptedException error) { throw new RuntimeException(error); } } }).runSync(v -> { chunkCallback.onFinish(); pendingTask.complete(null); PENDING_CHUNK_ACTIONS.remove(pendingTask); }); } public static List> getPendingChunkActions() { return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); } public static ProtoChunk createProtoChunk(ChunkCoordIntPair chunkCoord, World world) { try { // Paper's constructor for ProtoChunk return new ProtoChunk(chunkCoord, ChunkConverter.a, world); } catch (Throwable ex) { // Spigot's constructor for ProtoChunk // noinspection deprecation return new ProtoChunk(chunkCoord, ChunkConverter.a); } } public static IBlockData setBlock(Chunk chunk, BlockPosition blockPosition, int combinedId, CompoundTag statesTag, CompoundTag tileEntity) { if (!isValidPosition(chunk.getWorld(), blockPosition)) return null; IBlockData blockData = Block.getByCombinedId(combinedId); if (statesTag != null) { for (Map.Entry> entry : statesTag.entrySet()) { try { // noinspection rawtypes IBlockState blockState = BlockStatesMapper.getBlockState(entry.getKey()); if (blockState != null) { if (entry.getValue() instanceof ByteTag) { // noinspection unchecked blockData = blockData.set(blockState, ((ByteTag) entry.getValue()).getValue() == 1); } else if (entry.getValue() instanceof IntArrayTag) { int[] data = ((IntArrayTag) entry.getValue()).getValue(); // noinspection unchecked blockData = blockData.set(blockState, data[0]); } else if (entry.getValue() instanceof StringTag) { String data = ((StringTag) entry.getValue()).getValue(); // noinspection unchecked blockData = blockData.set(blockState, Enum.valueOf(blockState.getType(), data)); } } } catch (Exception ignored) { } } } if ((blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || blockData.getBlock() instanceof BlockBed) { chunk.world.setTypeAndData(blockPosition, blockData, 3); return blockData; } int indexY = blockPosition.getY() >> 4; ChunkSection chunkSection = chunk.getSections()[indexY]; if (chunkSection == null) { try { // Paper's constructor for ChunkSection for more optimized chunk sections. chunkSection = chunk.getSections()[indexY] = new ChunkSection(indexY << 4, chunk, chunk.world, true); } catch (Throwable ex) { // Spigot's constructor for ChunkSection // noinspection deprecation chunkSection = chunk.getSections()[indexY] = new ChunkSection(indexY << 4); } } int blockX = blockPosition.getX() & 15; int blockY = blockPosition.getY(); int blockZ = blockPosition.getZ() & 15; boolean isOriginallyChunkSectionEmpty = chunkSection.c(); chunkSection.setType(blockX, blockY & 15, blockZ, blockData, false); chunk.heightMap.get(HeightMap.Type.MOTION_BLOCKING).a(blockX, blockY, blockZ, blockData); chunk.heightMap.get(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES).a(blockX, blockY, blockZ, blockData); chunk.heightMap.get(HeightMap.Type.OCEAN_FLOOR).a(blockX, blockY, blockZ, blockData); chunk.heightMap.get(HeightMap.Type.WORLD_SURFACE).a(blockX, blockY, blockZ, blockData); chunk.markDirty(); chunk.setNeedsSaving(true); boolean isChunkSectionEmpty = chunkSection.c(); if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) chunk.getWorld().e().a(blockPosition, isChunkSectionEmpty); chunk.getWorld().e().a(blockPosition); if (tileEntity != null) { NBTTagCompound tileEntityCompound = (NBTTagCompound) tileEntity.toNBT(); if (tileEntityCompound != null) { tileEntityCompound.setInt("x", blockPosition.getX()); tileEntityCompound.setInt("y", blockPosition.getY()); tileEntityCompound.setInt("z", blockPosition.getZ()); TileEntity worldTileEntity = chunk.world.getTileEntity(blockPosition); if (worldTileEntity != null) worldTileEntity.load(blockData, tileEntityCompound); } } return blockData; } private static boolean isValidPosition(World world, BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && blockPosition.getY() >= 0 && blockPosition.getY() < world.getHeight(); } public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; } public abstract void onLoadedChunk(Chunk chunk); public abstract void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk); public abstract void onFinish(); protected final void latchCountDown() { if (this.chunkLoadLatch != null) this.chunkLoadLatch.countDown(); } public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) { latchCountDown(); return; } ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null).whenComplete((bukkitChunk, error) -> { if (error == null) { BukkitExecutor.ensureMain(() -> { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); onLoadedChunk(chunk); }); } else { latchCountDown(); throw new RuntimeException(error); } }); } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import com.bgsoftware.superiorskyblock.nms.NMSWorld; import com.bgsoftware.superiorskyblock.nms.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.spawners.TileEntityMobSpawnerNotifier; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockTickListServerTracker; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockAccessAir; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockPropertySlabType; import net.minecraft.server.v1_16_R3.BlockStepAbstract; import net.minecraft.server.v1_16_R3.Blocks; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.IChatBaseComponent; import net.minecraft.server.v1_16_R3.PacketPlayOutWorldBorder; import net.minecraft.server.v1_16_R3.SoundCategory; import net.minecraft.server.v1_16_R3.SoundEffectType; import net.minecraft.server.v1_16_R3.TagsBlock; import net.minecraft.server.v1_16_R3.TileEntityMobSpawner; import net.minecraft.server.v1_16_R3.TileEntitySign; import net.minecraft.server.v1_16_R3.World; import net.minecraft.server.v1_16_R3.WorldBorder; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_16_R3.block.CraftSign; import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { private static final ReflectMethod SOUND_VOLUME = new ReflectMethod<>(SoundEffectType.class, "a"); private static final ReflectMethod SOUND_PITCH = new ReflectMethod<>(SoundEffectType.class, "b"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(World.class, Object.class, "chunkPacketBlockController").removeFinal(); private static boolean alreadyWarned = false; private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { try { return getBlockKeyInternal(chunkSnapshot, x, y, z); } catch (ArrayIndexOutOfBoundsException error) { return ConstantKeys.AIR; } } private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); Location location = new Location( Bukkit.getWorld(chunkSnapshot.getWorldName()), (chunkSnapshot.getX() << 4) + x, y, (chunkSnapshot.getZ() << 4) + z ); return Keys.of(KeyBlocksCache.getBlockKey(block), location); } @Override public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) { try { return canPlayerSuffocateInternal(chunkSnapshot, x, y, z); } catch (ArrayIndexOutOfBoundsException error) { return true; } } private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { IBlockData blockData = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState(); return !blockData.getCollisionShape(BlockAccessAir.INSTANCE, BlockPosition.ZERO).isEmpty(); } @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); if (mobSpawner == null || mobSpawner instanceof TileEntityMobSpawnerNotifier) return; World world = mobSpawner.getWorld(); TileEntityMobSpawnerNotifier tileEntityMobSpawnerNotifier = new TileEntityMobSpawnerNotifier(mobSpawner, delayChangeCallback); world.removeTileEntity(mobSpawner.getPosition()); world.setTileEntity(mobSpawner.getPosition(), tileEntityMobSpawnerNotifier); } @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) return; Player player = superiorPlayer.asPlayer(); org.bukkit.World world = superiorPlayer.getWorld(); if (world == null || player == null) return; int islandSize = island == null ? 0 : island.getIslandSize(); boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; WorldServer worldServer = ((CraftWorld) superiorPlayer.getWorld()).getHandle(); WorldBorder worldBorder; if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { worldBorder = worldServer.getWorldBorder(); } else { Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); if (dimension == null) return; Location center = island.getCenter(dimension); worldBorder = new WorldBorder(); worldBorder.world = worldServer; worldBorder.setWarningDistance(0); worldBorder.setCenter(center.getX(), center.getZ()); switch (superiorPlayer.getBorderColor()) { case BLUE: { worldBorder.setSize((islandSize * 2) + 1D); break; } case GREEN: { worldBorder.setSize((islandSize * 2) + 1.001D); worldBorder.transitionSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); break; } case RED: { worldBorder.setSize((islandSize * 2) + 1D); worldBorder.transitionSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); break; } } } PacketPlayOutWorldBorder packetPlayOutWorldBorder = new PacketPlayOutWorldBorder(worldBorder, PacketPlayOutWorldBorder.EnumWorldBorderAction.INITIALIZE); ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutWorldBorder); } @Override public Object getBlockData(org.bukkit.block.Block block) { return block.getBlockData(); } @Override public void setBlock(Location location, int combinedId) { WorldServer world = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); IBlockData blockData = NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null, null); if (blockData != null) { world.getChunkProvider().flagDirty(blockPosition); if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { world.chunkPacketBlockController.onBlockChange(world, blockPosition, blockData, Blocks.AIR.getBlockData(), 530); } } } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) return true; org.bukkit.block.data.BlockData blockData = block.getBlockData(); return blockData instanceof BubbleColumn || (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } @Override public SignType getSignType(Object sign) { if (sign instanceof WallSign) return SignType.WALL_SIGN; else if (sign instanceof Sign) return SignType.STANDING_SIGN; else return SignType.UNKNOWN; } @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { IBlockData blockData = ((CraftBlock) block).getNMS(); return PistonPushReaction.values()[blockData.getPushReaction().ordinal()]; } @Override public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); } @Override public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); } private int getDefaultAmount(IBlockData blockData) { Block nmsBlock = blockData.getBlock(); // Checks for double slabs if ((nmsBlock.a(TagsBlock.SLABS) || nmsBlock.a(TagsBlock.WOODEN_SLABS)) && blockData.get(BlockStepAbstract.a) == BlockPropertySlabType.DOUBLE) { return 2; } return 1; } @Override public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { return !bukkitBlock.isPassable(); } @Override public void placeSign(Island island, Location location) { TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); if (tileEntitySign == null) return; String[] lines = new String[4]; System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); String[] strippedLines = new String[4]; for (int i = 0; i < 4; i++) strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); IChatBaseComponent[] newLines; IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); if (result.isCancelEvent()) { newLines = CraftSign.sanitizeLines(strippedLines); } else { newLines = CraftSign.sanitizeLines(lines); } System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } @Override public void playGeneratorSound(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(location.getX(), location.getY(), location.getZ()); world.triggerEffect(1501, blockPosition, 0); } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { World world = ((CraftWorld) block.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(block.getX(), block.getY(), block.getZ()); world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition))); } } @Override public void playPlaceSound(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); SoundEffectType soundEffectType = world.getType(blockPosition).getStepSound(); float volume = SOUND_VOLUME.isValid() ? SOUND_VOLUME.invoke(soundEffectType) : soundEffectType.getVolume(); float pitch = SOUND_PITCH.isValid() ? SOUND_PITCH.invoke(soundEffectType) : soundEffectType.getPitch(); world.playSound(null, blockPosition, soundEffectType.getPlaceSound(), SoundCategory.BLOCKS, (volume + 1.0F) / 2.0F, pitch * 0.8F); } } @Override public int getMinHeight(org.bukkit.World world) { try { return world.getMinHeight(); } catch (Throwable error) { return 0; } } @Override public void removeAntiXray(org.bukkit.World bukkitWorld) { World world = ((CraftWorld) bukkitWorld).getHandle(); if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) CHUNK_PACKET_BLOCK_CONTROLLER.set(world, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override public void setOceanLevel(org.bukkit.World world) { // Not possible in this version, it is hardcoded 63 } @Override public IslandsGenerator createGenerator(Dimension dimension) { return new IslandsGeneratorImpl(dimension); } @Override public WorldEditSession createEditSession(org.bukkit.World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } @Override public WorldEditSession createPartialEditSession(Dimension dimension) { return WorldEditSessionImpl.obtain(dimension); } @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } @Override public void listenBlockStateChanges(org.bukkit.World world) { WorldServer worldServer = ((CraftWorld) world).getHandle(); BlockTickListServerTracker.listenForTicks(worldServer); if (!alreadyWarned) { Log.warn("This version is old and you may experience issues with block changes detection"); alreadyWarned = true; } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; import net.minecraft.server.v1_16_R3.ChunkSection; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; import java.util.HashSet; import java.util.Random; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { private static final ReflectField WORLD_SERVER_RANDOM_TICK_RANDOM = new ReflectField<>( WorldServer.class, Random.class, "randomTickRandom"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static Set CROPS_TO_GROW_CACHE; static { plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final BlockPosition.MutableBlockPosition chunkTickMutablePosition = new BlockPosition.MutableBlockPosition(); private static final CropsTickingMethod INSTANCE = WORLD_SERVER_RANDOM_TICK_RANDOM.isValid() ? new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); protected CropsTickingMethod() { } public static void register() { // Calls the static initializer which registers the callback. } public static void tick(Chunk chunk, int tickSpeed) { INSTANCE.doTick(chunk, tickSpeed); } protected abstract void doTick(Chunk chunk, int tickSpeed); private static void onSettingsUpdate() { CROPS_TO_GROW_CACHE = new HashSet<>(); plugin.getSettings().getCropsToGrow().forEach(cropName -> { Key key = Keys.ofMaterialAndData(cropName); if (key instanceof MaterialKey) { Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial()); if (block != null && block.getBlockData().isTicking()) CROPS_TO_GROW_CACHE.add(block); } }); } private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override protected void doTick(Chunk chunk, int tickSpeed) { WorldServer worldServer = chunk.world; ChunkCoordIntPair chunkCoord = chunk.getPos(); int chunkOffsetX = chunkCoord.x << 4; int chunkOffsetZ = chunkCoord.z << 4; Random randomTickRandom = WORLD_SERVER_RANDOM_TICK_RANDOM.get(worldServer); ChunkSection[] sections = chunk.getSections(); for (int sectionIndex = 0; sectionIndex < 16; ++sectionIndex) { ChunkSection chunkSection = sections[sectionIndex]; if (chunkSection == null || chunkSection == Chunk.a) continue; int tickingBlocks = chunkSection.tickingList.size(); if (tickingBlocks <= 0) continue; int offsetY = sectionIndex << 4; for (int i = 0; i < tickSpeed; ++i) { int index = randomTickRandom.nextInt(4096); if (index >= tickingBlocks) continue; long raw = chunkSection.tickingList.getRaw(index); int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); IBlockData blockData = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); if (!CROPS_TO_GROW_CACHE.contains(blockData.getBlock())) continue; chunkTickMutablePosition.d((location & 15) | chunkOffsetX, ((location >>> 8) & 255) | offsetY, ((location >>> 4) & 15) | chunkOffsetZ); blockData.b(worldServer, chunkTickMutablePosition, randomTickRandom); } } } } private static class SpigotCropsTickingMethod extends CropsTickingMethod { private static int random = ThreadLocalRandom.current().nextInt(); @Override protected void doTick(Chunk chunk, int tickSpeed) { WorldServer worldServer = chunk.world; ChunkCoordIntPair chunkCoord = chunk.getPos(); int chunkOffsetX = chunkCoord.x << 4; int chunkOffsetZ = chunkCoord.z << 4; for (ChunkSection chunkSection : chunk.getSections()) { if (chunkSection != Chunk.a && chunkSection.d()) { for (int i = 0; i < tickSpeed; i++) { random = random * 3 + 1013904223; int factor = random >> 2; int x = factor & 15; int z = factor >> 8 & 15; int y = factor >> 16 & 15; IBlockData blockData = chunkSection.getType(x, y, z); if (blockData.isTicking() && CROPS_TO_GROW_CACHE.contains(blockData.getBlock())) { chunkTickMutablePosition.d(x + chunkOffsetX, y + chunkSection.getYPosition(), z + chunkOffsetZ); blockData.b(worldServer, chunkTickMutablePosition, worldServer.random); } } } } } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; import net.minecraft.server.v1_16_R3.GameRules; import net.minecraft.server.v1_16_R3.ITickable; import net.minecraft.server.v1_16_R3.TileEntity; import net.minecraft.server.v1_16_R3.TileEntityTypes; import java.lang.ref.WeakReference; import java.util.List; import java.util.function.Consumer; public class CropsTickingTileEntity extends TileEntity implements ITickable { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Chunk2ObjectMap tickingChunks = new Chunk2ObjectMap<>(); private final WeakReference island; private final WeakReference chunk; private int currentTick = 0; private double cachedCropGrowthMultiplier; private CropsTickingTileEntity(Island island, Chunk chunk) { super(TileEntityTypes.COMMAND_BLOCK); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(chunk); ChunkCoordIntPair chunkCoord = chunk.getPos(); setLocation(chunk.getWorld(), new BlockPosition(chunkCoord.x << 4, 1, chunkCoord.z << 4)); try { // Not a method of Spigot - fixes https://github.com/OmerBenGera/SuperiorSkyblock2/issues/5 setCurrentChunk(chunk); } catch (Throwable ignored) { } assert world != null; world.tileEntityListTick.add(this); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; } public static void create(Island island, String worldName, Chunk chunk) { long chunkPair = chunk.getPos().pair(); tickingChunks.computeIfAbsent(worldName, chunkPair, () -> new CropsTickingTileEntity(island, chunk)); } public static CropsTickingTileEntity remove(String worldName, long chunkCoords) { return tickingChunks.remove(worldName, chunkCoords); } public static void forEachChunk(List chunkPositions, Consumer cropsTickingTileEntityConsumer) { if (tickingChunks.isEmpty()) return; chunkPositions.forEach(chunkPosition -> { long chunkKey = chunkPosition.asPair(); CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey); if (cropsTickingTileEntity != null) cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity); }); } @Override public void tick() { assert world != null; if (++currentTick <= plugin.getSettings().getCropsInterval()) return; Chunk chunk = this.chunk.get(); Island island = this.island.get(); if (chunk == null || island == null) { world.tileEntityListTick.remove(this); return; } currentTick = 0; int worldRandomTick = world.getGameRules().getInt(GameRules.RANDOM_TICK_SPEED); int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); if (chunkRandomTickSpeed > 0) CropsTickingMethod.tick(chunk, chunkRandomTickSpeed); } @Override public void w() { tick(); } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { this.cachedCropGrowthMultiplier = cropGrowthMultiplier; } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/DragonUtils.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.WorldGenEndTrophy; import java.lang.reflect.Modifier; public class DragonUtils { private static final ReflectField END_PODIUM_LOCATION = new ReflectField( WorldGenEndTrophy.class, BlockPosition.class, Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) .removeFinal(); private static BlockPosition currentPodiumPosition = BlockPosition.ZERO; private DragonUtils() { } public static void runWithPodiumPosition(BlockPosition podiumPosition, Runnable runnable) { try { END_PODIUM_LOCATION.set(null, podiumPosition); currentPodiumPosition = podiumPosition; runnable.run(); } finally { END_PODIUM_LOCATION.set(null, BlockPosition.ZERO); currentPodiumPosition = BlockPosition.ZERO; } } public static BlockPosition getCurrentPodiumPosition() { return currentPodiumPosition; } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/EndWorldEnderDragonBattleHandler.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.v1_16_R3.EnderDragonBattle; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.WorldServer; import java.util.LinkedList; import java.util.List; public class EndWorldEnderDragonBattleHandler extends EnderDragonBattle { private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_BATTLE", IslandEnderDragonBattle.class); private final List worldDragonBattlesList = new LinkedList<>(); public EndWorldEnderDragonBattleHandler(WorldServer worldServer) { super(worldServer, worldServer.getSeed(), new NBTTagCompound()); } @Override public void b() { this.worldDragonBattlesList.forEach(EnderDragonBattle::b); } public void addDragonBattle(IslandCache islandCache, IslandEnderDragonBattle enderDragonBattle) { IslandEnderDragonBattle oldBattle = islandCache.store(CACHE_KEY, enderDragonBattle); if (oldBattle != null) this.worldDragonBattlesList.remove(oldBattle); this.worldDragonBattlesList.add(enderDragonBattle); } @Nullable public IslandEnderDragonBattle getDragonBattle(IslandCache islandCache) { return islandCache.get(CACHE_KEY); } @Nullable public IslandEnderDragonBattle removeDragonBattle(IslandCache islandCache) { IslandEnderDragonBattle enderDragonBattle = islandCache.remove(CACHE_KEY); if (enderDragonBattle != null) this.worldDragonBattlesList.remove(enderDragonBattle); return enderDragonBattle; } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.NMSUtils; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockPredicate; import net.minecraft.server.v1_16_R3.Blocks; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.DragonControllerLanding; import net.minecraft.server.v1_16_R3.DragonControllerPhase; import net.minecraft.server.v1_16_R3.EnderDragonBattle; import net.minecraft.server.v1_16_R3.EntityEnderDragon; import net.minecraft.server.v1_16_R3.EntityPlayer; import net.minecraft.server.v1_16_R3.HeightMap; import net.minecraft.server.v1_16_R3.IDragonController; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.ShapeDetector; import net.minecraft.server.v1_16_R3.ShapeDetectorBlock; import net.minecraft.server.v1_16_R3.ShapeDetectorBuilder; import net.minecraft.server.v1_16_R3.TileEntity; import net.minecraft.server.v1_16_R3.TileEntityEnderPortal; import net.minecraft.server.v1_16_R3.Vec3D; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; import java.lang.reflect.Modifier; import java.util.HashSet; import java.util.Set; import java.util.UUID; public class IslandEnderDragonBattle extends EnderDragonBattle { private static final ReflectField DRAGON_BATTLE = new ReflectField( EntityEnderDragon.class, EnderDragonBattle.class, Modifier.PRIVATE | Modifier.FINAL, 1) .removeFinal(); private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( EnderDragonBattle.class, boolean.class, Modifier.PRIVATE, 3); private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( EnderDragonBattle.class, boolean.class, Modifier.PRIVATE, 1); private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( DragonControllerLanding.class, Vec3D.class, Modifier.PRIVATE, 1); private static final ShapeDetector EXIT_PORTAL_PATTERN = ShapeDetectorBuilder.a() .a(new String[]{" ", " ", " ", " # ", " ", " ", " "}) .a(new String[]{" ", " ", " ", " # ", " ", " ", " "}) .a(new String[]{" ", " ", " ", " # ", " ", " ", " "}) .a(new String[]{" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### "}) .a(new String[]{" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " "}) .a('#', ShapeDetectorBlock.a(BlockPredicate.a(Blocks.BEDROCK))) .b(); private final Island island; private final BlockPosition islandBlockPosition; private final Vec3D islandBlockVectored; private final IslandEntityEnderDragon entityEnderDragon; private byte currentTick = 0; public IslandEnderDragonBattle(Island island, WorldServer worldServer, Location location) { this(island, worldServer, new BlockPosition(location.getX(), location.getY(), location.getZ()), null); } public IslandEnderDragonBattle(Island island, WorldServer worldServer, BlockPosition islandBlockPosition, @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { super(worldServer, worldServer.getSeed(), new NBTTagCompound()); SCAN_FOR_LEGACY_PORTALS.set(this, false); WAS_DRAGON_KILLED.set(this, false); this.island = island; this.islandBlockPosition = islandBlockPosition; this.islandBlockVectored = Vec3D.c(islandBlockPosition); this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; DRAGON_BATTLE.set(this.entityEnderDragon, this); } @Override public void b() { // doServerTick DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::b); IDragonController currentController = this.entityEnderDragon.getDragonControllerManager().a(); if (currentController instanceof DragonControllerLanding && !this.islandBlockVectored.equals(currentController.g())) { LANDING_TARGET_POSITION.set(currentController, this.islandBlockVectored); } if (++currentTick >= 20) { updateBattlePlayers(); currentTick = 0; } } @Nullable @Override public ShapeDetector.ShapeDetectorCollection getExitPortalShape() { // findExitPortal int chunkX = this.islandBlockPosition.getX() >> 4; int chunkZ = this.islandBlockPosition.getZ() >> 4; for (int x = -8; x <= 8; ++x) { for (int z = -8; z <= 8; ++z) { Chunk chunk = this.world.getChunkAt(chunkX + x, chunkZ + z); for (TileEntity tileEntity : chunk.getTileEntities().values()) { if (tileEntity instanceof TileEntityEnderPortal) { ShapeDetector.ShapeDetectorCollection shapeDetectorCollection = EXIT_PORTAL_PATTERN.a(this.world, tileEntity.getPosition()); if (shapeDetectorCollection != null) { if (this.exitPortalLocation == null) this.exitPortalLocation = shapeDetectorCollection.a(3, 3, 3).getPosition(); return shapeDetectorCollection; } } } } } int highestBlock = this.world.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING, this.islandBlockPosition).getY(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition currentPosition = wrapper.getHandle(); currentPosition.d(this.islandBlockPosition.getX(), 0, this.islandBlockPosition.getZ()); for (int y = highestBlock; y >= 0; --y) { currentPosition.setY(y); ShapeDetector.ShapeDetectorCollection shapeDetectorCollection = EXIT_PORTAL_PATTERN.a(this.world, currentPosition); if (shapeDetectorCollection != null) { if (this.exitPortalLocation == null) this.exitPortalLocation = shapeDetectorCollection.a(3, 3, 3).getPosition(); return shapeDetectorCollection; } } } return null; } @Override public void resetCrystals() { // resetSpikeCrystals DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::resetCrystals); } public void removeBattlePlayers() { this.bossBattle.getPlayers().forEach(this.bossBattle::removePlayer); } public IslandEntityEnderDragon getEnderDragon() { return this.entityEnderDragon; } private void updateBattlePlayers() { Set nearbyPlayers = new HashSet<>(); WorldInfo worldInfo = WorldInfo.of(this.world.getWorld()); try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { strategy.getPlayers(worldInfo).forEach(player -> { EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); this.bossBattle.addPlayer(entityPlayer); nearbyPlayers.add(entityPlayer.getUniqueID()); }); } this.bossBattle.getPlayers().stream() .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUniqueID())) .forEach(this.bossBattle::removePlayer); } private IslandEntityEnderDragon spawnEnderDragon() { IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.world, islandBlockPosition); entityEnderDragon.getDragonControllerManager().setControllerPhase(DragonControllerPhase.HOLDING_PATTERN); entityEnderDragon.setPositionRotation(islandBlockPosition.getX(), 128, islandBlockPosition.getZ(), this.world.getRandom().nextFloat() * 360.0F, 0.0F); this.world.addEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); this.dragonUUID = entityEnderDragon.getUniqueID(); this.resetCrystals(); // scan for crystals return entityEnderDragon; } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.DifficultyDamageScaler; import net.minecraft.server.v1_16_R3.EntityEnderDragon; import net.minecraft.server.v1_16_R3.EntityTypes; import net.minecraft.server.v1_16_R3.EnumMobSpawn; import net.minecraft.server.v1_16_R3.GroupDataEntity; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.World; import net.minecraft.server.v1_16_R3.WorldAccess; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEnderDragon; public class IslandEntityEnderDragon extends EntityEnderDragon { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public static EntityEnderDragon fromEntityTypes(EntityTypes entityTypes, World world) { return plugin.getGrid().isIslandsWorld(world.getWorld()) ? new IslandEntityEnderDragon(world) : new EntityEnderDragon(entityTypes, world); } private final Dimension dimension; private BlockPosition islandBlockPosition; public IslandEntityEnderDragon(WorldServer worldServer, BlockPosition islandBlockPosition) { this(worldServer); this.islandBlockPosition = islandBlockPosition; } private IslandEntityEnderDragon(World world) { super(EntityTypes.ENDER_DRAGON, world); this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world.getWorld()); } @Nullable @Override public GroupDataEntity prepare(WorldAccess worldaccess, DifficultyDamageScaler difficultydamagescaler, EnumMobSpawn enummobspawn, @Nullable GroupDataEntity groupdataentity, @Nullable NBTTagCompound nbttagcompound) { if (this.islandBlockPosition == null) finalizeIslandEnderDragon(); return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound); } @Override public void loadData(NBTTagCompound nbtTagCompound) { super.loadData(nbtTagCompound); finalizeIslandEnderDragon(); } @Override public void movementTick() { DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::movementTick); } @Override public CraftEnderDragon getBukkitEntity() { return (CraftEnderDragon) super.getBukkitEntity(); } private void finalizeIslandEnderDragon() { if (!(world instanceof WorldServer) || !(((WorldServer) world).getDragonBattle() instanceof EndWorldEnderDragonBattleHandler)) return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) ((WorldServer) world).getDragonBattle(); Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); } if (island == null) return; Location middleBlock = island.getCenter(dimension); SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); if (dimensionConfig instanceof SettingsManager.Worlds.End) { middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); } this.islandBlockPosition = new BlockPosition(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ()); IslandEnderDragonBattle dragonBattle = new IslandEnderDragonBattle(island, (WorldServer) world, this.islandBlockPosition, this); dragonBattleHandler.addDragonBattle(island.getCache(), dragonBattle); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/SpikesCache.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon; import com.bgsoftware.common.annotations.Nullable; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheStats; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.MathHelper; import net.minecraft.server.v1_16_R3.WorldGenEnder; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; public class SpikesCache implements LoadingCache> { private static final SpikesCache INSTANCE = new SpikesCache(); private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); private long worldSeed; public static SpikesCache getInstance() { return INSTANCE; } private SpikesCache() { } @Override public List get(Long worldSeed) throws ExecutionException { try { this.worldSeed = worldSeed; return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); } finally { this.worldSeed = 0; } } @Override public List getUnchecked(Long worldSeed) { try { this.worldSeed = worldSeed; return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); } finally { this.worldSeed = 0; } } @Override public ImmutableMap> getAll(Iterable keys) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public List apply(Long worldSeed) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public void refresh(Long worldSeed) { try { this.worldSeed = worldSeed; cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); } finally { this.worldSeed = 0; } } @Override public ConcurrentMap> asMap() { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Nullable @Override public List getIfPresent(Object worldSeed) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public List get(Long worldSeed, Callable> loader) throws ExecutionException { try { this.worldSeed = worldSeed; return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); } finally { this.worldSeed = 0; } } @Override public ImmutableMap> getAllPresent(Iterable keys) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public void put(Long worldSeed, List spikes) { try { this.worldSeed = worldSeed; cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); } finally { this.worldSeed = 0; } } @Override public void putAll(Map> spikesMap) { spikesMap.forEach(this::put); } @Override public void invalidate(Object worldSeed) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public void invalidateAll(Iterable keys) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public void invalidateAll() { this.cachedSpikes.invalidateAll(); } @Override public long size() { return this.cachedSpikes.size(); } @Override public CacheStats stats() { return this.cachedSpikes.stats(); } @Override public void cleanUp() { this.cachedSpikes.cleanUp(); } private class InternalCacheLoader extends CacheLoader> { @Override public List load(BlockPosition blockPosition) { List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); Collections.shuffle(list, new Random(worldSeed)); List spikesList = Lists.newArrayList(); for (int i = 0; i < 10; ++i) { int spikeX = MathHelper.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); int spikeZ = MathHelper.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); int l = list.get(i); int radius = 2 + l / 3; int height = 76 + l * 3; boolean guarded = l == 1 || l == 2; spikesList.add(new WorldGenEnder.Spike(spikeX + blockPosition.getX(), spikeZ + blockPosition.getZ(), radius, height, guarded)); } return spikesList; } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/generator/IslandsGeneratorImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.generator; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_16_R3.BiomeBase; import net.minecraft.server.v1_16_R3.BiomeStorage; import net.minecraft.server.v1_16_R3.IRegistry; import net.minecraft.server.v1_16_R3.Registry; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random; @SuppressWarnings({"unused", "NullableProblems"}) public class IslandsGeneratorImpl extends IslandsGenerator { private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( BiomeStorage.class, BiomeBase[].class, "h"); private static final ReflectField> BIOME_REGISTRY = new ReflectField<>( BiomeStorage.class, Registry.class, "registry", "g"); private static final ReflectField BIOME_STORAGE = new ReflectField<>( new ClassInfo("generator.CustomChunkGenerator$CustomBiomeGrid", ClassInfo.PackageType.CRAFTBUKKIT), BiomeStorage.class, "biome"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Dimension dimension; public IslandsGeneratorImpl(Dimension dimension) { this.dimension = dimension; } @Override public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) { ChunkData chunkData = createChunkData(world); Biome targetBiome = IslandUtils.getDefaultWorldBiome(this.dimension); setBiome(biomeGrid, targetBiome); if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { chunkData.setBlock(0, 99, 0, Material.BEDROCK); } return chunkData; } @Override public List getDefaultPopulators(World world) { return Collections.emptyList(); } @Override public Location getFixedSpawnLocation(World world, Random random) { return new Location(world, 0, 100, 0); } private static void setBiome(ChunkGenerator.BiomeGrid biomeGrid, Biome biome) { BiomeStorage biomeStorage = BIOME_STORAGE.get(biomeGrid); BiomeBase[] biomeBases = BIOME_BASE_ARRAY.get(biomeStorage); BiomeBase biomeBase = CraftBlock.biomeToBiomeBase((IRegistry) BIOME_REGISTRY.get(biomeStorage), biome); if (biomeBases == null) return; Arrays.fill(biomeBases, biomeBase); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/menu/MenuTileEntityBrewing.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu; import net.minecraft.server.v1_16_R3.ChatMessage; import net.minecraft.server.v1_16_R3.TileEntityBrewingStand; import org.bukkit.inventory.InventoryHolder; public class MenuTileEntityBrewing extends TileEntityBrewingStand { private final InventoryHolder holder; public MenuTileEntityBrewing(InventoryHolder holder, String title) { this.holder = holder; this.setCustomName(new ChatMessage(title)); } @Override public InventoryHolder getOwner() { return holder; } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/menu/MenuTileEntityDispenser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu; import net.minecraft.server.v1_16_R3.ChatMessage; import net.minecraft.server.v1_16_R3.TileEntityDispenser; import org.bukkit.inventory.InventoryHolder; public class MenuTileEntityDispenser extends TileEntityDispenser { private final InventoryHolder holder; public MenuTileEntityDispenser(InventoryHolder holder, String title) { this.holder = holder; this.setCustomName(new ChatMessage(title)); } @Override public InventoryHolder getOwner() { return holder; } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/menu/MenuTileEntityFurnace.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu; import net.minecraft.server.v1_16_R3.ChatMessage; import net.minecraft.server.v1_16_R3.TileEntityFurnaceFurnace; import org.bukkit.inventory.InventoryHolder; public class MenuTileEntityFurnace extends TileEntityFurnaceFurnace { private final InventoryHolder holder; public MenuTileEntityFurnace(InventoryHolder holder, String title) { this.holder = holder; this.setCustomName(new ChatMessage(title)); } @Override public InventoryHolder getOwner() { return holder; } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/menu/MenuTileEntityHopper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu; import net.minecraft.server.v1_16_R3.ChatMessage; import net.minecraft.server.v1_16_R3.TileEntityHopper; import org.bukkit.inventory.InventoryHolder; public class MenuTileEntityHopper extends TileEntityHopper { private final InventoryHolder holder; public MenuTileEntityHopper(InventoryHolder holder, String title) { this.holder = holder; this.setCustomName(new ChatMessage(title)); } @Override public InventoryHolder getOwner() { return holder; } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/player/OfflinePlayerDataImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.player; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.mojang.authlib.GameProfile; import net.minecraft.server.v1_16_R3.EntityPlayer; import net.minecraft.server.v1_16_R3.MinecraftServer; import net.minecraft.server.v1_16_R3.PlayerInteractManager; import net.minecraft.server.v1_16_R3.World; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.craftbukkit.v1_16_R3.CraftServer; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.Optional; public class OfflinePlayerDataImpl implements OfflinePlayerData { private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); private Player fakePlayer; public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { return POOL.obtain().initialize(offlinePlayer); } private OfflinePlayerDataImpl() { } private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); WorldServer worldServer = server.getWorldServer(World.OVERWORLD); assert worldServer != null; EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); this.fakePlayer = entityPlayer.getBukkitEntity(); this.fakePlayer.loadData(); return this; } @Override public Player getFakeOnlinePlayer() { return this.fakePlayer; } @Override public void setLocation(Location location) { EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle(); entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } @Override public void applyChanges() { this.fakePlayer.saveData(); } @Override public void release() { this.fakePlayer = null; POOL.release(this); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/spawners/TileEntityMobSpawnerNotifier.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.spawners; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.server.v1_16_R3.MobSpawnerAbstract; import net.minecraft.server.v1_16_R3.TileEntityMobSpawner; import java.lang.reflect.Modifier; import java.util.function.IntFunction; public class TileEntityMobSpawnerNotifier extends TileEntityMobSpawner { private static final ReflectField MOB_SPAWNER_ABSTRACT; static { // In Airplane, the modifiers of the field is `public final` instead of `private final` // as it is in Paper and Spigot. We want to make sure we support all jars. ReflectField mobSpawnerAbstract = new ReflectField<>( TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PRIVATE | Modifier.FINAL, 1); if (mobSpawnerAbstract.isValid()) { MOB_SPAWNER_ABSTRACT = mobSpawnerAbstract; } else { MOB_SPAWNER_ABSTRACT = new ReflectField<>(TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PUBLIC | Modifier.FINAL, 1); } MOB_SPAWNER_ABSTRACT.removeFinal(); } private final TileEntityMobSpawner tileEntityMobSpawner; private final IntFunction delayChangeCallback; public TileEntityMobSpawnerNotifier(TileEntityMobSpawner tileEntityMobSpawner, IntFunction delayChangeCallback) { this.tileEntityMobSpawner = tileEntityMobSpawner; this.delayChangeCallback = delayChangeCallback; this.position = tileEntityMobSpawner.getPosition(); this.world = tileEntityMobSpawner.getWorld(); MOB_SPAWNER_ABSTRACT.set(this, tileEntityMobSpawner.getSpawner()); updateDelay(); } @Override public void tick() { MobSpawnerAbstract mobSpawnerAbstract = tileEntityMobSpawner.getSpawner(); int startDelay = mobSpawnerAbstract.spawnDelay; try { tileEntityMobSpawner.tick(); } finally { int newDelay = mobSpawnerAbstract.spawnDelay; if (newDelay > startDelay) updateDelay(); } } public void updateDelay() { MobSpawnerAbstract mobSpawnerAbstract = tileEntityMobSpawner.getSpawner(); mobSpawnerAbstract.spawnDelay = delayChangeCallback.apply(mobSpawnerAbstract.spawnDelay); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockEntityCache.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.IRegistry; import net.minecraft.server.v1_16_R3.MinecraftKey; import net.minecraft.server.v1_16_R3.TileEntityTypes; import java.util.IdentityHashMap; import java.util.Map; public class BlockEntityCache { private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); private BlockEntityCache() { } public static String getTileEntityId(IBlockData blockData) { return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> { for (TileEntityTypes tileEntityTypes : IRegistry.BLOCK_ENTITY_TYPE) { if (tileEntityTypes.isValidBlock(block)) { MinecraftKey minecraftKey = TileEntityTypes.a(tileEntityTypes); if (minecraftKey != null) return minecraftKey.getKey(); } } return ""; }); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockStatesMapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.logging.Log; import net.minecraft.server.v1_16_R3.IBlockState; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class BlockStatesMapper { private static final Map> nameToBlockState = new HashMap<>(); private static final Map, String> blockStateToName = new HashMap<>(); static { Map fieldNameToName = new HashMap<>(); fieldNameToName.put("F", "axis-empty"); fieldNameToName.put("N", "facing-notup"); fieldNameToName.put("O", "facing-horizontal"); fieldNameToName.put("S", "wall-east"); fieldNameToName.put("T", "wall-north"); fieldNameToName.put("U", "wall-south"); fieldNameToName.put("V", "wall-west"); fieldNameToName.put("W", "redstone-east"); fieldNameToName.put("X", "redstone-north"); fieldNameToName.put("Y", "redstone-south"); fieldNameToName.put("Z", "redstone-west"); fieldNameToName.put("aa", "double-half"); fieldNameToName.put("ac", "track-shape-empty"); fieldNameToName.put("ad", "track-shape"); fieldNameToName.put("ae", "age1"); fieldNameToName.put("af", "age2"); fieldNameToName.put("ag", "age3"); fieldNameToName.put("ah", "age5"); fieldNameToName.put("ai", "age7"); fieldNameToName.put("aj", "age15"); fieldNameToName.put("ak", "age25"); fieldNameToName.put("ar", "level3"); fieldNameToName.put("as", "level8"); fieldNameToName.put("at", "level1-8"); fieldNameToName.put("av", "level15"); fieldNameToName.put("an", "distance1-7"); fieldNameToName.put("aB", "distance7"); fieldNameToName.put("aF", "chest-type"); fieldNameToName.put("aG", "comparator-mode"); fieldNameToName.put("aJ", "piston-type"); fieldNameToName.put("aK", "slab-type"); try { // Fixes BlockProperties being private-class in some versions of Yatopia causing illegal access errors. Class blockPropertiesClass = Class.forName("net.minecraft.server.v1_16_R3.BlockProperties"); for (Field field : blockPropertiesClass.getFields()) { field.setAccessible(true); Object value = field.get(null); if (value instanceof IBlockState) { register(fieldNameToName.getOrDefault(field.getName(), ((IBlockState) value).getName()), field.getName(), (IBlockState) value); } } } catch (Exception error) { Log.error(error, "An unexpected error occurred while loading block states mapper:"); } } private static void register(String key, String fieldName, IBlockState blockState) { if (nameToBlockState.containsKey(key)) { Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); } else { nameToBlockState.put(key, blockState); blockStateToName.put(blockState, key); } } @Nullable public static IBlockState getBlockState(String name) { return nameToBlockState.get(name); } @Nullable public static String getBlockStateName(IBlockState blockState) { return blockStateToName.get(blockState); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.NextTickListEntry; import net.minecraft.server.v1_16_R3.TickListServer; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlockState; import java.lang.reflect.Modifier; import java.util.List; import java.util.function.Consumer; public class BlockTickListServerTracker { private static final ReflectField>> TICK_FUNCTION_SPIGOT = new ReflectField>>(TickListServer.class, Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField>> TICK_FUNCTION_PAPER = new ReflectField>>( new ClassInfo("com.destroystokyo.paper.server.ticklist.PaperTickList", ClassInfo.PackageType.UNKNOWN), Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private BlockTickListServerTracker() { } public static void listenForTicks(WorldServer worldServer) { TickListServer blockTicks = worldServer.getBlockTickList(); if (TICK_FUNCTION_PAPER.isValid()) { TICK_FUNCTION_PAPER.set(blockTicks, nextTickData -> tick(worldServer, nextTickData)); } else { TICK_FUNCTION_SPIGOT.set(blockTicks, nextTickData -> tick(worldServer, nextTickData)); } } private static void tick(WorldServer worldServer, NextTickListEntry nextTickData) { BlockPosition blockPosition = nextTickData.getPosition(); IBlockData blockState = worldServer.getType(blockPosition); if (blockState.a(nextTickData.b())) { IBlockData oldData = worldServer.getType(blockPosition); try { plugin.getGameEventsDispatcher().startCaptureEvents(); blockState.a(worldServer, blockPosition, worldServer.random); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in that tick. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } IBlockData newData = worldServer.getType(blockPosition); if (oldData.getBlock() != newData.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(worldServer, blockPosition); CraftBlockState oldState = CraftBlockState.getBlockState(worldServer, blockPosition, 3); oldState.setData(oldData); blockUpdateShapeEvent.oldState = oldState; GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockStateBoolean; import net.minecraft.server.v1_16_R3.BlockStateInteger; import net.minecraft.server.v1_16_R3.Blocks; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; import net.minecraft.server.v1_16_R3.ChunkSection; import net.minecraft.server.v1_16_R3.DataPaletteBlock; import net.minecraft.server.v1_16_R3.Entity; import net.minecraft.server.v1_16_R3.EnumSkyBlock; import net.minecraft.server.v1_16_R3.GameProfileSerializer; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.LightEngine; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.NBTTagFloat; import net.minecraft.server.v1_16_R3.NibbleArray; import net.minecraft.server.v1_16_R3.SectionPosition; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; import org.bukkit.inventory.InventoryHolder; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class ChunkReaderImpl implements ChunkReader { private static final DataPaletteBlock EMPTY_BLOCKS = new ChunkSection(0).getBlocks(); private static final byte[] EMPTY_LIGHT = new byte[2048]; private final int x; private final int z; private final Map tileEntities = new HashMap<>(); private final List entities = new LinkedList<>(); private final DataPaletteBlock[] blockids; private final byte[][] skylight; private final byte[][] emitlight; public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkCoordIntPair chunkCoords = chunk.getPos(); this.x = chunkCoords.x; this.z = chunkCoords.z; ChunkSection[] chunkSections = chunk.getSections(); this.blockids = new DataPaletteBlock[chunkSections.length]; this.skylight = new byte[chunkSections.length][]; this.emitlight = new byte[chunkSections.length][]; LightEngine lightEngine = chunk.world.getChunkProvider().getLightEngine(); for (int i = 0; i < this.blockids.length; ++i) { ChunkSection chunkSection = chunkSections[i]; if (chunkSection == null) { this.blockids[i] = EMPTY_BLOCKS; this.skylight[i] = EMPTY_LIGHT; this.emitlight[i] = EMPTY_LIGHT; } else { this.blockids[i] = copyDataPalette(chunkSection.getBlocks()); NibbleArray skyLightArray = lightEngine.a(EnumSkyBlock.SKY).a(SectionPosition.a(this.x, i, this.z)); if (skyLightArray == null) { this.skylight[i] = EMPTY_LIGHT; } else { this.skylight[i] = new byte[2048]; if (!skyLightArray.c()) System.arraycopy(skyLightArray.asBytes(), 0, this.skylight[i], 0, 2048); } NibbleArray emitLightArray = lightEngine.a(EnumSkyBlock.BLOCK).a(SectionPosition.a(this.x, i, this.z)); if (emitLightArray == null) { this.emitlight[i] = EMPTY_LIGHT; } else { this.emitlight[i] = new byte[2048]; if (!emitLightArray.c()) System.arraycopy(emitLightArray.asBytes(), 0, this.emitlight[i], 0, 2048); } } } chunk.getTileEntities().forEach((blockPosition, tileEntity) -> { NBTTagCompound tileEntityCompound = tileEntity.save(new NBTTagCompound()); tileEntityCompound.remove("x"); tileEntityCompound.remove("y"); tileEntityCompound.remove("z"); InventoryHolder inventoryHolder = tileEntity.getOwner(); if (inventoryHolder != null) tileEntityCompound.setString("inventoryType", inventoryHolder.getInventory().getType().name()); tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound)); }); for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); } @Override public int getX() { return this.x; } @Override public int getZ() { return this.z; } @Override public Material getType(int x, int y, int z) { return CraftMagicNumbers.getMaterial(getBlockData(x, y, z).getBlock()); } @Override public short getData(int x, int y, int z) { return CraftMagicNumbers.toLegacyData(getBlockData(x, y, z)); } @Override @Nullable public CompoundTag getTileEntity(int x, int y, int z) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.d((this.x << 4) + x, y, (this.z << 4) + z); return this.tileEntities.get(blockPosition); } } @Override @Nullable public CompoundTag readBlockStates(int x, int y, int z) { IBlockData blockData = getBlockData(x, y, z); if (blockData.getStateMap().isEmpty()) return null; CompoundTag compoundTag = CompoundTag.of(); blockData.getStateMap().forEach((blockState, value) -> { Class keyClass = blockState.getClass(); String name = BlockStatesMapper.getBlockStateName(blockState); if (keyClass.equals(BlockStateBoolean.class)) { compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); } else if (keyClass.equals(BlockStateInteger.class)) { BlockStateInteger key = (BlockStateInteger) blockState; compoundTag.setIntArray(name, new int[]{(Integer) value, key.min, key.max}); } else { compoundTag.setString(name, ((Enum) value).name()); } }); return compoundTag; } @Override public byte[] getLightLevels(int x, int y, int z) { int off = (y & 15) << 7 | z << 3 | x >> 1; int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15; int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15; return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; } @Override public void forEachEntity(EntityConsumer consumer) { if (entities.isEmpty()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = wrapper.getHandle(); for (CachedEntity cachedEntity : entities) { location.setX(cachedEntity.x); location.setY(cachedEntity.y); location.setZ(cachedEntity.z); location.setYaw(cachedEntity.yaw); location.setPitch(cachedEntity.pitch); consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); } } } private IBlockData getBlockData(int x, int y, int z) { return this.blockids[y >> 4].a(x, y & 15, z); } private static DataPaletteBlock copyDataPalette(DataPaletteBlock original) { NBTTagCompound data = new NBTTagCompound(); original.a(data, "Palette", "BlockStates"); DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData()); blockids.a(data.getList("Palette", 10), data.getLongArray("BlockStates")); return blockids; } private static class CachedEntity { private final double x; private final double y; private final double z; private final float yaw; private final float pitch; private final EntityType entityType; private final CompoundTag entityTag; CachedEntity(Entity entity) { this.x = entity.locX(); this.y = entity.locY(); this.z = entity.locZ(); this.yaw = entity.getBukkitYaw(); this.pitch = entity.pitch; this.entityType = entity.getBukkitEntity().getType(); NBTTagCompound nbtTagCompound = new NBTTagCompound(); entity.save(nbtTagCompound); nbtTagCompound.set("Yaw", NBTTagFloat.a(entity.yaw)); nbtTagCompound.set("Pitch", NBTTagFloat.a(entity.pitch)); this.entityTag = CompoundTag.fromNBT(nbtTagCompound); } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/KeyBlocksCache.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.key.Keys; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.IRegistry; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; import java.util.IdentityHashMap; import java.util.Map; public class KeyBlocksCache { private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); private KeyBlocksCache() { } public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } public static void cacheAllBlocks() { IRegistry.BLOCK.forEach(KeyBlocksCache::getBlockKey); } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionDataImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; import net.minecraft.server.v1_16_R3.ChunkSection; import net.minecraft.server.v1_16_R3.HeightMap; import net.minecraft.server.v1_16_R3.IBlockData; import org.bukkit.Location; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Supplier; public class WorldEditSessionDataImpl implements WorldEditSession.Data { private static final boolean isStarLightInterface = ((Supplier) () -> { try { Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); return true; } catch (ClassNotFoundException error) { return false; } }).get(); private final List> chunks = new LinkedList<>(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, List> blocksToUpdate, List> blockEntities, Set lightenChunks) { int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); int baseChunkPosXAxis = baseBlockPosXAxis >> 4; int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // Convert chunk data Iterator> chunksIterator = chunks.entryIterator(); while (chunksIterator.hasNext()) { Long2ObjectMapView.Entry entry = chunksIterator.next(); int currChunkPosXAxis = ChunkCoordIntPair.getX(entry.getKey()); int currChunkPosZAxis = ChunkCoordIntPair.getZ(entry.getKey()); WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); List> lights; if (isStarLightInterface || chunkData.lights().isEmpty()) { lights = Collections.emptyList(); } else { lights = new LinkedList<>(); chunkData.lights().forEach(lightPosition -> { lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, null)); }); } PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), chunkData.heightmaps(), lights); this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); } // Convert blocksToUpdate blocksToUpdate.forEach(blockToUpdate -> { BlockPosition blockPos = blockToUpdate.getKey(); this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, blockToUpdate.getValue())); }); // Convert blockEntities blockEntities.forEach(blockEntity -> { BlockPosition blockPos = blockEntity.getKey(); this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, blockEntity.getValue())); }); // Convert lights lightenChunks.forEach(lightPosition -> { this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, lightPosition.z - baseChunkPosZAxis, null)); }); } public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, Long2ObjectMapView chunks) { this.chunks.forEach(chunkDataPositioned -> { long newPos = ChunkCoordIntPair.pair(baseChunkPosXAxis + chunkDataPositioned.xOffset, baseChunkPosZAxis + chunkDataPositioned.zOffset); List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); chunkDataPositioned.object.lights.forEach(lightPositioned -> { lights.add(new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset, baseBlockPosYAxis + lightPositioned.yOffset, baseBlockPosZAxis + lightPositioned.zOffset)); }); chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, chunkDataPositioned.object.heightmaps, lights)); }); } public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { this.blocksToUpdate.forEach(blockToUpdatePositioned -> { BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, baseBlockPosYAxis + blockToUpdatePositioned.yOffset, baseBlockPosZAxis + blockToUpdatePositioned.zOffset); blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); }); } public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { this.blockEntities.forEach(blockEntityPositioned -> { BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset, baseBlockPosYAxis + blockEntityPositioned.yOffset, baseBlockPosZAxis + blockEntityPositioned.zOffset); blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); }); } public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { this.lightenChunks.forEach(lightPositioned -> { ChunkCoordIntPair newPos = new ChunkCoordIntPair(baseChunkPosXAxis + lightPositioned.xOffset, baseChunkPosZAxis + lightPositioned.zOffset); lightenChunks.add(newPos); }); } private static class PositionedObject { private final int xOffset; private final int yOffset; private final int zOffset; private final V object; PositionedObject(int xOffset, int zOffset, V object) { this(xOffset, 0, zOffset, object); } PositionedObject(int xOffset, int yOffset, int zOffset, V object) { this.xOffset = xOffset; this.yOffset = yOffset; this.zOffset = zOffset; this.object = object; } } private static class PositionedChunkData { private final ChunkSection[] chunkSections; private final Map heightmaps; private final List> lights; public PositionedChunkData(ChunkSection[] chunkSections, Map heightmaps, List> lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } } } ================================================ FILE: NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.google.common.base.Preconditions; import net.minecraft.server.v1_16_R3.BiomeBase; import net.minecraft.server.v1_16_R3.BiomeStorage; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockBed; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.ChunkConverter; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; import net.minecraft.server.v1_16_R3.ChunkSection; import net.minecraft.server.v1_16_R3.ChunkStatus; import net.minecraft.server.v1_16_R3.FluidType; import net.minecraft.server.v1_16_R3.FluidTypes; import net.minecraft.server.v1_16_R3.HeightMap; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.IBlockState; import net.minecraft.server.v1_16_R3.IRegistry; import net.minecraft.server.v1_16_R3.LightEngineThreaded; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.ProtoChunk; import net.minecraft.server.v1_16_R3.ProtoChunkTickList; import net.minecraft.server.v1_16_R3.RegionLimitedWorldAccess; import net.minecraft.server.v1_16_R3.TileEntity; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_16_R3.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Supplier; public class WorldEditSessionImpl implements WorldEditSession { private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( BiomeStorage.class, BiomeBase[].class, "h"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { Class.forName("ca.spottedleaf.starlight.common.light.StarLightInterface"); return true; } catch (ClassNotFoundException error) { return false; } }).get(); private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectHashMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); private Dimension dimension; @Nullable private WorldServer worldServer; public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } public static WorldEditSessionImpl obtain(Dimension dimension) { return POOL.obtain().initialize(dimension); } private WorldEditSessionImpl() { } private WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); return this; } private WorldEditSessionImpl initialize(Dimension dimension) { this.worldServer = null; this.dimension = dimension; return this; } @Override public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData) { BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); if (!isValidPosition(blockPosition)) return; IBlockData blockData = Block.getByCombinedId(combinedId); if (statesTag != null) { for (Map.Entry> entry : statesTag.entrySet()) { try { // noinspection rawtypes IBlockState blockState = BlockStatesMapper.getBlockState(entry.getKey()); if (blockState != null) { if (entry.getValue() instanceof ByteTag) { // noinspection unchecked blockData = blockData.set(blockState, ((ByteTag) entry.getValue()).getValue() == 1); } else if (entry.getValue() instanceof IntArrayTag) { int[] data = ((IntArrayTag) entry.getValue()).getValue(); // noinspection unchecked blockData = blockData.set(blockState, data[0]); } else if (entry.getValue() instanceof StringTag) { String data = ((StringTag) entry.getValue()).getValue(); // noinspection unchecked blockData = blockData.set(blockState, Enum.valueOf(blockState.getType(), data)); } } } catch (Exception ignored) { } } } if ((blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || blockData.getBlock() instanceof BlockBed) { blocksToUpdate.add(new Pair<>(blockPosition, blockData)); return; } ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(blockPosition); if (blockEntityData != null) blockEntities.add(new Pair<>(blockPosition, blockEntityData)); ChunkData chunkData = this.chunks.computeIfAbsent(chunkCoord.pair(), ChunkData::new); if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockData.f() > 0) chunkData.lights.add(blockPosition); ChunkSection chunkSection = chunkData.chunkSections[blockPosition.getY() >> 4]; int blockX = blockPosition.getX() & 15; int blockY = blockPosition.getY(); int blockZ = blockPosition.getZ() & 15; chunkSection.setType(blockX, blockY & 15, blockZ, blockData, false); chunkData.heightmaps.get(HeightMap.Type.MOTION_BLOCKING).a(blockX, blockY, blockZ, blockData); chunkData.heightmaps.get(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES).a(blockX, blockY, blockZ, blockData); chunkData.heightmaps.get(HeightMap.Type.OCEAN_FLOOR).a(blockX, blockY, blockZ, blockData); chunkData.heightmaps.get(HeightMap.Type.WORLD_SURFACE).a(blockX, blockY, blockZ, blockData); } @Override public List getAffectedChunks() { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); if (chunks.isEmpty()) return Collections.emptyList(); List chunkPositions = new LinkedList<>(); World bukkitWorld = worldServer.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); int chunkX = (int) chunkKey; int chunkZ = (int) (chunkKey >> 32); chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkCoordIntPair chunkCoord = chunk.getPos(); ChunkData chunkData = this.chunks.remove(chunkCoord.pair()); if (chunkData == null) return; int chunkSectionsCount = Math.min(chunkData.chunkSections.length, chunk.getSections().length); for (int i = 0; i < chunkSectionsCount; ++i) { chunk.getSections()[i] = chunkData.chunkSections[i]; } chunkData.heightmaps.forEach(((type, heightmap) -> { chunk.a(type, heightmap.a()); })); // Update the biome for the chunk BiomeBase[] biomes = BIOME_BASE_ARRAY.get(chunk.getBiomeIndex()); if (biomes != null) { IRegistry biomesRegistry = worldServer.r().b(IRegistry.ay); BiomeBase biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(this.dimension)); Arrays.fill(biomes, biome); } if (plugin.getSettings().isLightsUpdate()) { if (isStarLightInterface) { this.lightenChunks.add(chunkCoord); } else { LightEngineThreaded lightEngineThreaded = worldServer.getChunkProvider().getLightEngine(); chunkData.lights.forEach(lightEngineThreaded::a); // Queues chunk light for this chunk. lightEngineThreaded.a(chunk, false); } } chunk.setNeedsSaving(true); } @Override public void finish(Island island) { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); // Update block entities blockEntities.forEach(data -> { NBTTagCompound blockEntityCompound = (NBTTagCompound) data.getValue().toNBT(); if (blockEntityCompound != null) { BlockPosition blockPosition = data.getKey(); blockEntityCompound.setInt("x", blockPosition.getX()); blockEntityCompound.setInt("y", blockPosition.getY()); blockEntityCompound.setInt("z", blockPosition.getZ()); TileEntity worldTileEntity = worldServer.getTileEntity(blockPosition); if (worldTileEntity != null) worldTileEntity.load(worldServer.getType(blockPosition), blockEntityCompound); } }); if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { LightEngineThreaded lightEngineThreaded = worldServer.getChunkProvider().getLightEngine(); lightEngineThreaded.relight(lightenChunks, chunkCallback -> { }, completeCallback -> { }); this.lightenChunks.clear(); } release(); } @Override public Data readData(Location baseLocation) { return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override public void applyData(Data data, Location baseLocation) { WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); int baseChunkPosXAxis = baseBlockPosXAxis >> 4; int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this, this.chunks); dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.worldServer = null; this.dimension = null; POOL.release(this); } public ChunkData createChunkData(ChunkSection[] chunkSections, Map heightmaps, List lights) { return new ChunkData(chunkSections, heightmaps, lights); } private boolean isValidPosition(BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && blockPosition.getY() >= 0 && blockPosition.getY() < 256; } public class ChunkData { private final ChunkSection[] chunkSections; private final Map heightmaps; private final List lights; private ChunkData(long chunkKey) { this(new ChunkSection[16], new EnumMap<>(HeightMap.Type.class), new LinkedList<>()); ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(chunkKey); createChunkSections(); ProtoChunkTickList blockTickScheduler = new ProtoChunkTickList<>(block -> { return block == null || block.getBlockData().isAir(); }, chunkCoord); ProtoChunkTickList fluidTickScheduler = new ProtoChunkTickList<>((fluid) -> { return fluid == null || fluid == FluidTypes.EMPTY; }, chunkCoord); ProtoChunk tempChunk; try { tempChunk = new ProtoChunk(chunkCoord, ChunkConverter.a, this.chunkSections, blockTickScheduler, fluidTickScheduler, worldServer); } catch (Throwable error) { tempChunk = new ProtoChunk(chunkCoord, ChunkConverter.a, this.chunkSections, blockTickScheduler, fluidTickScheduler); } createHeightmaps(tempChunk); if (worldServer != null) runCustomWorldGenerator(tempChunk); } private ChunkData(ChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } public ChunkSection[] chunkSections() { return this.chunkSections; } public Map heightmaps() { return this.heightmaps; } public List lights() { return this.lights; } private void createChunkSections() { for (int i = 0; i < this.chunkSections.length; ++i) { int chunkSectionPos = i << 4; try { this.chunkSections[i] = new ChunkSection(chunkSectionPos, null, worldServer, true); } catch (Throwable error) { this.chunkSections[i] = new ChunkSection(chunkSectionPos); } } } private void runCustomWorldGenerator(ProtoChunk tempChunk) { ChunkGenerator bukkitGenerator = worldServer.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(worldServer, worldServer.getChunkProvider().getChunkGenerator(), bukkitGenerator); RegionLimitedWorldAccess region = new RegionLimitedWorldAccess(worldServer, Collections.singletonList(tempChunk)); chunkGenerator.buildBase(region, tempChunk); // We want to copy the level chunk sections back ChunkSection[] tempChunkSections = tempChunk.getSections(); for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { ChunkSection chunkSection = tempChunkSections[i]; if (chunkSection != null && chunkSection != Chunk.a) this.chunkSections[i] = chunkSection; } } private void createHeightmaps(ProtoChunk tempChunk) { for (HeightMap.Type heightmapType : HeightMap.Type.values()) { if (ChunkStatus.FULL.h().contains(heightmapType)) { this.heightmaps.put(heightmapType, new HeightMap(tempChunk, heightmapType)); } } } } } ================================================ FILE: NMS/v1_17/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } group 'NMS:v1_17' dependencies { paperweight.paperDevBundle("1.17.1-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_17') && !Boolean.valueOf(project.findProperty("nms.compile_v1_17").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_17/properties ================================================ NMS_VERSION=v1_17 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_17_R1 COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.Registry CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=java.util.Random STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17; import com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import java.lang.reflect.Field; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms { private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } @Override public String getMinecraftKey(ItemStack itemStack) { return Registry.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { try { return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException e) { return null; } } private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; try { glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); } catch (Throwable error) { glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); } try { Field field = Enchantment.class.getDeclaredField("acceptingNew"); field.setAccessible(true); field.set(null, true); field.setAccessible(false); } catch (Exception ignored) { } try { Enchantment.registerEnchantment(glowEnchant); } catch (Exception ignored) { } return glowEnchant; } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_17.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.chunk.ChunkBiomeContainer; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSChunks { private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( ChunkBiomeContainer.class, Biome[].class, "f"); private static final ReflectField CHUNK_BIOME_CONTAINER = new ReflectField<>( LevelChunk.class, ChunkBiomeContainer.class, Modifier.PRIVATE, 1); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Biome biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); Biome[] biomes = BIOME_BASE_ARRAY.get(levelChunk.getBiomes()); if (biomes == null) throw new RuntimeException("Error while receiving biome bases of chunk (" + chunkPos.x + "," + chunkPos.z + ")."); Arrays.fill(biomes, biome); levelChunk.setUnsaved(true); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z); //noinspection deprecation ClientboundLevelChunkPacket levelChunkPacket = new ClientboundLevelChunkPacket(levelChunk); ClientboundLightUpdatePacket lightUpdatePacket = new ClientboundLightUpdatePacket(chunkPos, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(lightUpdatePacket); serverPlayer.connection.send(levelChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); if (!chunkCompound.contains("Level", 10)) return; CompoundTag unloadedChunk = chunkCompound.getCompound("Level"); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Biome biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); int[] biomes = unloadedChunk.contains("Biomes", 11) ? unloadedChunk.getIntArray("Biomes") : new int[256]; Arrays.fill(biomes, biomesRegistry.getId(biome)); unloadedChunk.putIntArray("Biomes", biomes); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Arrays.fill(levelChunk.getSections(), LevelChunk.EMPTY_SECTION); removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); if (!chunkCompound.contains("Level", 10)) return; CompoundTag unloadedChunk = chunkCompound.getCompound("Level"); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ListTag sectionsList = new ListTag(); ListTag tileEntities = new ListTag(); unloadedChunk.put("Sections", sectionsList); unloadedChunk.put("TileEntities", tileEntities); unloadedChunk.put("Entities", new ListTag()); if (!(serverLevel.generator instanceof IslandsGenerator)) { ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); ProtoChunk protoChunk = NMSUtils.createProtoChunk(chunkPos, serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] levelChunkSections = protoChunk.getSections(); for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { for (LevelChunkSection levelChunkSection : levelChunkSections) { if (levelChunkSection != LevelChunk.EMPTY_SECTION && levelChunkSection.bottomBlockY() >> 4 == i) { CompoundTag sectionCompound = new CompoundTag(); sectionCompound.putByte("Y", (byte) (i & 255)); levelChunkSection.getStates().write(sectionCompound, "Palette", "BlockStates"); sectionsList.add(sectionCompound); } } } for (BlockPos blockEntityPos : protoChunk.getBlockEntitiesPos()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbt(blockEntityPos); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); if (!chunkCompound.contains("Level", 10)) return; ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag unloadedChunk = chunkCompound.getCompound("Level"); ListTag sectionsList = unloadedChunk.getList("Sections", 10); LevelChunkSection[] levelChunkSections = new LevelChunkSection[sectionsList.size()]; for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); if (sectionCompound.contains("Palette", 9) && sectionCompound.contains("BlockStates", 12)) { //noinspection deprecation LevelChunkSection levelChunkSection = levelChunkSections[i] = new LevelChunkSection(yPosition); levelChunkSection.getStates().read(sectionCompound.getList("Palette", 10), sectionCompound.getLongArray("BlockStates")); levelChunkSection.recalcBlockCounts(); } } ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, levelChunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); if (!chunkCompound.contains("Level", 10)) return; unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getCompound("Level") .getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getInt("DataVersion"); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel); } private static void removeBlocks(LevelChunk levelChunk) { ServerLevel serverLevel = levelChunk.level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(levelChunk), ChunkStatus.SURFACE, 0); try { chunkGenerator.buildSurface(region, levelChunk); } catch (ClassCastException error) { ProtoChunk protoChunk = NMSUtils.createProtoChunk(levelChunk.getPos(), serverLevel); chunkGenerator.buildSurface(region, protoChunk); // Load chunk sections from proto chunk to the actual chunk for (int i = 0; i < protoChunk.getSections().length && i < levelChunk.getSections().length; ++i) { levelChunk.getSections()[i] = protoChunk.getSections()[i]; } // Load biomes from proto chunk to the actual chunk if (protoChunk.getBiomes() != null) CHUNK_BIOME_CONTAINER.set(levelChunk, protoChunk.getBiomes()); // Load tile entities from proto chunk to the actual chunk protoChunk.getBlockEntities().forEach(((blockPosition, tileEntity) -> levelChunk.setBlockEntity(tileEntity))); } } } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; import java.lang.reflect.Modifier; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override protected int getPortalTicks(Entity entity) { return PORTAL_TICKS.get(entity); } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSTags { @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.of(compoundTag); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.setTag(compoundTag); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).getAsByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).getAsDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).getAsFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).getAsInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).getAsLong(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).getAsShort(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.nms.v1_17.vibration.IslandSculkSensorBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_17.world.BlockServerTickListTracker; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSWorld { private static boolean alreadyWarned = false; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.delegate; } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.get(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity) return; ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos()); serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); BlockServerTickListTracker.listenForTicks(serverLevel); if (!alreadyWarned) { Log.warn("This version is old and you may experience issues with block changes detection"); alreadyWarned = true; } } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; import com.bgsoftware.superiorskyblock.nms.v1_17.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_17.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_17.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17.utils; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_17.utils.TickingBlockList; import com.bgsoftware.superiorskyblock.nms.v1_17.world.WorldEditSessionImpl; import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoTickList; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); private static final ReflectMethod> WORKER_LOAD_ASYNC = new ReflectMethod<>( IOWorker.class, CompletableFuture.class, 1, ChunkPos.class); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) throws IOException { return chunkMap.read(chunkPos); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) throws IOException { return chunkMap.getChunkData(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { chunkMap.write(chunkPos, chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { try { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel); } catch (Throwable ex) { //noinspection deprecation return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { ProtoTickList blockTickScheduler = new ProtoTickList<>(block -> { return block == null || block.defaultBlockState().isAir(); }, chunkPos, levelHeightAccessor); ProtoTickList fluidTickScheduler = new ProtoTickList<>((fluid) -> { return fluid == null || fluid == Fluids.EMPTY; }, chunkPos, levelHeightAccessor); try { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor, serverLevel); } catch (Throwable error) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor); } } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.getMaterial().isLiquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.isEmpty(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.load(compoundTag); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.relight(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { if (compoundTag.getByte("SSB.HasSignLines") == 1) { // We want to convert the sign lines from raw string to json for (int i = 1; i <= 4; ++i) { String line = compoundTag.getString("SSB.Text" + i); if (!Text.isBlank(line)) { Component newLine = CraftChatMessage.fromString(line)[0]; compoundTag.putString("Text" + i, Component.Serializer.toJson(newLine)); } } } } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = DimensionType.NETHER_LOCATION; case THE_END -> resourceKey = DimensionType.END_LOCATION; default -> resourceKey = DimensionType.OVERWORLD_LOCATION; } Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); return registry.getOrThrow(resourceKey); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { for (int i = 0; i < chunkSections.length; ++i) { int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); try { chunkSections[i] = new LevelChunkSection(chunkSectionPos, null, serverLevel, true); } catch (Throwable error) { chunkSections[i] = new LevelChunkSection(chunkSectionPos); } } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ProtoChunk protoChunk) { CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(protoChunk), ChunkStatus.SURFACE, 0); chunkGenerator.buildSurface(region, protoChunk); } public static PalettedContainer createEmptyPlattedContainerStates() { return new LevelChunkSection(0).getStates(); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { CompoundTag data = new CompoundTag(); original.write(data, "Palette", "BlockStates"); PalettedContainer blockids = new PalettedContainer<>(LevelChunkSection.GLOBAL_BLOCKSTATE_PALETTE, Block.BLOCK_STATE_REGISTRY, NbtUtils::readBlockState, NbtUtils::writeBlockState, Blocks.AIR.defaultBlockState(), null, false); blockids.read(data.getList("Palette", CraftMagicNumbers.NBT.TAG_COMPOUND), data.getLongArray("BlockStates")); return blockids; } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.save(new CompoundTag()); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.tickingList.size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.tickingList.getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.getValue(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.dragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absMoveTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSection(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinBuildHeight(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxBuildHeight(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer)); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLong(key); } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/vibration/IslandSculkSensorBlockEntity.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.GameEventListener; import javax.annotation.Nullable; public class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState()); this.island = island; } @Override public boolean shouldListen(Level world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable Entity entity) { if (!super.shouldListen(world, listener, pos, event, entity)) return false; if (entity instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17.world; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ServerTickList; import net.minecraft.world.level.TickNextTickData; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockStates; import java.lang.reflect.Modifier; import java.util.List; import java.util.function.Consumer; public class BlockServerTickListTracker { private static final ReflectField>> TICK_FUNCTION_SPIGOT = new ReflectField>>(ServerTickList.class, Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField>> TICK_FUNCTION_PAPER = new ReflectField>>( new ClassInfo("com.destroystokyo.paper.server.ticklist.PaperTickList", ClassInfo.PackageType.UNKNOWN), Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private BlockServerTickListTracker() { } public static void listenForTicks(ServerLevel serverLevel) { ServerTickList blockTicks = serverLevel.getBlockTicks(); if (TICK_FUNCTION_PAPER.isValid()) { TICK_FUNCTION_PAPER.set(blockTicks, nextTickData -> tick(serverLevel, nextTickData)); } else { TICK_FUNCTION_SPIGOT.set(blockTicks, nextTickData -> tick(serverLevel, nextTickData)); } } private static void tick(ServerLevel serverLevel, TickNextTickData nextTickData) { BlockState blockState = serverLevel.getBlockState(nextTickData.pos); if (blockState.is(nextTickData.getType())) { BlockState oldState = serverLevel.getBlockState(nextTickData.pos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); blockState.tick(serverLevel, nextTickData.pos, serverLevel.random); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = serverLevel.getBlockState(nextTickData.pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(serverLevel, nextTickData.pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(nextTickData.pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } } ================================================ FILE: NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_17.world; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_18/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } group 'NMS:v1_18' dependencies { paperweight.paperDevBundle("1.18.2-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_18') && !Boolean.valueOf(project.findProperty("nms.compile_v1_18").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_18/properties ================================================ NMS_VERSION=v1_18 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_18_R2 COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.Registry CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=java.util.Random STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18; import com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import java.lang.reflect.Field; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms { private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } @Override public String getMinecraftKey(ItemStack itemStack) { return Registry.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { try { return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException e) { return null; } } private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; try { glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); } catch (Throwable error) { glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); } try { Field field = Enchantment.class.getDeclaredField("acceptingNew"); field.setAccessible(true); field.set(null, true); field.setAccessible(false); } catch (Exception ignored) { } try { Enchantment.registerEnchantment(glowEnchant); } catch (Exception ignored) { } return glowEnchant; } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_18.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.bottomBlockY() >> 4, currentSection.getStates(), biomesContainer); } } levelChunk.setUnsaved(true); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); Codec>> biomesCodec = PalettedContainer.codec( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(false, error -> { }); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(levelChunk.level.getSectionYFromSectionIndex(i), biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codec( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(false, error -> { }); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Codec>> biomesCodec = PalettedContainer.codec( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow(false, error -> { })); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow(false, error -> { })); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Codec> blocksCodec = PalettedContainer.codec( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codec( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(yPosition, blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getInt("DataVersion"); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel); } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; import java.lang.reflect.Modifier; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override protected int getPortalTicks(Entity entity) { return PORTAL_TICKS.get(entity); } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSTags { @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.of(compoundTag); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.setTag(compoundTag); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).getAsByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).getAsDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).getAsFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).getAsInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).getAsLong(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).getAsShort(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.nms.v1_18.vibration.IslandSculkSensorBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_18.world.BlockLevelTicksTracker; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSWorld { private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static boolean alreadyWarned = false; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.delegate; } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.structureSets, original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity) return; ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos()); serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); if (!alreadyWarned) { Log.warn("This version is old and you may experience issues with block changes detection"); alreadyWarned = true; } } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; import com.bgsoftware.superiorskyblock.nms.v1_18.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_18.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_18.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18.utils; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_18.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); private static final ReflectMethod> WORKER_LOAD_ASYNC = new ReflectMethod<>( IOWorker.class, CompletableFuture.class, 1, ChunkPos.class); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) throws IOException { return chunkMap.read(chunkPos); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) throws IOException { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { chunkMap.write(chunkPos, chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.getMaterial().isLiquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.load(compoundTag); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.relight(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { if (compoundTag.getByte("SSB.HasSignLines") == 1) { // We want to convert the sign lines from raw string to json for (int i = 1; i <= 4; ++i) { String line = compoundTag.getString("SSB.Text" + i); if (!Text.isBlank(line)) { Component newLine = CraftChatMessage.fromString(line)[0]; compoundTag.putString("Text" + i, Component.Serializer.toJson(newLine)); } } } } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = DimensionType.NETHER_LOCATION; case THE_END -> resourceKey = DimensionType.END_LOCATION; default -> resourceKey = DimensionType.OVERWORLD_LOCATION; } Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); return registry.getOrThrow(resourceKey); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(chunkSectionPos, statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess), ChunkStatus.SURFACE, 0); chunkGenerator.buildSurface(region, serverLevel.structureFeatureManager().forWorldGenRegion(region), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.tickingList.size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.tickingList.getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.getValue(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.dragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absMoveTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSection(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinBuildHeight(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxBuildHeight(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer)); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLong(key); } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/vibration/IslandSculkSensorBlockEntity.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.GameEventListener; import javax.annotation.Nullable; public class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState()); this.island = island; } @Override public boolean shouldListen(Level world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable Entity entity) { if (!super.shouldListen(world, listener, pos, event, entity)) return false; if (entity instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(chunkPos -> isPositionTickingWithEntitiesLoaded(serverLevel, chunkPos), serverLevel.getProfilerSupplier()); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } private static boolean isPositionTickingWithEntitiesLoaded(ServerLevel serverLevel, long chunkPos) { ChunkHolder chunkHolder = serverLevel.chunkSource.chunkMap.getVisibleChunkIfPresent(chunkPos); return chunkHolder != null && chunkHolder.isTickingReady() && serverLevel.areEntitiesLoaded(chunkPos); } } ================================================ FILE: NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_18.world; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_19/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } group 'NMS:v1_19' dependencies { paperweight.paperDevBundle("1.19.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_19') && !Boolean.valueOf(project.findProperty("nms.compile_v1_19").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_19/properties ================================================ NMS_VERSION=v1_19 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_19_R3 COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19; import com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import java.lang.reflect.Field; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms { private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; try { glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); } catch (Throwable error) { glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); } try { Field field = Enchantment.class.getDeclaredField("acceptingNew"); field.setAccessible(true); field.set(null, true); field.setAccessible(false); } catch (Exception ignored) { } try { Enchantment.registerEnchantment(glowEnchant); } catch (Exception ignored) { } return glowEnchant; } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_19.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.bottomBlockY() >> 4, currentSection.getStates(), biomesContainer); } } levelChunk.setUnsaved(true); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(false, error -> { }); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(levelChunk.level.getSectionYFromSectionIndex(i), biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(false, error -> { }); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow(false, error -> { })); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow(false, error -> { })); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(yPosition, blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getInt("DataVersion"); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel); } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; import java.lang.reflect.Modifier; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override protected int getPortalTicks(Entity entity) { return PORTAL_TICKS.get(entity); } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSTags { @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.of(compoundTag); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.setTag(compoundTag); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).getAsByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).getAsDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).getAsFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).getAsInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).getAsLong(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).getAsShort(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_19.vibration.IslandSculkSensorBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_19.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_19.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSWorld { private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity) return; ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos()); serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; import com.bgsoftware.superiorskyblock.nms.v1_19.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_19.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_19.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19.utils; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_19.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { chunkMap.write(chunkPos, chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { CompoundTag entityData = serverLevel.entityDataControllerNew.readData( chunkPosition.getX(), chunkPosition.getZ()); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); return; } NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().registryOrThrow(Registries.BIOME), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.getMaterial().isLiquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.load(compoundTag); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.relight(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { if (compoundTag.getByte("SSB.HasSignLines") == 1) { // We want to convert the sign lines from raw string to json for (int i = 1; i <= 4; ++i) { String line = compoundTag.getString("SSB.Text" + i); if (!Text.isBlank(line)) { Component newLine = CraftChatMessage.fromString(line)[0]; compoundTag.putString("Text" + i, Component.Serializer.toJson(newLine)); } } } } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(chunkSectionPos, statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess), ChunkStatus.SURFACE, 0); chunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.tickingList.size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.tickingList.getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.getValue(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.dragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absMoveTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSection(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinBuildHeight(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxBuildHeight(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer)); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLong(key); } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/vibration/IslandSculkSensorBlockEntity.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.GameEventListener; import javax.annotation.Nullable; public class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState()); this.island = island; } @Override public boolean shouldListen(ServerLevel world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable GameEvent.Context context) { if (!super.shouldListen(world, listener, pos, event, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; public class BlockLevelTicksTracker extends LevelTicks { private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = initializePositionTickingWithEntitiesLoaded(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos), serverLevel.getProfilerSupplier()); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.serverLevel, blockPos, oldState); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); } private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos); return chunkHolder != null && chunkHolder.isTickingReady(); } private static BiFunction initializePositionTickingWithEntitiesLoaded() { try { Class.forName("io.papermc.paper.chunk.system.scheduling.NewChunkHolder"); return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; } catch (Throwable error) { return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; } } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.level, pos, oldState); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_19.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_20_3/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(17)) } } group 'NMS:v1_20_3' dependencies { paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty("nms.compile_v1_20").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_20_3/properties ================================================ NMS_VERSION=v1_20_3 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_20_R3 COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.SpigotGlowEnchantment; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_20_R3.CraftRegistry; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; import java.util.Map; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms { private static final ReflectField> REGISTRY_CACHE = new ReflectField<>(CraftRegistry.class, Map.class, "cache"); private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; try { glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); } catch (Throwable error) { glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); } Map registryCache = REGISTRY_CACHE.get(Registry.ENCHANTMENT); registryCache.put(glowEnchant.getKey(), glowEnchant); return glowEnchant; } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_3.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.setUnsaved(true); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(false, error -> { }); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(false, error -> { }); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow(false, error -> { })); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow(false, error -> { })); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getInt("DataVersion"); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel); } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; import java.lang.reflect.Modifier; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override protected int getPortalTicks(Entity entity) { return PORTAL_TICKS.get(entity); } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSTags { @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.of(compoundTag); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.setTag(compoundTag); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).getAsByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).getAsDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).getAsFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).getAsInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).getAsLong(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).getAsShort(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_3.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; import com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData, @Nullable CompoundTag entityNbt) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_20_3.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.utils; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_3.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { chunkMap.write(chunkPos, chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { CompoundTag entityData = serverLevel.entityDataControllerNew.readData( chunkPosition.getX(), chunkPosition.getZ()); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); return; } NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().registryOrThrow(Registries.BIOME), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.load(compoundTag); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.relight(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess), ChunkStatus.SURFACE, 0); chunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.tickingList.size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.tickingList.getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absMoveTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSection(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinBuildHeight(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxBuildHeight(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer)); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLong(key); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } while (textLines.size() < 4) textLines.add(Component.empty()); Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, GameEvent gameEvent, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, gameEvent, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, GameEvent holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(GameEvent gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; public class BlockLevelTicksTracker extends LevelTicks { private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = initializePositionTickingWithEntitiesLoaded(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos), serverLevel.getProfilerSupplier()); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.serverLevel, blockPos, oldState); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); } private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos); return chunkHolder != null && chunkHolder.isTickingReady(); } private static BiFunction initializePositionTickingWithEntitiesLoaded() { try { Class.forName("io.papermc.paper.chunk.system.scheduling.NewChunkHolder"); return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; } catch (Throwable error) { return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; } } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.level, pos, oldState); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_20_4/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } group 'NMS:v1_20_4' dependencies { paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty("nms.compile_v1_20").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_20_4/properties ================================================ NMS_VERSION=v1_20_4 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_4.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.setUnsaved(true); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getInt("DataVersion"); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel); } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; import java.lang.reflect.Modifier; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override protected int getPortalTicks(Entity entity) { return PORTAL_TICKS.get(entity); } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); PropertyMap propertyMap = new PropertyMap(); propertyMap.put("textures", new Property("textures", texture)); ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).getAsByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).getAsDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).getAsFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).getAsInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).getAsLong(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).getAsShort(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_4.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; import com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @javax.annotation.Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_20_4.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4.utils; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_4.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { chunkMap.write(chunkPos, chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { CompoundTag entityData = serverLevel.entityDataControllerNew.readData( chunkPosition.getX(), chunkPosition.getZ()); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); return; } NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().registryOrThrow(Registries.BIOME), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.relight(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess), ChunkStatus.SURFACE, 0); chunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.tickingList.size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.tickingList.getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } while (textLines.size() < 4) textLines.add(Component.empty()); Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } } private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absMoveTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSection(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinBuildHeight(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxBuildHeight(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return MinecraftServer.getServer().getPlayerList().load(serverPlayer); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLong(key); } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; public class BlockLevelTicksTracker extends LevelTicks { private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = initializePositionTickingWithEntitiesLoaded(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos), serverLevel.getProfilerSupplier()); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); } private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos); return chunkHolder != null && chunkHolder.isTickingReady(); } private static BiFunction initializePositionTickingWithEntitiesLoaded() { try { Class.forName("io.papermc.paper.chunk.system.scheduling.NewChunkHolder"); return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; } catch (Throwable error) { return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; } } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_21/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } group 'NMS:v1_21' dependencies { paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_21/properties ================================================ NMS_VERSION=v1_21 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.setUnsaved(true); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getHolderOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getInt("DataVersion"); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel); } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSEntities { private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); PropertyMap propertyMap = new PropertyMap(); propertyMap.put("textures", new Property("textures", texture)); ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).getAsByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).getAsDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).getAsFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).getAsInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).getAsLong(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).getAsShort(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_21.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return; if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { VaultConfig vaultConfig = vaultBlockEntity.getConfig(); PlayerDetector playerDetector = vaultConfig.playerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; VaultConfig newConfig = new VaultConfig( vaultConfig.lootTable(), vaultConfig.activationRange(), vaultConfig.deactivationRange(), vaultConfig.keyItem(), vaultConfig.overrideLootTableToDisplay(), IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), vaultConfig.entitySelector() ); vaultBlockEntity.setConfig(newConfig); } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; trialSpawnerBlockEntity.trialSpawner = new TrialSpawner( trialSpawner.normalConfig, trialSpawner.ominousConfig, trialSpawner.getData(), trialSpawner.getTargetCooldownLength(), trialSpawner.getRequiredPlayerRange(), trialSpawner.stateAccessor, IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector), trialSpawner.getEntitySelector() ); } } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; import com.bgsoftware.superiorskyblock.nms.v1_21.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @javax.annotation.Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final PlayerDetector original; private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; } @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } return players; } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.utils; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkPyramid; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { chunkMap.write(chunkPos, chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { net.minecraft.nbt.CompoundTag entityData = serverLevel.moonrise$getEntityChunkDataController() .readData(chunkPosition.getX(), chunkPosition.getZ()); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); return; } NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().registryOrThrow(Registries.BIOME), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); // Unsafe: we do not provide chunks cache, even tho it is required. // Should be fine in normal flow, as the only method that access the chunks cache // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); customChunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.moonrise$getTickingBlockList().size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absMoveTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSection(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinBuildHeight(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxBuildHeight(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return MinecraftServer.getServer().getPlayerList().load(serverPlayer); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLong(key); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } while (textLines.size() < 4) textLines.add(Component.empty()); Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; public class BlockLevelTicksTracker extends LevelTicks { private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = initializePositionTickingWithEntitiesLoaded(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos), serverLevel.getProfilerSupplier()); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); } private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); return chunkHolder != null && chunkHolder.isTickingReady(); } private static BiFunction initializePositionTickingWithEntitiesLoaded() { try { Class.forName("ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder"); return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; } catch (Throwable error) { return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; } } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_21_10/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } group 'NMS:v1_21_10' dependencies { paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_21_10/properties ================================================ NMS_VERSION=v1_21_10 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10; import com.bgsoftware.common.reflection.ReflectField; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.lang.reflect.Modifier; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms { public static final ReflectField SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class, double[].class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); @Override public String parseSignLine(String original) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) .getOrThrow(JsonParseException::new); return COMPONENT_GSON.toJson(jsonElement); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); } @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_10.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.ProblemReporter; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import static com.bgsoftware.superiorskyblock.nms.v1_21_10.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSChunks { private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.markUnsaved(); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); DataResult dataResult = getBiomeContainerRWCodec() .encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() .encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec() .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; Optional blockStatesCompound = sectionCompound.getCompound("block_states"); if (blockStatesCompound.isPresent()) { DataResult> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get()) .promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); } PalettedContainer> biomesPalettedContainer; Optional biomesCompound = sectionCompound.getCompound("biomes"); if (biomesCompound.isPresent()) { DataResult>> dataResult = getBiomeContainerRWCodec() .parse(NbtOps.INSTANCE, biomesCompound.get()) .promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes(); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getIntOr("DataVersion", 0); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL); } } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } private static Codec>> getBiomeContainerRWCodec() { if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) { return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY); } else { return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec(); } } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSEntities { @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Util; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.slf4j.Logger; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSTags { private static final Logger LOGGER = LogUtils.getLogger(); @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); Multimap properties = HashMultimap.create(); properties.put("textures", new Property("textures", texture)); GameProfile gameProfile = new GameProfile(Util.NIL_UUID, "", new PropertyMap(properties)); ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.getIntOr(key, def); } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); return ItemStack.CODEC.parse(context, compoundTag) .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) .orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).byteValue(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).keySet(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).doubleValue(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).floatValue(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).intValue(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).longValue(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).shortValue(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).value(); } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_10.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_10.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_10.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_21_10.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE, worldBorder.world.getGameTime()); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return; if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { VaultConfig vaultConfig = vaultBlockEntity.getConfig(); PlayerDetector playerDetector = vaultConfig.playerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; VaultConfig newConfig = new VaultConfig( vaultConfig.lootTable(), vaultConfig.activationRange(), vaultConfig.deactivationRange(), vaultConfig.keyItem(), vaultConfig.overrideLootTableToDisplay(), IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), vaultConfig.entitySelector() ); vaultBlockEntity.setConfig(newConfig); } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); } } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon; import com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.storage.ValueInput; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override protected void readAdditionalSaveData(ValueInput input) { super.readAdditionalSaveData(input); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.hologram; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_10.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override protected void addAdditionalSaveData(ValueOutput output) { // Do not save NBT. } @Override protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { // Do not save NBT. } @Override protected void readAdditionalSaveData(ValueInput input) { // Do not load NBT. } @Override public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { // Do not save NBT. return false; } @Override public boolean saveAsPassenger(ValueOutput output) { // Do not save NBT. return false; } @Override public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { // Do not save NBT. } @Override public void saveWithoutId(ValueOutput output) { // Do not save NBT. } @Override public void load(ValueInput input) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final PlayerDetector original; private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; } @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } return players; } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.utils; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.util.ProblemReporter; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.Strategy; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkPyramid; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.TagValueOutput; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Logger LOGGER = LogUtils.getLogger(); private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create( MinecraftServer.getServer().registryAccess()); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(chunkCompoundTag); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { chunkMap.write(chunkPos, () -> chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { MoonriseRegionFileIO.RegionDataController regionDataController = serverLevel.moonrise$getEntityChunkDataController(); int chunkX = chunkPosition.getX(); int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); if (readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); default -> null; }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); return; } } chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, DEFAULT_PALETTED_CONTAINER_FACTORY, null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); blockEntity.loadWithComponents(valueInput); } } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = createBiomesContainer(biome); PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); // Unsafe: we do not provide chunks cache, even tho it is required. // Should be fine in normal flow, as the only method that access the chunks cache // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); customChunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); entity.save(valueOutput); return valueOutput.buildResult(); } } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.moonrise$getTickingBlockList().size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.properties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absSnapTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSectionY(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinY(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxY(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } public static PalettedContainer> createBiomesContainer(Holder biome) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); Strategy> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap()); return new PalettedContainerFactory( null, null, null, biomesStrategy, biome, null, null ).createForBiomes(); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()) .map(playerData -> { ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); serverPlayer.load(valueInput); return playerData; }); } } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLongOr(key, def); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); } } for (int i = 0; i < 4; i++) { if (textLines.get(i) == null) textLines.set(i, Component.empty()); } Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); }); } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static Identifier getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(serverLevel::isPositionTickingWithEntitiesLoaded); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, @Block.UpdateFlags int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_10.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_21_3/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } group 'NMS:v1_21_3' dependencies { paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_21_3/properties ================================================ NMS_VERSION=v1_21_3 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); } @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_3.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.markUnsaved(); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getInt("DataVersion"); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSEntities { @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); PropertyMap propertyMap = new PropertyMap(); propertyMap.put("textures", new Property("textures", texture)); ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).getAsByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).getAsDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).getAsFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).getAsInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).getAsLong(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).getAsShort(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_3.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_3.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return; if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { VaultConfig vaultConfig = vaultBlockEntity.getConfig(); PlayerDetector playerDetector = vaultConfig.playerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; VaultConfig newConfig = new VaultConfig( vaultConfig.lootTable(), vaultConfig.activationRange(), vaultConfig.deactivationRange(), vaultConfig.keyItem(), vaultConfig.overrideLootTableToDisplay(), IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), vaultConfig.entitySelector() ); vaultBlockEntity.setConfig(newConfig); } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; trialSpawnerBlockEntity.trialSpawner = new TrialSpawner( trialSpawner.normalConfig, trialSpawner.ominousConfig, trialSpawner.getData(), trialSpawner.getTargetCooldownLength(), trialSpawner.getRequiredPlayerRange(), trialSpawner.stateAccessor, IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector), trialSpawner.getEntitySelector() ); } } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; import com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_3.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final PlayerDetector original; private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; } @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } return players; } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.utils; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_3.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkPyramid; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { chunkMap.write(chunkPos, () -> chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { MoonriseRegionFileIO.RegionDataController regionDataController = serverLevel.moonrise$getEntityChunkDataController(); int chunkX = chunkPosition.getX(); int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); if(readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); default -> null; }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); return; } } chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); // Unsafe: we do not provide chunks cache, even tho it is required. // Should be fine in normal flow, as the only method that access the chunks cache // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); customChunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.moonrise$getTickingBlockList().size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absMoveTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSectionY(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinY(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxY(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return MinecraftServer.getServer().getPlayerList().load(serverPlayer); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLong(key); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } while (textLines.size() < 4) textLines.add(Component.empty()); Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; public class BlockLevelTicksTracker extends LevelTicks { private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = initializePositionTickingWithEntitiesLoaded(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos)); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); } private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); return chunkHolder != null && chunkHolder.isTickingReady(); } private static BiFunction initializePositionTickingWithEntitiesLoaded() { try { Class.forName("ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder"); return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; } catch (Throwable error) { return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; } } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_21_4/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } group 'NMS:v1_21_4' dependencies { paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_21_4/properties ================================================ NMS_VERSION=v1_21_4 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); } @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_4.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.markUnsaved(); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getInt("DataVersion"); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSEntities { @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); PropertyMap propertyMap = new PropertyMap(); propertyMap.put("textures", new Property("textures", texture)); ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).getAsByte(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).getAsDouble(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).getAsFloat(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).getAsInt(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).getAsLong(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).getAsShort(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_4.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_4.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return; if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { VaultConfig vaultConfig = vaultBlockEntity.getConfig(); PlayerDetector playerDetector = vaultConfig.playerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; VaultConfig newConfig = new VaultConfig( vaultConfig.lootTable(), vaultConfig.activationRange(), vaultConfig.deactivationRange(), vaultConfig.keyItem(), vaultConfig.overrideLootTableToDisplay(), IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), vaultConfig.entitySelector() ); vaultBlockEntity.setConfig(newConfig); } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; trialSpawnerBlockEntity.trialSpawner = new TrialSpawner( trialSpawner.normalConfig, trialSpawner.ominousConfig, trialSpawner.getData(), trialSpawner.getTargetCooldownLength(), trialSpawner.getRequiredPlayerRange(), trialSpawner.stateAccessor, IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector), trialSpawner.getEntitySelector() ); } } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_4.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final PlayerDetector original; private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; } @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } return players; } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.utils; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_4.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkPyramid; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { chunkMap.write(chunkPos, () -> chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { MoonriseRegionFileIO.RegionDataController regionDataController = serverLevel.moonrise$getEntityChunkDataController(); int chunkX = chunkPosition.getX(); int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); if(readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); default -> null; }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); return; } } chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); // Unsafe: we do not provide chunks cache, even tho it is required. // Should be fine in normal flow, as the only method that access the chunks cache // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); customChunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.moonrise$getTickingBlockList().size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absMoveTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSectionY(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinY(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxY(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return MinecraftServer.getServer().getPlayerList().load(serverPlayer); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLong(key); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } while (textLines.size() < 4) textLines.add(Component.empty()); Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; public class BlockLevelTicksTracker extends LevelTicks { private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = initializePositionTickingWithEntitiesLoaded(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos)); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); } private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); return chunkHolder != null && chunkHolder.isTickingReady(); } private static BiFunction initializePositionTickingWithEntitiesLoaded() { try { Class.forName("ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder"); return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; } catch (Throwable error) { return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; } } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_21_5/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } group 'NMS:v1_21_5' dependencies { paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_21_5/properties ================================================ NMS_VERSION=v1_21_5 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); } @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_5.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.markUnsaved(); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; Optional blockStatesCompound = sectionCompound.getCompound("block_states"); if (blockStatesCompound.isPresent()) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, blockStatesCompound.get()).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; Optional biomesCompound = sectionCompound.getCompound("biomes"); if (biomesCompound.isPresent()) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, biomesCompound.get()).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getIntOr("DataVersion", 0); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSEntities { @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); PropertyMap propertyMap = new PropertyMap(); propertyMap.put("textures", new Property("textures", texture)); ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.getIntOr(key, def); } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).byteValue(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).keySet(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).doubleValue(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).floatValue(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).intValue(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).longValue(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).shortValue(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).value(); } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_5.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_5.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return; if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { VaultConfig vaultConfig = vaultBlockEntity.getConfig(); PlayerDetector playerDetector = vaultConfig.playerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; VaultConfig newConfig = new VaultConfig( vaultConfig.lootTable(), vaultConfig.activationRange(), vaultConfig.deactivationRange(), vaultConfig.keyItem(), vaultConfig.overrideLootTableToDisplay(), IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), vaultConfig.entitySelector() ); vaultBlockEntity.setConfig(newConfig); } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; trialSpawnerBlockEntity.trialSpawner = new TrialSpawner( trialSpawner.normalConfig, trialSpawner.ominousConfig, trialSpawner.getData(), trialSpawner.getTargetCooldownLength(), trialSpawner.getRequiredPlayerRange(), trialSpawner.stateAccessor, IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector), trialSpawner.getEntitySelector() ); } } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData super.readAdditionalSaveData(compoundTag); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_5.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override public void addAdditionalSaveData(CompoundTag compoundTag) { // Do not save NBT. } @Override public void readAdditionalSaveData(CompoundTag compoundTag) { // Do not load NBT. } @Override public boolean saveAsPassenger(CompoundTag compoundTag) { // Do not save NBT. return false; } @Override public CompoundTag saveWithoutId(CompoundTag compoundTag) { // Do not save NBT. return compoundTag; } @Override public void load(CompoundTag compoundTag) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final PlayerDetector original; private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; } @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } return players; } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.utils; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkPyramid; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { chunkMap.write(chunkPos, () -> chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { MoonriseRegionFileIO.RegionDataController regionDataController = serverLevel.moonrise$getEntityChunkDataController(); int chunkX = chunkPosition.getX(); int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); if (readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); default -> null; }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); return; } } chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); // Unsafe: we do not provide chunks cache, even tho it is required. // Should be fine in normal flow, as the only method that access the chunks cache // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); customChunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { CompoundTag compoundTag = new CompoundTag(); entity.save(compoundTag); return compoundTag; } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.moonrise$getTickingBlockList().size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absSnapTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSectionY(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinY(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxY(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { return MinecraftServer.getServer().getPlayerList().load(serverPlayer); } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLongOr(key, def); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); } } while (textLines.size() < 4) textLines.add(Component.empty()); Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); }); } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(serverLevel::isPositionTickingWithEntitiesLoaded); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_21_7/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } group 'NMS:v1_21_7' dependencies { paperweight.paperDevBundle("1.21.7-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_21_7/properties ================================================ NMS_VERSION=v1_21_7 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms { private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); @Override public String parseSignLine(String original) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) .getOrThrow(JsonParseException::new); return COMPONENT_GSON.toJson(jsonElement); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); } @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { try { return MinecraftServer.getServer().tps1.getAverage(); } catch (Throwable error) { //noinspection removal return MinecraftServer.getServer().recentTps[0]; } } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_7.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.ProblemReporter; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSChunks { private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.markUnsaved(); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(biomesRegistry); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState()); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState() ); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomesRegistry.getOrThrow(Biomes.PLAINS) ); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; Optional blockStatesCompound = sectionCompound.getCompound("block_states"); if (blockStatesCompound.isPresent()) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, blockStatesCompound.get()).promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } PalettedContainer> biomesPalettedContainer; Optional biomesCompound = sectionCompound.getCompound("biomes"); if (biomesCompound.isPresent()) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, biomesCompound.get()).promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getIntOr("DataVersion", 0); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL); } } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSEntities { @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.slf4j.Logger; import java.util.Optional; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSTags { private static final Logger LOGGER = LogUtils.getLogger(); @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); PropertyMap propertyMap = new PropertyMap(); propertyMap.put("textures", new Property("textures", texture)); ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.getIntOr(key, def); } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); return ItemStack.CODEC.parse(context, compoundTag) .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) .orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).byteValue(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).keySet(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).doubleValue(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).floatValue(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).intValue(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).longValue(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).shortValue(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).value(); } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_7.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_7.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return; if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { VaultConfig vaultConfig = vaultBlockEntity.getConfig(); PlayerDetector playerDetector = vaultConfig.playerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; VaultConfig newConfig = new VaultConfig( vaultConfig.lootTable(), vaultConfig.activationRange(), vaultConfig.deactivationRange(), vaultConfig.keyItem(), vaultConfig.overrideLootTableToDisplay(), IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), vaultConfig.entitySelector() ); vaultBlockEntity.setConfig(newConfig); } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); } } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.storage.ValueInput; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override protected void readAdditionalSaveData(ValueInput input) { super.readAdditionalSaveData(input); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.hologram; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_7.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override protected void addAdditionalSaveData(ValueOutput output) { // Do not save NBT. } @Override protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { // Do not save NBT. } @Override protected void readAdditionalSaveData(ValueInput input) { // Do not load NBT. } @Override public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { // Do not save NBT. return false; } @Override public boolean saveAsPassenger(ValueOutput output) { // Do not save NBT. return false; } @Override public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { // Do not save NBT. } @Override public void saveWithoutId(ValueOutput output) { // Do not save NBT. } @Override public void load(ValueInput input) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final PlayerDetector original; private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; } @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } return players; } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.utils; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_7.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.util.ProblemReporter; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkPyramid; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.TagValueOutput; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Logger LOGGER = LogUtils.getLogger(); private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { chunkMap.write(chunkPos, () -> chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { MoonriseRegionFileIO.RegionDataController regionDataController = serverLevel.moonrise$getEntityChunkDataController(); int chunkX = chunkPosition.getX(); int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); if (readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); default -> null; }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); return; } } chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); blockEntity.loadWithComponents(valueInput); } } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); // Unsafe: we do not provide chunks cache, even tho it is required. // Should be fine in normal flow, as the only method that access the chunks cache // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); customChunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); entity.save(valueOutput); return valueOutput.buildResult(); } } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.moonrise$getTickingBlockList().size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absSnapTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSectionY(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinY(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxY(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { return MinecraftServer.getServer().getPlayerList().playerIo.load( serverPlayer.getName().getString(), serverPlayer.getStringUUID(), scopedCollector) .map(playerData -> { ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); serverPlayer.load(valueInput); return playerData; }); } } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLongOr(key, def); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); } } for (int i = 0; i < 4; i++) { if (textLines.get(i) == null) textLines.set(i, Component.empty()); } Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); }); } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(serverLevel::isPositionTickingWithEntitiesLoaded); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_21_9/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) } } group 'NMS:v1_21_9' dependencies { paperweight.paperDevBundle("1.21.10-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } assemble { dependsOn(reobfJar) } if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_21_9/properties ================================================ NMS_VERSION=v1_21_9 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight SPIKE_FEATURE_CLASS=SpikeFeature ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9; import com.bgsoftware.common.reflection.ReflectField; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.lang.reflect.Modifier; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms { public static final ReflectField SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class, double[].class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); @Override public String parseSignLine(String original) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) .getOrThrow(JsonParseException::new); return COMPONENT_GSON.toJson(jsonElement); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); } @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.ProblemReporter; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import static com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSChunks { private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.markUnsaved(); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); DataResult dataResult = getBiomeContainerRWCodec() .encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() .encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec() .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; Optional blockStatesCompound = sectionCompound.getCompound("block_states"); if (blockStatesCompound.isPresent()) { DataResult> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get()) .promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); } PalettedContainer> biomesPalettedContainer; Optional biomesCompound = sectionCompound.getCompound("biomes"); if (biomesCompound.isPresent()) { DataResult>> dataResult = getBiomeContainerRWCodec() .parse(NbtOps.INSTANCE, biomesCompound.get()) .promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes(); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getIntOr("DataVersion", 0); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL); } } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } private static Codec>> getBiomeContainerRWCodec() { if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) { return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY); } else { return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec(); } } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSEntities { @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.Util; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.slf4j.Logger; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSTags { private static final Logger LOGGER = LogUtils.getLogger(); @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); Multimap properties = HashMultimap.create(); properties.put("textures", new Property("textures", texture)); GameProfile gameProfile = new GameProfile(Util.NIL_UUID, "", new PropertyMap(properties)); ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.getIntOr(key, def); } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); return ItemStack.CODEC.parse(context, compoundTag) .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) .orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).byteValue(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).keySet(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).doubleValue(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).floatValue(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).intValue(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).longValue(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).shortValue(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).value(); } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_9.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_9.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_9.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v1_21_9.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return; if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { VaultConfig vaultConfig = vaultBlockEntity.getConfig(); PlayerDetector playerDetector = vaultConfig.playerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; VaultConfig newConfig = new VaultConfig( vaultConfig.lootTable(), vaultConfig.activationRange(), vaultConfig.deactivationRange(), vaultConfig.keyItem(), vaultConfig.overrideLootTableToDisplay(), IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), vaultConfig.entitySelector() ); vaultBlockEntity.setConfig(newConfig); } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); } } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon; import com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon.EndWorldEndDragonFightHandler; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.portalLocation; } protected void setPortalPos(BlockPos blockPos) { this.portalLocation = blockPos; } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.storage.ValueInput; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override protected void readAdditionalSaveData(ValueInput input) { super.readAdditionalSaveData(input); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.hologram; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_9.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override protected void addAdditionalSaveData(ValueOutput output) { // Do not save NBT. } @Override protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { // Do not save NBT. } @Override protected void readAdditionalSaveData(ValueInput input) { // Do not load NBT. } @Override public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { // Do not save NBT. return false; } @Override public boolean saveAsPassenger(ValueOutput output) { // Do not save NBT. return false; } @Override public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { // Do not save NBT. } @Override public void saveWithoutId(ValueOutput output) { // Do not save NBT. } @Override public void load(ValueInput input) { // Do not load NBT. } @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final PlayerDetector original; private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; } @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } return players; } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.utils; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.util.ProblemReporter; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.Strategy; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkPyramid; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EndDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.TagValueOutput; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.function.BiConsumer; public class NMSUtilsVersioned { private static final Logger LOGGER = LogUtils.getLogger(); private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create( MinecraftServer.getServer().registryAccess()); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { chunkMap.write(chunkPos, () -> chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { MoonriseRegionFileIO.RegionDataController regionDataController = serverLevel.moonrise$getEntityChunkDataController(); int chunkX = chunkPosition.getX(); int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); if (readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); default -> null; }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); return; } } chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, DEFAULT_PALETTED_CONTAINER_FACTORY, null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); blockEntity.loadWithComponents(valueInput); } } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = createBiomesContainer(biome); PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); // Unsafe: we do not provide chunks cache, even tho it is required. // Should be fine in normal flow, as the only method that access the chunks cache // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); customChunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); entity.save(valueOutput); return valueOutput.buildResult(); } } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.moonrise$getTickingBlockList().size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.properties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absSnapTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSectionY(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinY(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxY(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } public static PalettedContainer> createBiomesContainer(Holder biome) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); Strategy> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap()); return new PalettedContainerFactory( null, null, null, biomesStrategy, biome, null, null ).createForBiomes(); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()) .map(playerData -> { ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); serverPlayer.load(valueInput); return playerData; }); } } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLongOr(key, def); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); } } for (int i = 0; i < 4; i++) { if (textLines.get(i) == null) textLines.set(i, Component.empty()); } Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); }); } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getNMS(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { if (blockState.getValues().isEmpty()) return false; blockState.getValues().forEach(consumer); return true; } public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { return BlockEntityType.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(serverLevel::isPositionTickingWithEntitiesLoaded); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_21_9.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); } private PropertiesMapperVersioned() { } } ================================================ FILE: NMS/v1_8_R3/build.gradle ================================================ group 'NMS:v1_8_R3' dependencies { compileOnly "org.spigotmc:v1_8_R3:latest" compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('nms.compile_v1_8') && !Boolean.valueOf(project.findProperty("nms.compile_v1_8").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.EntityFallingBlock; import net.minecraft.server.v1_8_R3.EntityMinecartAbstract; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.IChatBaseComponent; import net.minecraft.server.v1_8_R3.Item; import net.minecraft.server.v1_8_R3.MinecraftKey; import net.minecraft.server.v1_8_R3.MinecraftServer; import net.minecraft.server.v1_8_R3.World; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_8_R3.CraftServer; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftFallingSand; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftMinecart; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.entity.FallingBlock; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; import java.lang.reflect.Field; import java.util.Locale; import java.util.Optional; public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); private final SuperiorSkyblockPlugin plugin; public NMSAlgorithmsImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public void registerCommand(BukkitCommand command) { ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); } @Override public String parseSignLine(String original) { return IChatBaseComponent.ChatSerializer.a(CraftChatMessage.fromString(original)[0]); } @Override public int getCombinedId(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); IBlockData blockData; try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { wrapper.getHandle().c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); blockData = world.getType(wrapper.getHandle()); } return Block.getCombinedId(blockData); } @Override public int getCombinedId(Material material, byte data) { //noinspection deprecation return material.getId() + (data << 12); } @Override public Optional getTileEntityIdFromCombinedId(int combinedId) { IBlockData blockData = Block.getByCombinedId(combinedId); if (!blockData.getBlock().isTileEntity()) return Optional.empty(); String id = BlockEntityCache.getTileEntityId(blockData); return Text.isBlank(id) ? Optional.empty() : Optional.of(id); } @Override public int compareMaterials(Material o1, Material o2) { return Integer.compare(o1.ordinal(), o2.ordinal()); } @Override public short getBlockDataValue(BlockState blockState) { return blockState.getRawData(); } @Override public short getBlockDataValue(org.bukkit.block.Block block) { return block.getData(); } @Override public short getMaxBlockDataValue(Material material) { return 0; } @Override public Key getBlockKey(int combinedId) { IBlockData blockData = Block.getByCombinedId(combinedId); return KeyBlocksCache.getBlockKey(blockData); } @Override public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { EntityMinecartAbstract minecart = ((CraftMinecart) bukkitMinecart).getHandle(); return KeyBlocksCache.getBlockKey(minecart.getDisplayBlock()); } @Override public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { EntityFallingBlock fallingBlock = ((CraftFallingSand) bukkitFallingBlock).getHandle(); return Optional.ofNullable(fallingBlock.getBlock()).map(KeyBlocksCache::getBlockKey).orElse(ConstantKeys.AIR); } @Override public void setCustomModel(ItemMeta itemMeta, int customModel) { // Doesn't exist } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { // Doesn't exist } @Override public void setRarity(ItemMeta itemMeta, String rarity) { // Doesn't exist } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { // Doesn't exist } @Override public void setHideTooltip(ItemMeta itemMeta) { // Doesn't exist } @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { potionMeta.addCustomEffect(potionEffect, true); } @Override public String getMinecraftKey(org.bukkit.inventory.ItemStack itemStack) { MinecraftKey minecraftKey = Item.REGISTRY.c(CraftItemStack.asNMSCopy(itemStack).getItem()); return minecraftKey == null ? "minecraft:air" : minecraftKey.toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { return defaultHolder; } @Override public int getMaxWorldSize() { MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); return server.getPropertyManager().getInt("max-world-size", 29999984); } @Override public double getCurrentTps() { return MinecraftServer.getServer().recentTps[0]; } @Override public int getDataVersion() { return -1; } @Override public Biome getBiome(String biomeName) { try { return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException e) { return null; } } private static Enchantment initializeGlowEnchantment() { int enchantId = 100; while (Enchantment.getById(enchantId) != null) ++enchantId; Enchantment glowEnchant = new Enchantment(enchantId) { @Override public String getName() { return "SuperiorSkyblockGlow"; } @Override public int getMaxLevel() { return 1; } @Override public int getStartLevel() { return 0; } @Override public EnchantmentTarget getItemTarget() { return null; } @Override public boolean conflictsWith(Enchantment enchantment) { return false; } @Override public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) { return true; } }; try { Field field = Enchantment.class.getDeclaredField("acceptingNew"); field.setAccessible(true); field.set(null, true); field.setAccessible(false); } catch (Exception ignored) { } try { Enchantment.registerEnchantment(glowEnchant); } catch (Exception ignored) { } return glowEnchant; } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSCachedBlock.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @SuppressWarnings("deprecation") public class NMSCachedBlock implements ICachedBlock { private static final ObjectsPool POOL = new ObjectsPool<>(NMSCachedBlock::new); private Material blockType; private byte blockData; public static NMSCachedBlock obtain(Block block) { return POOL.obtain().initialize(block); } private NMSCachedBlock() { } private NMSCachedBlock initialize(Block block) { this.blockType = block.getType(); this.blockData = block.getData(); return this; } @Override public void setBlock(Location location) { Block block = location.getWorld().getBlockAt(location); block.setType(blockType); block.setData(blockData); } @Override public void release() { this.blockType = null; POOL.release(this); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.chunks.CropsTickingTileEntity; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockDoubleStep; import net.minecraft.server.v1_8_R3.BlockDoubleStepAbstract; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.Blocks; import net.minecraft.server.v1_8_R3.Chunk; import net.minecraft.server.v1_8_R3.ChunkCoordIntPair; import net.minecraft.server.v1_8_R3.ChunkSection; import net.minecraft.server.v1_8_R3.EntityHuman; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.MinecraftKey; import net.minecraft.server.v1_8_R3.TileEntity; import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_8_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_8_R3.util.UnsafeList; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl implements NMSChunks { private final SuperiorSkyblockPlugin plugin; public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); CropsTickingTileEntity.register(); } @Override public void setBiome(List chunkPositions, Biome biome, Collection playersToUpdate) { if (chunkPositions.isEmpty()) return; byte biomeBase = (byte) CraftBlock.biomeToBiomeBase(biome).id; NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { Arrays.fill(chunk.getBiomeIndex(), biomeBase); chunk.e(); } @Override public void onFinish() { // Do nothing. } }); } @Override public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { if (chunkPositions.isEmpty()) return; chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { Arrays.fill(chunk.getSections(), null); removeEntities(chunk); removeTileEntities(chunk); removeBlocks(chunk); } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }); } @Override public CompletableFuture> calculateChunks(List chunkPositions, Synchronized> unloadedChunksCache) { List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); Iterator chunkPositionsIterator = chunkPositions.iterator(); while (chunkPositionsIterator.hasNext()) { ChunkPosition chunkPosition = chunkPositionsIterator.next(); CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); if (cachedCalculatedChunk != null) { allCalculatedChunks.add(cachedCalculatedChunk); chunkPositionsIterator.remove(); } else { chunkPositionsToCalculate.add(chunkPosition); } } if (chunkPositions.isEmpty()) return CompletableFuture.completedFuture(allCalculatedChunks); CompletableFuture> completableFuture = new CompletableFuture<>(); NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { World bukkitWorld = chunk.world.getWorld(); ChunkPosition chunkPosition = ChunkPosition.of(bukkitWorld, chunk.locX, chunk.locZ, false); KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); List spawnersLocations = new LinkedList<>(); for (ChunkSection chunkSection : chunk.getSections()) { if (chunkSection != null && !chunkSection.a()) { for (BlockPosition bp : BlockPosition.b(new BlockPosition(0, 0, 0), new BlockPosition(15, 15, 15))) { IBlockData blockData = chunkSection.getType(bp.getX(), bp.getY(), bp.getZ()); Block block = blockData.getBlock(); if (block != Blocks.AIR) { Location location = new Location(bukkitWorld, (chunkPosition.getX() << 4) + bp.getX(), chunkSection.getYPosition() + bp.getY(), (chunkPosition.getZ() << 4) + bp.getZ()); int blockAmount = 1; if (block instanceof BlockDoubleStep) { blockAmount = 2; // Converts the block data to a regular slab MinecraftKey blockKey = Block.REGISTRY.c(block); blockData = Block.REGISTRY.get(new MinecraftKey(blockKey.a() .replace("double_", ""))).getBlockData() .set(BlockDoubleStepAbstract.VARIANT, blockData.get(BlockDoubleStepAbstract.VARIANT)); } Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockData), location); blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); if (block == Blocks.MOB_SPAWNER) { spawnersLocations.add(location); } } } } } CalculatedChunk.Blocks calculatedChunk = new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations); allCalculatedChunks.add(calculatedChunk); if (!isLoaded) unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }); return completableFuture; } @Override public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { if (chunkPositions.isEmpty()) return CompletableFuture.completedFuture(Collections.emptyList()); CompletableFuture> completableFuture = new CompletableFuture<>(); List allCalculatedChunks = new LinkedList<>(); NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); for (org.bukkit.entity.Entity bukkitEntity : chunk.bukkitChunk.getEntities()) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false); CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities); allCalculatedChunks.add(calculatedChunk); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }); return completableFuture; } @Override public void injectChunkSections(org.bukkit.Chunk chunk) { // No implementation } @Override public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); return Arrays.stream(chunk.getSections()).allMatch(chunkSection -> chunkSection == null || chunkSection.a()); } @Override public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { Chunk chunk = ((CraftWorld) chunkPosition.getWorld()).getHandle().chunkProviderServer .getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); return chunk == null ? null : chunk.bukkitChunk; } @Override public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) { if (plugin.getSettings().getCropsInterval() <= 0) return; if (stop) { CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove( chunk.getWorld().getName(), ChunkCoordIntPair.a(chunk.getX(), chunk.getZ())); if (cropsTickingTileEntity != null) { try { cropsTickingTileEntity.getWorld().tileEntityList.remove(cropsTickingTileEntity); } catch (Throwable error) { cropsTickingTileEntity.getWorld().t(cropsTickingTileEntity.getPosition()); } } } else { CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle()); } } @Override public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { if (chunkPositions.isEmpty()) return; CropsTickingTileEntity.forEachChunk(chunkPositions, cropsTickingTileEntity -> cropsTickingTileEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); } @Override public void shutdown() { // Do nothing. There are no tasks to wait for. } @Override public List getBlockEntities(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); List blockEntities = new LinkedList<>(); World bukkitWorld = bukkitChunk.getWorld(); chunk.getTileEntities().keySet().forEach(blockPosition -> blockEntities.add(new Location(bukkitWorld, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()))); return blockEntities; } private static void removeEntities(Chunk chunk) { for (int i = 0; i < chunk.entitySlices.length; i++) { chunk.entitySlices[i].forEach(entity -> { if (!(entity instanceof EntityHuman)) entity.dead = true; }); chunk.entitySlices[i] = new UnsafeList<>(); } } private static void removeTileEntities(Chunk chunk) { boolean hasWorldHField = false; try { // This field doesn't exist in Taco 1.8 List tileEntities = chunk.world.h; hasWorldHField = true; } catch (Throwable ignored) { } if (hasWorldHField) { chunk.tileEntities.forEach(((blockPosition, tileEntity) -> { chunk.world.tileEntityList.remove(tileEntity); chunk.world.h.remove(tileEntity); chunk.world.capturedTileEntities.remove(blockPosition); })); } else { chunk.tileEntities.forEach(((blockPosition, tileEntity) -> { chunk.world.tileEntityList.remove(tileEntity); chunk.world.capturedTileEntities.remove(blockPosition); })); } chunk.tileEntities.clear(); } private static void removeBlocks(Chunk chunk) { WorldServer worldServer = (WorldServer) chunk.world; if (worldServer.generator != null && !(worldServer.generator instanceof IslandsGenerator)) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(worldServer, 0L, worldServer.generator); Chunk generatedChunk = customChunkGenerator.getOrCreateChunk(chunk.locX, chunk.locZ); for (int i = 0; i < 16; i++) chunk.getSections()[i] = generatedChunk.getSections()[i]; for (Map.Entry entry : generatedChunk.getTileEntities().entrySet()) worldServer.setTileEntity(entry.getKey(), entry.getValue()); } } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.Items; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>(Entity.class, int.class, "al"); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { ItemStack[] itemStacks = new ItemStack[6]; itemStacks[0] = new ItemStack(Material.ARMOR_STAND); itemStacks[1] = entityEquipment.getItemInHand(); itemStacks[2] = entityEquipment.getHelmet(); itemStacks[3] = entityEquipment.getChestplate(); itemStacks[4] = entityEquipment.getLeggings(); itemStacks[5] = entityEquipment.getBoots(); return itemStacks; } @Override public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().d(CraftItemStack.asNMSCopy(itemStack)); } @Override public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { return CraftItemStack.asNMSCopy(bukkitItem).getItem() == Items.COAL; } @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSHologramsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import com.bgsoftware.superiorskyblock.nms.NMSHolograms; import net.minecraft.server.v1_8_R3.AxisAlignedBB; import net.minecraft.server.v1_8_R3.DamageSource; import net.minecraft.server.v1_8_R3.EntityArmorStand; import net.minecraft.server.v1_8_R3.EntityHuman; import net.minecraft.server.v1_8_R3.ItemStack; import net.minecraft.server.v1_8_R3.NBTTagCompound; import net.minecraft.server.v1_8_R3.Vec3D; import net.minecraft.server.v1_8_R3.World; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftArmorStand; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; @SuppressWarnings("unused") public class NMSHologramsImpl implements NMSHolograms { @Override public Hologram createHologram(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); EntityHologram entityHologram = new EntityHologram(world, location.getX(), location.getY(), location.getZ()); world.addEntity(entityHologram); return entityHologram; } @Override public boolean isHologram(Entity entity) { return ((CraftEntity) entity).getHandle() instanceof Hologram; } public static class EntityHologram extends EntityArmorStand implements Hologram { EntityHologram(World world, double x, double y, double z) { super(world, x, y, z); setInvisible(true); setSmall(true); setArms(false); setGravity(false); setBasePlate(true); n(true); super.setCustomNameVisible(true); super.a(new AxisAlignedBB(0D, 0D, 0D, 0D, 0D, 0D)); this.onGround = true; // Workaround to force EntityTrackerEntry to send a teleport packet. } @Override public void setHologramName(String name) { super.setCustomName(name); } @Override public void removeHologram() { super.die(); } @Override public ArmorStand getHandle() { return this.getBukkitEntity(); } @Override public void inactiveTick() { // Disable normal ticking for this entity. // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. if (this.onGround) { this.onGround = false; } } @Override public void setEquipment(int i, ItemStack item) { // Prevent stand being equipped } @Override public boolean d(int i, ItemStack item) { // Prevent stand being equipped return false; } @Override public void b(NBTTagCompound nbttagcompound) { // Do not save NBT. } @Override public boolean a(EntityHuman human, Vec3D vec3d) { // Prevent stand being equipped return true; } @Override public void t_() { // Disable normal ticking for this entity. // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. if (this.onGround) { this.onGround = false; } } @Override public void die() { // Prevent being killed. } @Override public void makeSound(String sound, float f1, float f2) { // Remove sounds. } @Override public boolean c(NBTTagCompound nbttagcompound) { // Do not save NBT. return false; } @Override public boolean d(NBTTagCompound nbttagcompound) { // Do not save NBT. return false; } @Override public void e(NBTTagCompound nbttagcompound) { // Do not save NBT. } @Override public CraftArmorStand getBukkitEntity() { if (super.bukkitEntity == null) { this.bukkitEntity = new CraftArmorStand(this.world.getServer(), this); } return (CraftArmorStand) this.bukkitEntity; } @Override public boolean isInvulnerable(DamageSource source) { /* * The field Entity.invulnerable is private. * It's only used while saving NBTTags, but since the entity would be killed * on chunk unload, we prefer to override isInvulnerable(). */ return true; } @Override public void setCustomName(String customName) { // Locks the custom name. } @Override public void setCustomNameVisible(boolean visible) { // Locks the custom name. } @Override public void a(AxisAlignedBB boundingBox) { // Do not change it! } } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.EmptyBossBar; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.chat.TextComponent; import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.EntityItem; import net.minecraft.server.v1_8_R3.EntityPlayer; import net.minecraft.server.v1_8_R3.PacketPlayOutChat; import net.minecraft.server.v1_8_R3.PacketPlayOutTitle; import net.minecraft.server.v1_8_R3.PlayerConnection; import org.bukkit.OfflinePlayer; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftItem; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage; import org.bukkit.entity.Player; import java.util.Locale; import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { @Override public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { return OfflinePlayerDataImpl.create(offlinePlayer); } @Override public void setSkinTexture(SuperiorPlayer superiorPlayer) { superiorPlayer.runIfOnline(player -> { EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); Optional optional = entityPlayer.getProfile().getProperties().get("textures").stream().findFirst(); optional.ifPresent(property -> setSkinTexture(superiorPlayer, property)); }); } @Override public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { superiorPlayer.setTextureValue(property.getValue()); } @Override public void sendActionBar(Player player, String message) { PacketPlayOutChat packetPlayOutChat = new PacketPlayOutChat(null, (byte) 2); packetPlayOutChat.components = TextComponent.fromLegacyText(message); ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutChat); } @Override public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { return EmptyBossBar.getInstance(); } @Override public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; PacketPlayOutTitle times; if (title != null) { times = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.TITLE, CraftChatMessage.fromString(title)[0]); playerConnection.sendPacket(times); } if (subtitle != null) { times = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.SUBTITLE, CraftChatMessage.fromString(subtitle)[0]); playerConnection.sendPacket(times); } times = new PacketPlayOutTitle(fadeIn, duration, fadeOut); playerConnection.sendPacket(times); } @Override public boolean wasThrownByPlayer(org.bukkit.entity.Item item, SuperiorPlayer superiorPlayer) { Entity entity = ((CraftItem) item).getHandle(); return entity instanceof EntityItem && superiorPlayer.getName().equals(((EntityItem) entity).n()); } @Nullable @Override public Locale getPlayerLocale(Player player) { try { return PlayerLocales.getLocale(player.spigot().getLocale()); } catch (IllegalArgumentException error) { return null; } } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.Tag; import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.EntityTypes; import net.minecraft.server.v1_8_R3.ItemStack; import net.minecraft.server.v1_8_R3.MinecraftKey; import net.minecraft.server.v1_8_R3.NBTBase; import net.minecraft.server.v1_8_R3.NBTTagByte; import net.minecraft.server.v1_8_R3.NBTTagByteArray; import net.minecraft.server.v1_8_R3.NBTTagCompound; import net.minecraft.server.v1_8_R3.NBTTagDouble; import net.minecraft.server.v1_8_R3.NBTTagFloat; import net.minecraft.server.v1_8_R3.NBTTagInt; import net.minecraft.server.v1_8_R3.NBTTagIntArray; import net.minecraft.server.v1_8_R3.NBTTagList; import net.minecraft.server.v1_8_R3.NBTTagLong; import net.minecraft.server.v1_8_R3.NBTTagShort; import net.minecraft.server.v1_8_R3.NBTTagString; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; import org.bukkit.entity.EntityType; import java.util.Set; @SuppressWarnings({"unused"}) public class NMSTagsImpl implements NMSTags { @Override public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); NBTTagCompound tagCompound = itemStack.save(new NBTTagCompound()); return CompoundTag.fromNBT(tagCompound); } @Override public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { if (compoundTag.containsKey("NBT")) { // Old compound version, deserialize it accordingly return deserializeItemOld(compoundTag); } NBTTagCompound tagCompound = (NBTTagCompound) compoundTag.toNBT(); ItemStack itemStack = ItemStack.createStack(tagCompound); return CraftItemStack.asCraftMirror(itemStack); } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); int amount = compoundTag.getInt("amount").orElse(0); short data = (short) compoundTag.getShort("data").orElse(0); CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); if (nbtData != null) itemStack.setTag((NBTTagCompound) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } @Override public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) { CraftWorld craftWorld = (CraftWorld) location.getWorld(); NBTTagCompound nbtTagCompound = (NBTTagCompound) compoundTag.toNBT(); if (nbtTagCompound == null) nbtTagCompound = new NBTTagCompound(); if (!nbtTagCompound.hasKey("id")) //noinspection deprecation nbtTagCompound.setString("id", new MinecraftKey(entityType.getName()).a()); Entity entity = EntityTypes.a(nbtTagCompound, craftWorld.getHandle()); entity.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((NBTTagByteArray) object).c(); } @Override public byte getNBTByteValue(Object object) { return ((NBTTagByte) object).f(); } @Override public Set getNBTCompoundValue(Object object) { return ((NBTTagCompound) object).c(); } @Override public double getNBTDoubleValue(Object object) { return ((NBTTagDouble) object).g(); } @Override public float getNBTFloatValue(Object object) { return ((NBTTagFloat) object).h(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((NBTTagIntArray) object).c(); } @Override public int getNBTIntValue(Object object) { return ((NBTTagInt) object).d(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((NBTTagList) object).g(index); } @Override public long getNBTLongValue(Object object) { return ((NBTTagLong) object).c(); } @Override public short getNBTShortValue(Object object) { return ((NBTTagShort) object).e(); } @Override public String getNBTStringValue(Object object) { return ((NBTTagString) object).a_(); } @Override public Object parseList(ListTag listTag) { NBTTagList nbtTagList = new NBTTagList(); for (Tag tag : listTag) nbtTagList.add((NBTBase) tag.toNBT()); return nbtTagList; } @Override public Object getNBTCompoundTag(Object object, String key) { return ((NBTTagCompound) object).get(key); } @Override public void setNBTCompoundTagValue(Object object, String key, Object value) { ((NBTTagCompound) object).set(key, (NBTBase) value); } @Override public int getNBTTagListSize(Object object) { return ((NBTTagList) object).size(); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.google.common.collect.Maps; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.Chunk; import net.minecraft.server.v1_8_R3.ChunkProviderServer; import net.minecraft.server.v1_8_R3.ChunkRegionLoader; import net.minecraft.server.v1_8_R3.ChunkSection; import net.minecraft.server.v1_8_R3.EntityHuman; import net.minecraft.server.v1_8_R3.EntityPlayer; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.IChunkLoader; import net.minecraft.server.v1_8_R3.NBTTagCompound; import net.minecraft.server.v1_8_R3.Packet; import net.minecraft.server.v1_8_R3.PlayerChunkMap; import net.minecraft.server.v1_8_R3.TileEntity; import net.minecraft.server.v1_8_R3.World; import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final ReflectField CHUNK_LOADER = new ReflectField<>( ChunkProviderServer.class, IChunkLoader.class, "chunkLoader"); private static final Map chunkLoadersMap = Maps.newConcurrentMap(); public static final ObjectsPool> BLOCK_POS_POOL = ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0)); private NMSUtils() { } @Nullable public static T getTileEntityAt(Location location, Class type) { org.bukkit.World bukkitWorld = location.getWorld(); if (bukkitWorld == null) return null; WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); TileEntity tileEntity = worldServer.getTileEntity(blockPosition); return !type.isInstance(tileEntity) ? null : type.cast(tileEntity); } } public static void runActionOnChunks(Collection chunksCoords, boolean saveChunks, ChunkCallback chunkCallback) { List unloadedChunks = new LinkedList<>(); List loadedChunks = new LinkedList<>(); chunksCoords.forEach(chunkPosition -> { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); Chunk chunk = worldServer.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); if (chunk != null) { loadedChunks.add(chunk); } else { unloadedChunks.add(chunkPosition.copy()); } }); boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); loadedChunks.forEach(loadedChunk -> chunkCallback.onChunk(loadedChunk, true)); if (hasUnloadedChunks) { runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback); } else { chunkCallback.onFinish(); } } public static void runActionOnUnloadedChunks(Collection chunks, boolean saveChunks, ChunkCallback chunkCallback) { chunks.forEach(chunkPosition -> { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); IChunkLoader chunkLoader = chunkLoadersMap.computeIfAbsent(worldServer.getDataManager().getUUID(), uuid -> CHUNK_LOADER.get(worldServer.chunkProviderServer)); if (chunkLoader instanceof ChunkRegionLoader && !((ChunkRegionLoader) chunkLoader).chunkExists(worldServer, chunkPosition.getX(), chunkPosition.getZ())) return; try { Chunk loadedChunk = chunkLoader.a(worldServer, chunkPosition.getX(), chunkPosition.getZ()); if (loadedChunk != null) { chunkCallback.onChunk(loadedChunk, false); if (saveChunks) { try { chunkLoader.a(worldServer, loadedChunk); } catch (Exception error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } } } chunkCallback.onFinish(); } catch (Exception error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); } public static void sendPacketToRelevantPlayers(WorldServer worldServer, int chunkX, int chunkZ, Packet packet) { PlayerChunkMap playerChunkMap = worldServer.getPlayerChunkMap(); for (EntityHuman entityHuman : worldServer.players) { if (entityHuman instanceof EntityPlayer && playerChunkMap.a((EntityPlayer) entityHuman, chunkX, chunkZ)) ((EntityPlayer) entityHuman).playerConnection.sendPacket(packet); } } public static void setBlock(Chunk chunk, BlockPosition blockPosition, int combinedId, CompoundTag tileEntity) { if (!isValidPosition(chunk.world, blockPosition)) return; IBlockData blockData = Block.getByCombinedId(combinedId); if (blockData.getBlock().getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) { chunk.world.setTypeAndData(blockPosition, blockData, 3); return; } int blockX = blockPosition.getX() & 15; int blockY = blockPosition.getY(); int blockZ = blockPosition.getZ() & 15; int highestBlockLight = chunk.b(blockX, blockZ); boolean initLight = false; int indexY = blockY >> 4; ChunkSection chunkSection = chunk.getSections()[indexY]; if (chunkSection == null) { chunkSection = chunk.getSections()[indexY] = new ChunkSection(indexY << 4, !chunk.world.worldProvider.o()); initLight = blockY > highestBlockLight; } chunkSection.setType(blockX, blockY & 15, blockZ, blockData); chunk.e(); if (initLight) chunk.initLighting(); if (tileEntity != null) { NBTTagCompound tileEntityCompound = (NBTTagCompound) tileEntity.toNBT(); if (tileEntityCompound != null) { tileEntityCompound.setInt("x", blockPosition.getX()); tileEntityCompound.setInt("y", blockPosition.getY()); tileEntityCompound.setInt("z", blockPosition.getZ()); TileEntity worldTileEntity = chunk.world.getTileEntity(blockPosition); if (worldTileEntity != null) worldTileEntity.a(tileEntityCompound); } } } private static boolean isValidPosition(World world, BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && blockPosition.getY() >= 0 && blockPosition.getY() < world.getHeight(); } public interface ChunkCallback { void onChunk(Chunk chunk, boolean isLoaded); void onFinish(); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import com.bgsoftware.superiorskyblock.nms.NMSWorld; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.spawners.MobSpawnerAbstractNotifier; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockDoubleStep; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.EnumParticle; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.IChatBaseComponent; import net.minecraft.server.v1_8_R3.MobSpawnerAbstract; import net.minecraft.server.v1_8_R3.PacketPlayOutBlockChange; import net.minecraft.server.v1_8_R3.PacketPlayOutWorldBorder; import net.minecraft.server.v1_8_R3.TileEntityMobSpawner; import net.minecraft.server.v1_8_R3.TileEntitySign; import net.minecraft.server.v1_8_R3.WorldBorder; import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.block.CraftSign; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.material.MaterialData; import java.lang.reflect.Modifier; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { private static final ReflectField MOB_SPAWNER_ABSTRACT = new ReflectField( TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static boolean alreadyWarned = false; private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { try { return getBlockKeyInternal(chunkSnapshot, x, y, z); } catch (ArrayIndexOutOfBoundsException error) { return ConstantKeys.AIR; } } @SuppressWarnings("deprecation") private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { int blockId = chunkSnapshot.getBlockTypeId(x, y, z); int blockData = chunkSnapshot.getBlockData(x, y, z); int combinedId = blockId + (blockData << 12); Location location = new Location( Bukkit.getWorld(chunkSnapshot.getWorldName()), (chunkSnapshot.getX() << 4) + x, y, (chunkSnapshot.getZ() << 4) + z ); return Keys.of(KeyBlocksCache.getBlockKey(Block.getByCombinedId(combinedId)), location); } @Override public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) { try { return canPlayerSuffocateInternal(chunkSnapshot, x, y, z); } catch (ArrayIndexOutOfBoundsException error) { return true; } } @SuppressWarnings("deprecation") private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { int blockId = chunkSnapshot.getBlockTypeId(x, y, z); int blockData = chunkSnapshot.getBlockData(x, y, z); int combinedId = blockId + (blockData << 12); return Block.getByCombinedId(combinedId).getBlock().w(); } @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); if (mobSpawner == null) return; MobSpawnerAbstract mobSpawnerAbstract = mobSpawner.getSpawner(); if (mobSpawnerAbstract instanceof MobSpawnerAbstractNotifier) return; MobSpawnerAbstractNotifier mobSpawnerAbstractNotifier = new MobSpawnerAbstractNotifier(mobSpawnerAbstract, delayChangeCallback); MOB_SPAWNER_ABSTRACT.set(mobSpawner, mobSpawnerAbstractNotifier); mobSpawnerAbstractNotifier.updateDelay(); } @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) return; Player player = superiorPlayer.asPlayer(); World world = superiorPlayer.getWorld(); if (world == null || player == null) return; int islandSize = island == null ? 0 : island.getIslandSize(); boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; WorldServer worldServer = ((CraftWorld) superiorPlayer.getWorld()).getHandle(); WorldBorder worldBorder; if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { worldBorder = worldServer.getWorldBorder(); } else { Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); if (dimension == null) return; Location center = island.getCenter(dimension); worldBorder = new WorldBorder(); worldBorder.world = worldServer; worldBorder.setWarningDistance(0); if (dimension.getEnvironment() == World.Environment.NETHER) { worldBorder.setCenter(center.getX() * 8, center.getZ() * 8); } else { worldBorder.setCenter(center.getX(), center.getZ()); } switch (superiorPlayer.getBorderColor()) { case BLUE: { worldBorder.setSize((islandSize * 2) + 1D); break; } case GREEN: { worldBorder.setSize((islandSize * 2) + 1.001D); worldBorder.transitionSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); break; } case RED: { worldBorder.setSize((islandSize * 2) + 1D); worldBorder.transitionSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); break; } } } PacketPlayOutWorldBorder packetPlayOutWorldBorder = new PacketPlayOutWorldBorder(worldBorder, PacketPlayOutWorldBorder.EnumWorldBorderAction.INITIALIZE); ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutWorldBorder); } @Override public Object getBlockData(org.bukkit.block.Block block) { throw new UnsupportedOperationException(); } @Override public void setBlock(Location location, int combinedId) { WorldServer world = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null); NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, new PacketPlayOutBlockChange(world, blockPosition)); } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } @Override public boolean isWaterLogged(org.bukkit.block.Block block) { Material blockType = block.getType(); return blockType == Material.WATER || blockType == Material.STATIONARY_WATER; } @Override public SignType getSignType(org.bukkit.block.Block block) { Material blockType = block.getType(); return blockType == Material.SIGN_POST ? SignType.STANDING_SIGN : blockType == Material.WALL_SIGN ? SignType.WALL_SIGN : SignType.UNKNOWN; } @Override public SignType getSignType(Object sign) { throw new UnsupportedOperationException("Not supported"); } @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { Block nmsBlock = CraftMagicNumbers.getBlock(block); return PistonPushReaction.values()[nmsBlock.getMaterial().getPushReaction()]; } @Override public int getDefaultAmount(org.bukkit.block.Block block) { WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); IBlockData blockData = worldServer.getType(new BlockPosition(block.getX(), block.getY(), block.getZ())); return getDefaultAmount(blockData); } @Override public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { MaterialData materialData = bukkitBlockState.getData(); // noinspection deprecation int combinedId = materialData.getItemType().getId() + (materialData.getData() << 12); return getDefaultAmount(Block.getByCombinedId(combinedId)); } private int getDefaultAmount(IBlockData blockData) { Block nmsBlock = blockData.getBlock(); // Checks for double slabs if (nmsBlock instanceof BlockDoubleStep) { return 2; } return 1; } @Override public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { WorldServer worldServer = ((CraftWorld) bukkitBlock.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); return worldServer.getType(blockPosition).getBlock().w(); } } @Override public void placeSign(Island island, Location location) { TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); if (tileEntitySign == null) return; String[] lines = new String[4]; System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); String[] strippedLines = new String[4]; for (int i = 0; i < 4; i++) strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); IChatBaseComponent[] newLines; IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); if (result.isCancelEvent()) { newLines = CraftSign.sanitizeLines(strippedLines); } else { newLines = CraftSign.sanitizeLines(lines); } System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } @Override public void playGeneratorSound(Location location) { WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); double x = location.getX(); double y = location.getY(); double z = location.getZ(); blockPosition.c(x, y, z); worldServer.makeSound(x + 0.5D, y + 0.5D, z + 0.5D, "random.fizz", 0.5F, 2.6F + (worldServer.random.nextFloat() - worldServer.random.nextFloat()) * 0.8F); for (int i = 0; i < 8; i++) { worldServer.addParticle(EnumParticle.SMOKE_LARGE, x + Math.random(), y + 1.2D, z + Math.random(), 0.0D, 0.0D, 0.0D); } } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(block.getX(), block.getY(), block.getZ()); worldServer.a(null, 2001, blockPosition, Block.getCombinedId(worldServer.getType(blockPosition))); } } @Override public void playPlaceSound(Location location) { WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); Block.StepSound stepSound = worldServer.getType(blockPosition).getBlock().stepSound; worldServer.makeSound(blockPosition.getX() + 0.5F, blockPosition.getY() + 0.5F, blockPosition.getZ() + 0.5F, stepSound.getPlaceSound(), (stepSound.getVolume1() + 1.0F) / 2.0F, stepSound.getVolume2() * 0.8F); } } @Override public int getMinHeight(World world) { return 0; } @Override public void removeAntiXray(World bukkitWorld) { // Doesn't exist in this version. } @Override public void setOceanLevel(World world) { ((CraftWorld) world).getHandle().b(plugin.getSettings().getWorlds().getSeaLevelHeight()); } @Override public IslandsGenerator createGenerator(Dimension dimension) { return new IslandsGeneratorImpl(dimension); } @Override public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } @Override public WorldEditSession createPartialEditSession(Dimension dimension) { return WorldEditSessionImpl.obtain(dimension); } @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } @Override public void listenBlockStateChanges(org.bukkit.World world) { if (!alreadyWarned) { Log.warn("This version is old and you may experience issues with block changes detection"); alreadyWarned = true; } } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.chunks; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.Chunk; import net.minecraft.server.v1_8_R3.ChunkCoordIntPair; import net.minecraft.server.v1_8_R3.ChunkSection; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.IUpdatePlayerListBox; import net.minecraft.server.v1_8_R3.TileEntity; import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; public class CropsTickingTileEntity extends TileEntity implements IUpdatePlayerListBox { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static Set CROPS_TO_GROW_CACHE; static { plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingTileEntity::onSettingsUpdate); } private static final Chunk2ObjectMap tickingChunks = new Chunk2ObjectMap<>(); private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; private final WeakReference chunk; private final int chunkX; private final int chunkZ; private int currentTick = 0; private double cachedCropGrowthMultiplier; public static void register() { // Calls the static initializer which registers the callback. } public static CropsTickingTileEntity remove(String worldName, long chunkCoords) { return tickingChunks.remove(worldName, chunkCoords); } public static void create(Island island, String worldName, Chunk chunk) { long chunkKey = ChunkCoordIntPair.a(chunk.locX, chunk.locZ); tickingChunks.computeIfAbsent(worldName, chunkKey, () -> new CropsTickingTileEntity(island, chunk)); } public static void forEachChunk(List chunkPositions, Consumer cropsTickingTileEntityConsumer) { if (tickingChunks.isEmpty()) return; chunkPositions.forEach(chunkPosition -> { long chunkKey = chunkPosition.asPair(); CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey); if (cropsTickingTileEntity != null) cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity); }); } private CropsTickingTileEntity(Island island, Chunk chunk) { this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(chunk); this.chunkX = chunk.locX; this.chunkZ = chunk.locZ; a(chunk.getWorld()); a(new BlockPosition(chunkX << 4, 1, chunkZ << 4)); try { world.tileEntityList.add(this); } catch (Throwable error) { world.a(this); } this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; } @Override public void c() { if (++currentTick <= plugin.getSettings().getCropsInterval()) return; Chunk chunk = this.chunk.get(); Island island = this.island.get(); if (chunk == null || island == null) { world.tileEntityList.remove(this); return; } currentTick = 0; int worldRandomTick = world.getGameRules().c("randomTickSpeed"); int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); if (chunkRandomTickSpeed > 0) { for (ChunkSection chunkSection : chunk.getSections()) { if (chunkSection != null && chunkSection.shouldTick()) { for (int i = 0; i < chunkRandomTickSpeed; i++) { random = random * 3 + 1013904223; int factor = random >> 2; int x = factor & 15; int z = factor >> 8 & 15; int y = factor >> 16 & 15; IBlockData blockData = chunkSection.getType(x, y, z); Block block = blockData.getBlock(); if (block.isTicking() && CROPS_TO_GROW_CACHE.contains(block)) { block.a(world, new BlockPosition(x + (chunkX << 4), y + chunkSection.getYPosition(), z + (chunkZ << 4)), blockData, ThreadLocalRandom.current()); } } } } } } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { this.cachedCropGrowthMultiplier = cropGrowthMultiplier; } private static void onSettingsUpdate() { CROPS_TO_GROW_CACHE = new HashSet<>(); plugin.getSettings().getCropsToGrow().forEach(cropName -> { Key key = Keys.ofMaterialAndData(cropName); if (key instanceof MaterialKey) { Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial()); if (block != null && block.isTicking()) CROPS_TO_GROW_CACHE.add(block); } }); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/generator/IslandsGeneratorImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.generator; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_8_R3.BiomeBase; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlock; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random; @SuppressWarnings("unused") public class IslandsGeneratorImpl extends IslandsGenerator { private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( new ClassInfo("generator.CustomChunkGenerator$CustomBiomeGrid", ClassInfo.PackageType.CRAFTBUKKIT), BiomeBase[].class, "biome"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Dimension dimension; public IslandsGeneratorImpl(Dimension dimension) { this.dimension = dimension; } @Override public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) { ChunkData chunkData = createChunkData(world); Biome targetBiome = IslandUtils.getDefaultWorldBiome(this.dimension); setBiome(biomeGrid, targetBiome); if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { chunkData.setBlock(0, 99, 0, Material.BEDROCK); } return chunkData; } @Override public List getDefaultPopulators(World world) { return Collections.emptyList(); } @Override public Location getFixedSpawnLocation(World world, Random random) { return new Location(world, 0, 100, 0); } private static void setBiome(ChunkGenerator.BiomeGrid biomeGrid, Biome biome) { BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(biome); BiomeBase[] biomeBases = BIOME_BASE_ARRAY.get(biomeGrid); if (biomeBases == null) return; Arrays.fill(biomeBases, biomeBase); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/player/OfflinePlayerDataImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.player; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.mojang.authlib.GameProfile; import net.minecraft.server.v1_8_R3.EntityPlayer; import net.minecraft.server.v1_8_R3.MinecraftServer; import net.minecraft.server.v1_8_R3.PlayerInteractManager; import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.craftbukkit.v1_8_R3.CraftServer; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.Optional; public class OfflinePlayerDataImpl implements OfflinePlayerData { private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); private Player fakePlayer; public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { return POOL.obtain().initialize(offlinePlayer); } private OfflinePlayerDataImpl() { } private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); WorldServer worldServer = server.getWorldServer(0); EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); this.fakePlayer = entityPlayer.getBukkitEntity(); this.fakePlayer.loadData(); return this; } @Override public Player getFakeOnlinePlayer() { return this.fakePlayer; } @Override public void setLocation(Location location) { EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle(); entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } @Override public void applyChanges() { this.fakePlayer.saveData(); } @Override public void release() { this.fakePlayer = null; POOL.release(this); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/spawners/MobSpawnerAbstractNotifier.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.spawners; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.MobSpawnerAbstract; import net.minecraft.server.v1_8_R3.NBTTagCompound; import net.minecraft.server.v1_8_R3.World; import java.util.function.IntFunction; public class MobSpawnerAbstractNotifier extends MobSpawnerAbstract { private final MobSpawnerAbstract mobSpawnerAbstract; private final IntFunction delayChangeCallback; public MobSpawnerAbstractNotifier(MobSpawnerAbstract mobSpawnerAbstract, IntFunction delayChangeCallback) { this.mobSpawnerAbstract = mobSpawnerAbstract; this.delayChangeCallback = delayChangeCallback; // Copy data from original spawner to this NBTTagCompound spawnerCompound = new NBTTagCompound(); mobSpawnerAbstract.b(spawnerCompound); this.a(spawnerCompound); } @Nullable @Override public String getMobName() { return mobSpawnerAbstract.getMobName(); } @Override public void setMobName(String name) { mobSpawnerAbstract.setMobName(name); } @Override public void c() { int startDelay = mobSpawnerAbstract.spawnDelay; try { mobSpawnerAbstract.c(); } finally { int newDelay = mobSpawnerAbstract.spawnDelay; if (newDelay > startDelay) updateDelay(); } } @Override public void a(NBTTagCompound nbttagcompound) { mobSpawnerAbstract.a(nbttagcompound); } @Override public void b(NBTTagCompound nbttagcompound) { mobSpawnerAbstract.b(nbttagcompound); } @Override public boolean b(int i) { return mobSpawnerAbstract.b(i); } @Override public void a(a mobspawnerabstract_a) { mobSpawnerAbstract.a(mobspawnerabstract_a); } @Override public void a(int i) { mobSpawnerAbstract.a(i); } @Override public World a() { return mobSpawnerAbstract.a(); } @Override public BlockPosition b() { return mobSpawnerAbstract.b(); } public void updateDelay() { mobSpawnerAbstract.spawnDelay = delayChangeCallback.apply(mobSpawnerAbstract.spawnDelay); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/BlockEntityCache.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.IContainer; import net.minecraft.server.v1_8_R3.MinecraftServer; import net.minecraft.server.v1_8_R3.NBTTagCompound; import net.minecraft.server.v1_8_R3.TileEntity; import net.minecraft.server.v1_8_R3.World; import java.util.IdentityHashMap; import java.util.Map; public class BlockEntityCache { private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); private BlockEntityCache() { } public static String getTileEntityId(IBlockData blockData) { return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> { if (block instanceof IContainer) { World world = MinecraftServer.getServer().getWorld(); TileEntity tileEntity = ((IContainer) block).a(world, block.toLegacyData(blockData)); if (tileEntity != null) { NBTTagCompound nbtTagCompound = new NBTTagCompound(); tileEntity.b(nbtTagCompound); return nbtTagCompound.getString("id"); } } return ""; }); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/ChunkReaderImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.Chunk; import net.minecraft.server.v1_8_R3.ChunkSection; import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.NBTTagCompound; import net.minecraft.server.v1_8_R3.NBTTagFloat; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.entity.EntityType; import org.bukkit.inventory.InventoryHolder; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class ChunkReaderImpl implements ChunkReader { private static final short[] EMPTY_BLOCKS = new short[4096]; private static final byte[] EMPTY_DATA = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; private final int x; private final int z; private final Map tileEntities = new HashMap<>(); private final List entities = new LinkedList<>(); private final short[][] blockids; private final byte[][] blockdata; private final byte[][] skylight; private final byte[][] emitlight; public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); this.x = chunk.locX; this.z = chunk.locZ; ChunkSection[] chunkSections = chunk.getSections(); this.blockids = new short[chunkSections.length][]; this.blockdata = new byte[chunkSections.length][]; this.skylight = new byte[chunkSections.length][]; this.emitlight = new byte[chunkSections.length][]; for (int i = 0; i < this.blockids.length; ++i) { ChunkSection chunkSection = chunkSections[i]; if (chunkSection == null) { this.blockids[i] = EMPTY_BLOCKS; this.blockdata[i] = EMPTY_DATA; this.skylight[i] = EMPTY_LIGHT; this.emitlight[i] = EMPTY_LIGHT; } else { copyBlockIds(chunkSection.getIdArray(), i); if (chunkSection.getSkyLightArray() == null) { skylight[i] = EMPTY_LIGHT; } else { skylight[i] = new byte[2048]; System.arraycopy(chunkSection.getSkyLightArray().a(), 0, skylight[i], 0, 2048); } emitlight[i] = new byte[2048]; System.arraycopy(chunkSection.getEmittedLightArray().a(), 0, emitlight[i], 0, 2048); } } chunk.getTileEntities().forEach((blockPosition, tileEntity) -> { NBTTagCompound tileEntityCompound = new NBTTagCompound(); tileEntity.b(tileEntityCompound); tileEntityCompound.remove("x"); tileEntityCompound.remove("y"); tileEntityCompound.remove("z"); InventoryHolder inventoryHolder = tileEntity.getOwner(); if (inventoryHolder != null) tileEntityCompound.setString("inventoryType", inventoryHolder.getInventory().getType().name()); tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound)); }); for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); } @Override public int getX() { return this.x; } @Override public int getZ() { return this.z; } @Override public Material getType(int x, int y, int z) { return Material.getMaterial(this.getBlockId(x, y, z)); } @Override public short getData(int x, int y, int z) { int off = (y & 15) << 7 | z << 3 | x >> 1; return (short) (this.blockdata[y >> 4][off] >> ((x & 1) << 2) & 15); } @Override @Nullable public CompoundTag getTileEntity(int x, int y, int z) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.c((this.x << 4) + x, y, (this.z << 4) + z); return this.tileEntities.get(blockPosition); } } @Override @Nullable public CompoundTag readBlockStates(int x, int y, int z) { // Doesn't exist return null; } @Override public byte[] getLightLevels(int x, int y, int z) { int off = (y & 15) << 7 | z << 3 | x >> 1; int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15; int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15; return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; } @Override public void forEachEntity(EntityConsumer consumer) { if (entities.isEmpty()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = wrapper.getHandle(); for (CachedEntity cachedEntity : entities) { location.setX(cachedEntity.x); location.setY(cachedEntity.y); location.setZ(cachedEntity.z); location.setYaw(cachedEntity.yaw); location.setPitch(cachedEntity.pitch); consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); } } } private int getBlockId(int x, int y, int z) { return this.blockids[y >> 4][(y & 15) << 8 | z << 4 | x]; } private void copyBlockIds(char[] baseids, int i) { short[] blockids = this.blockids[i] = new short[4096]; byte[] dataValues = this.blockdata[i] = new byte[2048]; for (int j = 0; j < 4096; ++j) { if (baseids[j] != 0) { IBlockData blockData = Block.d.a(baseids[j]); if (blockData != null) { blockids[j] = (short) Block.getId(blockData.getBlock()); int data = blockData.getBlock().toLegacyData(blockData); int k = j >> 1; if ((j & 1) == 0) { dataValues[k] = (byte) (dataValues[k] & 240 | data & 15); } else { dataValues[k] = (byte) (dataValues[k] & 15 | (data & 15) << 4); } } } } } private static class CachedEntity { private final double x; private final double y; private final double z; private final float yaw; private final float pitch; private final EntityType entityType; private final CompoundTag entityTag; CachedEntity(Entity entity) { this.x = entity.locX; this.y = entity.locY; this.z = entity.locZ; this.yaw = entity.yaw; this.pitch = entity.pitch; this.entityType = entity.getBukkitEntity().getType(); NBTTagCompound nbtTagCompound = new NBTTagCompound(); entity.c(nbtTagCompound); nbtTagCompound.set("Yaw", new NBTTagFloat(entity.yaw)); nbtTagCompound.set("Pitch", new NBTTagFloat(entity.pitch)); this.entityTag = CompoundTag.fromNBT(nbtTagCompound); } } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/KeyBlocksCache.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.key.Keys; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.IBlockData; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import java.util.IdentityHashMap; import java.util.Map; public class KeyBlocksCache { private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); private KeyBlocksCache() { } public static Key getBlockKey(IBlockData blockData) { return BLOCK_TO_KEY.computeIfAbsent(blockData, unused -> { Block block = blockData.getBlock(); Material blockType = CraftMagicNumbers.getMaterial(block); if (blockType == null) return null; byte data = (byte) block.toLegacyData(blockData); return Keys.of(blockType, data); }); } public static void cacheAllBlocks() { Block.d.forEach(KeyBlocksCache::getBlockKey); } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionDataImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.ChunkCoordIntPair; import net.minecraft.server.v1_8_R3.IBlockData; import org.bukkit.Location; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class WorldEditSessionDataImpl implements WorldEditSession.Data { private final List> chunks = new LinkedList<>(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List> lights = new LinkedList<>(); public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, List> blocksToUpdate, List> blockEntities, List lights) { int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); int baseChunkPosXAxis = baseBlockPosXAxis >> 4; int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // Convert chunk data Iterator> chunksIterator = chunks.entryIterator(); while (chunksIterator.hasNext()) { Long2ObjectMapView.Entry entry = chunksIterator.next(); int currChunkPosXAxis = getChunkCoordX(entry.getKey()); int currChunkPosZAxis = getChunkCoordZ(entry.getKey()); this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, currChunkPosZAxis - baseChunkPosZAxis, entry.getValue())); } // Convert blocksToUpdate blocksToUpdate.forEach(blockToUpdate -> { BlockPosition blockPosition = blockToUpdate.getKey(); this.blocksToUpdate.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis, blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis, blockToUpdate.getValue())); }); // Convert blockEntities blockEntities.forEach(blockEntity -> { BlockPosition blockPosition = blockEntity.getKey(); this.blockEntities.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis, blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis, blockEntity.getValue())); }); // Convert lights lights.forEach(lightPosition -> { this.lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, null)); }); } public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, Long2ObjectMapView chunks) { this.chunks.forEach(chunkDataPositioned -> { long newPos = ChunkCoordIntPair.a(baseChunkPosXAxis + chunkDataPositioned.xOffset, baseChunkPosZAxis + chunkDataPositioned.zOffset); chunks.put(newPos, chunkDataPositioned.object); }); } public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { this.blocksToUpdate.forEach(blockToUpdatePositioned -> { BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, baseBlockPosYAxis + blockToUpdatePositioned.yOffset, baseBlockPosZAxis + blockToUpdatePositioned.zOffset); blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); }); } public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { this.blockEntities.forEach(blockEntityPositioned -> { BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset, baseBlockPosYAxis + blockEntityPositioned.yOffset, baseBlockPosZAxis + blockEntityPositioned.zOffset); blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); }); } public void readLights(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List lights) { this.lights.forEach(lightPositioned -> { BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset, baseBlockPosYAxis + lightPositioned.yOffset, baseBlockPosZAxis + lightPositioned.zOffset); lights.add(newPos); }); } private static int getChunkCoordX(long i) { return (int) (i & 4294967295L); } private static int getChunkCoordZ(long i) { return (int) (i >>> 32 & 4294967295L); } private static class PositionedObject { private final int xOffset; private final int yOffset; private final int zOffset; private final V object; PositionedObject(int xOffset, int zOffset, V object) { this(xOffset, 0, zOffset, object); } PositionedObject(int xOffset, int yOffset, int zOffset, V object) { this.xOffset = xOffset; this.yOffset = yOffset; this.zOffset = zOffset; this.object = object; } } } ================================================ FILE: NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.google.common.base.Preconditions; import net.minecraft.server.v1_8_R3.BiomeBase; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockBed; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.Chunk; import net.minecraft.server.v1_8_R3.ChunkCoordIntPair; import net.minecraft.server.v1_8_R3.ChunkSection; import net.minecraft.server.v1_8_R3.EnumSkyBlock; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.NBTTagCompound; import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk; import net.minecraft.server.v1_8_R3.TileEntity; import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_8_R3.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class WorldEditSessionImpl implements WorldEditSession { private static final ReflectMethod WORLD_SERVER_UPDATE_LIGHT_PAPER = new ReflectMethod<>( net.minecraft.server.v1_8_R3.World.class, "updateLight", EnumSkyBlock.class, BlockPosition.class); private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List lights = new LinkedList<>(); private Dimension dimension; @Nullable private WorldServer worldServer; public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } public static WorldEditSessionImpl obtain(Dimension dimension) { return POOL.obtain().initialize(dimension); } private WorldEditSessionImpl() { } private WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); return this; } private WorldEditSessionImpl initialize(Dimension dimension) { this.worldServer = null; this.dimension = dimension; return this; } @Override public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData) { BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); if (!isValidPosition(blockPosition)) return; IBlockData blockData = Block.getByCombinedId(combinedId); Block block = blockData.getBlock(); if ((block.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || block instanceof BlockBed) { blocksToUpdate.add(new Pair<>(blockPosition, blockData)); return; } int chunkX = blockPosition.getX() >> 4; int chunkZ = blockPosition.getZ() >> 4; if (blockEntityData != null) blockEntities.add(new Pair<>(blockPosition, blockEntityData)); if (plugin.getSettings().isLightsUpdate() && block.r() > 0) this.lights.add(blockPosition); ChunkData chunkData = this.chunks.computeIfAbsent(ChunkCoordIntPair.a(chunkX, chunkZ), ChunkData::new); ChunkSection chunkSection = chunkData.chunkSections[blockPosition.getY() >> 4]; int blockX = blockPosition.getX() & 15; int blockY = blockPosition.getY(); int blockZ = blockPosition.getZ() & 15; chunkSection.setType(blockX, blockY & 15, blockZ, blockData); } @Override public List getAffectedChunks() { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); if (chunks.isEmpty()) return Collections.emptyList(); List chunkPositions = new LinkedList<>(); World bukkitWorld = worldServer.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); int chunkX = (int) chunkKey; int chunkZ = (int) (chunkKey >> 32); chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkData chunkData = this.chunks.get(ChunkCoordIntPair.a(chunk.locX, chunk.locZ)); if (chunkData == null) return; int chunkSectionsCount = Math.min(chunkData.chunkSections.length, chunk.getSections().length); for (int i = 0; i < chunkSectionsCount; ++i) { chunk.getSections()[i] = chunkData.chunkSections[i]; } // Update the biome for the chunk BiomeBase biome = CraftBlock.biomeToBiomeBase(IslandUtils.getDefaultWorldBiome(this.dimension)); Arrays.fill(chunk.getBiomeIndex(), (byte) biome.id); if (plugin.getSettings().isLightsUpdate()) { // initLightning calculates the light emitted from sky to the chunk. chunk.initLighting(); } chunk.e(); } @Override public void finish(Island island) { Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); // Update block entities blockEntities.forEach(data -> { NBTTagCompound blockEntityCompound = (NBTTagCompound) data.getValue().toNBT(); if (blockEntityCompound != null) { BlockPosition blockPosition = data.getKey(); blockEntityCompound.setInt("x", blockPosition.getX()); blockEntityCompound.setInt("y", blockPosition.getY()); blockEntityCompound.setInt("z", blockPosition.getZ()); TileEntity worldTileEntity = worldServer.getTileEntity(blockPosition); if (worldTileEntity != null) worldTileEntity.a(blockEntityCompound); } }); if (plugin.getSettings().isLightsUpdate() && !lights.isEmpty()) { // For each light block, we calculate its light // We only update the lights after all the chunks were loaded. BukkitExecutor.sync(() -> { if (WORLD_SERVER_UPDATE_LIGHT_PAPER.isValid()) { lights.forEach(blockPosition -> WORLD_SERVER_UPDATE_LIGHT_PAPER.invoke(worldServer, EnumSkyBlock.BLOCK, blockPosition)); } else { lights.forEach(blockPosition -> worldServer.c(EnumSkyBlock.BLOCK, blockPosition)); } LongIterator iterator = this.chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); NMSUtils.sendPacketToRelevantPlayers(worldServer, chunkCoord.x, chunkCoord.z, new PacketPlayOutMapChunk(worldServer.getChunkAt(chunkCoord.x, chunkCoord.z), true, 65535)); } }, 5L); } release(); } @Override public Data readData(Location baseLocation) { return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lights); } @Override public void applyData(Data data, Location baseLocation) { WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); int baseChunkPosXAxis = baseBlockPosXAxis >> 4; int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, this.chunks); dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); dataImpl.readLights(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.lights); } @Override public void release() { this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lights.clear(); this.worldServer = null; this.dimension = null; POOL.release(this); } private boolean isValidPosition(BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && blockPosition.getY() >= 0 && blockPosition.getY() < 256; } public class ChunkData { private final ChunkSection[] chunkSections = new ChunkSection[16]; private ChunkData(long chunkKey) { ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); createChunkSections(); if (worldServer != null) runCustomWorldGenerator(chunkCoord); } private void createChunkSections() { boolean hasSkyLight = dimension.getEnvironment() != World.Environment.THE_END; for (int i = 0; i < this.chunkSections.length; ++i) { int chunkSectionPos = i << 4; this.chunkSections[i] = new ChunkSection(chunkSectionPos, hasSkyLight); } } private void runCustomWorldGenerator(ChunkCoordIntPair chunkCoord) { ChunkGenerator bukkitGenerator = worldServer.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(worldServer, worldServer.getSeed(), bukkitGenerator); Chunk generatedChunk = chunkGenerator.getOrCreateChunk(chunkCoord.x, chunkCoord.z); for (int i = 0; i < this.chunkSections.length; ++i) { ChunkSection generatorChunkSection = generatedChunk.getSections()[i]; if (generatorChunkSection != null) this.chunkSections[i] = generatorChunkSection; } } } } ================================================ FILE: NMS/v26_1/build.gradle ================================================ plugins { id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { toolchain { languageVersion.set(JavaLanguageVersion.of(25)) } } paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.getMOJANG_PRODUCTION() group 'NMS:v26_1' dependencies { paperweight.paperDevBundle("26.1.1.build.+") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly project(":") } if (project.hasProperty('nms.compile_v26_1') && !Boolean.valueOf(project.findProperty("nms.compile_v26_1").toString())) { project.tasks.all { task -> task.enabled = false } } ================================================ FILE: NMS/v26_1/properties ================================================ NMS_VERSION=v26_1 CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) END_DRAGON_FIGHT_CLASS=EnderDragonFight SPIKE_FEATURE_CLASS=EndSpikeFeature ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1; import com.bgsoftware.common.reflection.ReflectField; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; import java.lang.reflect.Modifier; import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms { public static final ReflectField SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class, double[].class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); @Override public String parseSignLine(String original) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) .getOrThrow(JsonParseException::new); return COMPONENT_GSON.toJson(jsonElement); } @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); } @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); } @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); if (materialRegistry == null || patternRegistry == null) { return; } TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + " into trim material, skipping..."); if (pattern == null) throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + " into trim pattern, skipping..."); ArmorTrim armorTrim = new ArmorTrim(material, pattern); armorMeta.setTrim(armorTrim); } } @Override public void setHideTooltip(ItemMeta itemMeta) { itemMeta.setHideTooltip(true); } @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } @Override public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } @Override public double getCurrentTps() { return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; } @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); if (key == null) { return null; } Registry registry = Bukkit.getRegistry(Biome.class); if (registry == null) { return null; } return registry.get(key); } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v26_1.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.ProblemReporter; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import static com.bgsoftware.superiorskyblock.nms.v26_1.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSChunks { private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; if (currentSection != null) { PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); } } levelChunk.markUnsaved(); ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); DataResult dataResult = getBiomeContainerRWCodec() .encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); } @Override public void onFinish() { // Do nothing. } }; } @Override protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY); } removeEntities(levelChunk); removeBlockEntities(levelChunk); removeBlocks(levelChunk); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ListTag tileEntities = new ListTag(); chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() .encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } LevelLightEngine lightEngine = serverLevel.getLightEngine(); LevelChunkSection[] chunkSections = protoChunk.getSections(); ListTag sectionsList = new ListTag(); // Save blocks for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { int chunkSectionIndex = serverLevel.getSectionIndex(i); CompoundTag sectionCompound = new CompoundTag(); if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; { DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); sectionCompound.put("block_states", dataResult.getOrThrow()); } { DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec() .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); sectionCompound.put("biomes", dataResult.getOrThrow()); } } if (!sectionCompound.isEmpty()) { sectionCompound.putByte("Y", (byte) i); sectionsList.add(sectionCompound); } } for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, MinecraftServer.getServer().registryAccess()); if (blockEntityCompound != null) tileEntities.add(blockEntityCompound); } chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { if (onFinish != null) onFinish.run(); } }; } @Override protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, Synchronized> unloadedChunksCache, List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), levelChunk.locX, levelChunk.locZ, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { PalettedContainer blocksPalettedContainer; Optional blockStatesCompound = sectionCompound.getCompound("block_states"); if (blockStatesCompound.isPresent()) { DataResult> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get()) .promotePartial((sx) -> { }); blocksPalettedContainer = dataResult.getOrThrow(); } else { blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); } PalettedContainer> biomesPalettedContainer; Optional biomesCompound = sectionCompound.getCompound("biomes"); if (biomesCompound.isPresent()) { DataResult>> dataResult = getBiomeContainerRWCodec() .parse(NbtOps.INSTANCE, biomesCompound.get()) .promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); } else { biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes(); } chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); latchCountDown(); } @Override public void onFinish() { completableFuture.complete(allCalculatedChunks); } }; } @Override protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), levelChunk.locX, levelChunk.locZ, false); allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } completableFuture.complete(allCalculatedChunks); }); } }; } @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { int dataVersion = compoundTag.getIntOr("DataVersion", 0); if (dataVersion < com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION) { compoundTag = (CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION).getValue(); } try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL); } } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } private static Codec>> getBiomeContainerRWCodec() { if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) { return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY); } else { return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec(); } } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSEntitiesImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.minecart.PoweredMinecart; public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSEntities { @Override public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSTagsImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Util; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.slf4j.Logger; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSTags { private static final Logger LOGGER = LogUtils.getLogger(); @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); Multimap properties = HashMultimap.create(); properties.put("textures", new Property("textures", texture)); GameProfile gameProfile = new GameProfile(Util.NIL_UUID, "", new PropertyMap(properties)); ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile); itemStack.set(DataComponents.PROFILE, resolvableProfile); return CraftItemStack.asBukkitCopy(itemStack); } @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } @Override protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { return compoundTag.getIntOr(key, def); } @Override protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); return ItemStack.CODEC.parse(context, compoundTag) .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) .orElseThrow(); } @Override protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; }); } @Override public byte[] getNBTByteArrayValue(Object object) { return ((ByteArrayTag) object).getAsByteArray(); } @Override public byte getNBTByteValue(Object object) { return ((NumericTag) object).byteValue(); } @Override public Set getNBTCompoundValue(Object object) { return ((net.minecraft.nbt.CompoundTag) object).keySet(); } @Override public double getNBTDoubleValue(Object object) { return ((NumericTag) object).doubleValue(); } @Override public float getNBTFloatValue(Object object) { return ((NumericTag) object).floatValue(); } @Override public int[] getNBTIntArrayValue(Object object) { return ((IntArrayTag) object).getAsIntArray(); } @Override public int getNBTIntValue(Object object) { return ((NumericTag) object).intValue(); } @Override public Object getNBTListIndexValue(Object object, int index) { return ((net.minecraft.nbt.ListTag) object).get(index); } @Override public long getNBTLongValue(Object object) { return ((NumericTag) object).longValue(); } @Override public short getNBTShortValue(Object object) { return ((NumericTag) object).shortValue(); } @Override public String getNBTStringValue(Object object) { return ((StringTag) object).value(); } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSWorldImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v26_1.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v26_1.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v26_1.world.BlockLevelTicksTracker; import com.bgsoftware.superiorskyblock.nms.v26_1.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSWorld { private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); private static final ReflectField> BLOCK_TICKS = new ReflectField>( ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE, worldBorder.world.getGameTime()); } @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } @Override protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { return chunkGenerator.getDelegate(); } @Override protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { return new FlatLevelSource(original.settings()) { @Override public int getSeaLevel() { return seaLevel; } }; } @Override protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { return noiseBasedChunkGenerator.settings.value(); } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return; if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { VaultConfig vaultConfig = vaultBlockEntity.getConfig(); PlayerDetector playerDetector = vaultConfig.playerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; VaultConfig newConfig = new VaultConfig( vaultConfig.lootTable(), vaultConfig.activationRange(), vaultConfig.deactivationRange(), vaultConfig.keyItem(), vaultConfig.overrideLootTableToDisplay(), IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), vaultConfig.entitySelector() ); vaultBlockEntity.setConfig(newConfig); } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); if (playerDetector instanceof IslandPlayerDetector) return; trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); } } @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } @Override public SignType getSignType(Object sign) { if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else return super.getSignType(sign); } @Override public void listenBlockStateChanges(World world) { ServerLevel serverLevel = ((CraftWorld) world).getHandle(); COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.dragon; import com.bgsoftware.superiorskyblock.nms.v26_1.dragon.EndWorldEndDragonFightHandler; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EnderDragonFight; import java.util.List; import java.util.Optional; public class EndDragonFightWrapper extends EnderDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); public EndDragonFightWrapper(ServerLevel serverLevel) { super(true, false, false, Optional.empty(), 0, Optional.empty(), Optional.empty(), new ObjectArrayList(), List.of()); } @Override public void tick() { HANDLER.tick(); } protected BlockPos getPortalPos() { return this.exitPortalLocation; } protected void setPortalPos(BlockPos blockPos) { this.exitPortalLocation = blockPos; } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/IslandEntityEnderDragon.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.dragon; import com.bgsoftware.common.annotations.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.storage.ValueInput; public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v26_1.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { super(level, islandBlockPos); } public IslandEntityEnderDragon(Level level) { super(level); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override protected void readAdditionalSaveData(ValueInput input) { super.readAdditionalSaveData(input); finalizeIslandEnderDragon(); } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/hologram/EntityHologram.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.hologram; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v26_1.hologram.AbstractEntityHologram { public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { super(serverLevel, x, y, z); } @Override protected void addAdditionalSaveData(ValueOutput output) { // Do not save NBT. } @Override protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { // Do not save NBT. } @Override protected void readAdditionalSaveData(ValueInput input) { // Do not load NBT. } @Override public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { // Do not save NBT. return false; } @Override public boolean saveAsPassenger(ValueOutput output) { // Do not save NBT. return false; } @Override public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { // Do not save NBT. } @Override public void saveWithoutId(ValueOutput output) { // Do not save NBT. } @Override public void load(ValueInput input) { // Do not load NBT. } @Override public InteractionResult interact(Player player, InteractionHand hand, Vec3 location) { // Prevent stand being equipped return InteractionResult.PASS; } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final PlayerDetector original; private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; } @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } return players; } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/utils/NMSUtilsVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.utils; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.mutable.MutableInt; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v26_1.utils.TickingBlockList; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.util.ProblemReporter; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.Strategy; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkPyramid; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStep; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.dimension.end.EnderDragonFight; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.TagValueOutput; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.stream.Stream; public class NMSUtilsVersioned { private static final Logger LOGGER = LogUtils.getLogger(); private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create( MinecraftServer.getServer().registryAccess()); public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { return chunkMap.read(chunkPos).join().orElse(null); } public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { return chunkMap.upgradeChunkTag(chunkCompoundTag); } public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { chunkMap.write(chunkPos, () -> chunkCompoundTag); } public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { return BukkitExecutor.createTask().runSync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { countDownLatch.countDown(); throw new RuntimeException(error); } else { CompoundTag entityData = entityDataOptional.orElse(null); if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } }); }); }); } else { return BukkitExecutor.createTask().runAsync(v -> { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); try { MoonriseRegionFileIO.RegionDataController regionDataController = serverLevel.moonrise$getEntityChunkDataController(); int chunkX = chunkPosition.getX(); int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); if (readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); default -> null; }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); return; } } chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); }); } } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, DEFAULT_PALETTED_CONTAINER_FACTORY, null); } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null); } public static boolean isBlockStateLiquid(BlockState blockState) { return blockState.liquid(); } public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { return levelChunkSection.hasOnlyAir(); } public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); blockEntity.loadWithComponents(valueInput); } } public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { }, completeCallback -> { }); } public static void rewriteSignLines(CompoundTag compoundTag) { applySignTextLines(compoundTag, "front_text"); applySignTextLines(compoundTag, "back_text"); convertLegacySignTextLines(compoundTag); } public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { ResourceKey resourceKey; switch (dimension.getEnvironment()) { case NETHER -> resourceKey = LevelStem.NETHER; case THE_END -> resourceKey = LevelStem.END; default -> resourceKey = LevelStem.OVERWORLD; } HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); return registry.getOrThrow(resourceKey).value().type().value(); } public static void createChunkSections(@Nullable ServerLevel serverLevel, LevelHeightAccessor levelHeightAccessor, LevelChunkSection[] chunkSections, Dimension dimension) { Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); for (int i = 0; i < chunkSections.length; ++i) { PalettedContainer> biomesContainer = createBiomesContainer(biome); PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); } } public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, serverLevel.getChunkSource().getGenerator(), bukkitGenerator); ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); // Unsafe: we do not provide chunks cache, even tho it is required. // Should be fine in normal flow, as the only method that access the chunks cache // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); customChunkGenerator.buildSurface(region, serverLevel.structureManager().forWorldGenRegion(region), serverLevel.getChunkSource().randomState(), chunkAccess); } public static PalettedContainer createEmptyPlattedContainerStates() { return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); } public static PalettedContainer copyPalettedContainer(PalettedContainer original) { return original.copy(); } public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); } public static CompoundTag saveEntity(Entity entity) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); entity.save(valueOutput); return valueOutput.buildResult(); } } public static Material getMaterialFromBlock(Block block) { return CraftMagicNumbers.getMaterial(block); } public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); } public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { return new TickingBlockList() { @Override public int size() { return levelChunkSection.moonrise$getTickingBlockList().size(); } @Override public int getRaw(int index) { return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); } }; } public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { serverLevel.addFreshEntity(entity, spawnReason); } public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.properties(); } public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } public static EnderDragonFight getEndDragonFight(ServerLevel serverLevel) { return serverLevel.getDragonFight(); } public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { entity.absSnapTo(x, y, z, yaw, pitch); } public static int getMinSection(ServerLevel serverLevel) { return serverLevel.getMinSectionY(); } public static int getMinBuildHeight(ServerLevel serverLevel) { return serverLevel.getMinY(); } public static int getMaxBuildHeight(ServerLevel serverLevel) { return serverLevel.getMaxY(); } public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } public static PalettedContainer> createBiomesContainer(Holder biome) { Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); Strategy> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap()); return new PalettedContainerFactory( null, null, null, biomesStrategy, biome, null, null ).createForBiomes(); } public static Optional loadPlayerData(ServerPlayer serverPlayer) { try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()) .map(playerData -> { ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); serverPlayer.load(valueInput); return playerData; }); } } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { return compoundTag.getLongOr(key, def); } private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); } catch (JsonParseException error) { textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); } } for (int i = 0; i < 4; i++) { if (textLines.get(i) == null) textLines.set(i, Component.empty()); } Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); }); } private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { Component[] signLines = new Component[4]; Arrays.fill(signLines, Component.empty()); boolean hasAnySignLines = false; // We try to convert old text sign lines for (int i = 1; i <= 4; ++i) { if (blockEntityCompound.contains("SSB.Text" + i)) { String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; hasAnySignLines = true; } } else { String signLine = blockEntityCompound.getString("Text" + i).orElse(null); if (!Text.isBlank(signLine)) { signLines[i - 1] = CraftChatMessage.fromJSON(signLine); hasAnySignLines = true; } } } if (hasAnySignLines) { SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); } } public static BlockState getBlockState(org.bukkit.block.Block block) { return ((CraftBlock) block).getBlockState(); } public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { int[] count = new int[]{0}; blockState.getValues().forEach(value -> { ++count[0]; consumer.accept(value.property(), value.value()); }); return count[0] > 0; } public static Identifier getBlockEntityTypeKey(BlockEntityType type) { return BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(type); } private NMSUtilsVersioned() { } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/vibration/IslandVibrationUser.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gameevent.PositionSource; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import javax.annotation.Nullable; public class IslandVibrationUser implements VibrationSystem.User { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Island island; private final VibrationSystem.User original; public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { this.island = island; this.original = sculkSensorBlockEntity.getVibrationUser(); } @Override public int getListenerRadius() { return this.original.getListenerRadius(); } @Override public PositionSource getPositionSource() { return this.original.getPositionSource(); } @Override public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) return false; if (context.sourceEntity() instanceof Player player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); } return true; } @Override public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); } @Override public TagKey getListenableEvents() { return this.original.getListenableEvents(); } @Override public boolean canTriggerAvoidVibration() { return this.original.canTriggerAvoidVibration(); } @Override public boolean requiresAdjacentChunksToBeTicking() { return this.original.requiresAdjacentChunksToBeTicking(); } @Override public int calculateTravelTimeInTicks(float distance) { return this.original.calculateTravelTimeInTicks(distance); } @Override public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { return this.original.isValidVibration(gameEvent, context); } @Override public void onDataChanged() { this.original.onDataChanged(); } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/BlockLevelTicksTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.ticks.LevelTicks; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ServerLevel serverLevel; public BlockLevelTicksTracker(ServerLevel serverLevel) { super(serverLevel::isPositionTickingWithEntitiesLoaded); this.serverLevel = serverLevel; } @Override public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); try { // Only capture blocks related events plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); ticker.accept(blockPos, block); } finally { List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); // Remove BlockPhysicsEvent which we don't listen to capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. // This is to prevent blocks from being considered updated twice. if (!capturedEvents.isEmpty()) return; } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } }); } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/CollectingNeighborUpdaterTracker.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.redstone.CollectingNeighborUpdater; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Level level; public CollectingNeighborUpdaterTracker(Level level) { super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); this.level = level; } @Override public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, @Block.UpdateFlags int flags, int recursionLeft) { BlockState oldState = this.level.getBlockState(pos); super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); BlockState newState = this.level.getBlockState(pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); } } } ================================================ FILE: NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/PropertiesMapperVersioned.java ================================================ package com.bgsoftware.superiorskyblock.nms.v26_1.world; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import java.util.Map; public class PropertiesMapperVersioned { public static void initializeFields(Map fieldsToNames) { fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); } private PropertiesMapperVersioned() { } } ================================================ FILE: README.md ================================================

The most optimized Skyblock core on the market.



## Compiling You can compile the project using gradlew.
Run `gradlew build` in console to build the project.
You can find already compiled jars on our [Jenkins](https://hub.bg-software.com/) hub!
## API The plugin is packed with a rich API for interacting with islands, players and more. When hooking into the plugin, it's highly recommended to only use the API and not the compiled plugin, as the API methods are not only commented, but also will not get removed or changed unless they are marked as deprecated. This means that when using the API, you won't have to do any additional changes to your code between updates. ### Maven ```xml bg-repo https://repo.bg-software.com/repository/api/ com.bgsoftware SuperiorSkyblockAPI VERSION provided ``` ### Gradle ```text repositories { maven { url 'https://repo.bg-software.com/repository/api/' } } dependencies { compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:VERSION' } ``` Make sure you replace `VERSION` with the matching version. ## Updates This plugin is provided "as is", which means no updates or new features are guaranteed. We will do our best to keep updating and pushing new updates, and you are more than welcome to contribute your time as well and make pull requests for bug fixes. ## License This plugin is licensed under GNU GPL v3.0 This plugin uses HikariCP which you can find [here](https://github.com/brettwooldridge/HikariCP). ================================================ FILE: build.gradle ================================================ plugins { id 'java' id 'com.gradleup.shadow' version '9.4.1' id 'maven-publish' } group 'SuperiorSkyblock' version = "2026.1" project.ext { targetFolder = file("target/") buildVersion = System.getenv("BUILD_NUMBER") == null || Boolean.parseBoolean(System.getenv("STABLE_BUILD")) ? version : version + "-b" + System.getenv("BUILD_NUMBER") } allprojects { apply plugin: 'java' apply plugin: 'com.gradleup.shadow' java { toolchain { languageVersion.set(JavaLanguageVersion.of(8)) } } repositories { maven { url 'https://repo.bg-software.com/repository/nms/' } maven { url 'https://repo.bg-software.com/repository/api/' } maven { url 'https://repo.bg-software.com/repository/common/' } maven { url 'https://repo.bg-software.com/repository/dependencies/' } } dependencies { compileOnly 'com.bgsoftware.common.reflection:ReflectionUtils:b8' compileOnly 'com.bgsoftware.common.annotations:Annotations:b2' } tasks.register('checkDebug') { Set filesWithDebug = fileTree('src/main/java').filter { file -> file.text.contains('Bukkit.broadcastMessage') }.getFiles() if (!filesWithDebug.isEmpty()) throw new GradleException("Found debug messages: " + filesWithDebug) } shadowJar { relocate 'com.bgsoftware.common', 'com.bgsoftware.superiorskyblock.libs.com.bgsoftware.common' } build { dependsOn checkDebug dependsOn shadowJar } } repositories { mavenCentral() } dependencies { implementation project(":API") implementation 'com.bgsoftware.common.config:CommentedConfiguration:b1' implementation 'com.bgsoftware.common.updater:Updater:b1' implementation 'com.bgsoftware.common.reflection:ReflectionUtils:b8' implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b20' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2' implementation 'org.bstats:bstats-bukkit:3.0.0' // Spigot jars compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly 'org.spigotmc:v1_16_R3-Tuinity:latest' } processResources { outputs.upToDateWhen { false } eachFile { details -> if (details.name.contentEquals('plugin.yml')) { filter { String line -> line.replace('${project.version}', rootProject.buildVersion) } } } } subprojects.each { evaluationDependsOn(it.path) } shadowJar { relocate 'org.bstats', 'com.bgsoftware.superiorskyblock.libs.org.bstats' archiveClassifier.set('') from sourceSets.main.output from(project.configurations.runtimeClasspath.filter { it.name.endsWith('.jar') }.collect { zipTree(it) }) { exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' } duplicatesStrategy = DuplicatesStrategy.EXCLUDE subprojects.each { sub -> if (sub.path.startsWith(':NMS:v1')) { try { def reobfTask = sub.tasks.named('reobfJar') dependsOn(reobfTask) from(reobfTask.map { it.outputJar }) { exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' rename { sub.name } into("nms") } return; } catch (Exception ignored) { } } if (sub.path.startsWith(':NMS:v')) { def shadowJarTask = sub.tasks.named("shadowJar") dependsOn(shadowJarTask) from(shadowJarTask.map { it.archiveFile }) { exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' rename { sub.name } into("nms") } } else { from sub.sourceSets.main.output } } def missionsProject = project(':Missions'); missionsProject.subprojects.forEach { sub -> def shadowJarTask = sub.tasks.named("shadowJar") dependsOn(shadowJarTask) from(shadowJarTask.map { it.archiveFile }) { exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' rename { sub.name } into("modules/missions") } } dependencies { // This includes the API and all sub-modules in the final JAR include project(':API') // Use a loop to include all NMS and Hook subprojects automatically subprojects.findAll { it.path.startsWith(':NMS:') || it.path.startsWith(':Hooks:') }.each { sub -> include project(sub.path) } } } tasks.register('cleanTarget', Delete) { delete rootProject.targetFolder } tasks.register('collectArtifacts', Copy) { group = 'build' dependsOn('cleanTarget') dependsOn(tasks.named('shadowJar')) dependsOn(project(':API').tasks.named('shadowJar')) from(tasks.named('shadowJar').map { it.archiveFile }) { rename { rootProject.name + "-" + rootProject.buildVersion + ".jar" } } from(project(':API').tasks.named('shadowJar').map { it.archiveFile }) { rename { rootProject.name + "-API.jar" } } into(rootProject.targetFolder) } tasks.named('build') { dependsOn(tasks.named('shadowJar')) } tasks.named('shadowJar') { finalizedBy('collectArtifacts') } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: gradlew ================================================ #!/usr/bin/env sh # # Copyright 2015 the original author or authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn () { echo "$*" } die () { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin or MSYS, switch paths to Windows format before running java if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=`expr $i + 1` done case $i in 0) set -- ;; 1) set -- "$args0" ;; 2) set -- "$args0" "$args1" ;; 3) set -- "$args0" "$args1" "$args2" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Escape application args save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" exec "$JAVACMD" "$@" ================================================ FILE: gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: settings.gradle ================================================ pluginManagement { repositories { gradlePluginPortal() maven { url "https://repo.papermc.io/repository/maven-public/" } } } rootProject.name = 'SuperiorSkyblock2' include 'API' include 'Hooks' include 'Hooks:AdvancedSlimePaper' include 'Hooks:AdvancedSpawners' include 'Hooks:CandcSilkSpawners' include 'Hooks:ChangeSkin' include 'Hooks:CMI' include 'Hooks:CoreProtect' include 'Hooks:CraftEngine' include 'Hooks:EpicSpawners6' include 'Hooks:EpicSpawners7' include 'Hooks:EpicSpawners8' include 'Hooks:EpicSpawners9' include 'Hooks:Essentials' include 'Hooks:FastAsyncWorldEdit' include 'Hooks:ItemsAdder' include 'Hooks:JetsMinions' include 'Hooks:LuckPerms' include 'Hooks:MergedSpawner' include 'Hooks:MiniMessage' include 'Hooks:MVdWPlaceholderAPI' include 'Hooks:Nexo' include 'Hooks:OpenJdkNashornEngine' include 'Hooks:Oraxen' include 'Hooks:Plan' include 'Hooks:PaperMC' include 'Hooks:PlaceholderAPI' include 'Hooks:ProtocolLib' include 'Hooks:PvpingSpawners' include 'Hooks:RoseStacker' include 'Hooks:SkinsRestorer' include 'Hooks:SkinsRestorer14' include 'Hooks:SkinsRestorer15' include 'Hooks:Slimefun' include 'Hooks:Slimefun:ProtectionModule_RC13' include 'Hooks:Slimefun:ProtectionModule_Dev999' include 'Hooks:SlimeWorldManager' include 'Hooks:SmoothTimber' include 'Hooks:SuperVanish' include 'Hooks:TimbruSilkSpawners' include 'Hooks:UltimateStacker' include 'Hooks:UltimateStacker3' include 'Hooks:UltimateStacker4' include 'Hooks:VanishNoPacket' include 'Hooks:Vault' include 'Hooks:WildStacker' include 'Missions' include 'Missions:BlocksMissions' include 'Missions:BrewingMissions' include 'Missions:CraftingMissions' include 'Missions:EnchantingMissions' include 'Missions:FarmingMissions' include 'Missions:FishingMissions' include 'Missions:IslandMissions' include 'Missions:ItemsMissions' include 'Missions:KillsMissions' include 'Missions:StatisticsMissions' include 'NMS' include 'NMS:Spigot' include 'NMS:Spigot-1_20_3' include 'NMS:Paper' include 'NMS:Paper-1_20_3' include 'NMS:v1_8_R3' include 'NMS:v1_12_R1' include 'NMS:v1_16_R3' include 'NMS:v1_17' include 'NMS:v1_18' include 'NMS:v1_19' include 'NMS:v1_20_3' include 'NMS:v1_20_4' include 'NMS:v1_21' include 'NMS:v1_21_3' include 'NMS:v1_21_4' include 'NMS:v1_21_5' include 'NMS:v1_21_7' include 'NMS:v1_21_9' include 'NMS:v1_21_10' include 'NMS:v26_1' ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java ================================================ package com.bgsoftware.superiorskyblock; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.dependencies.DependenciesManager; import com.bgsoftware.common.nmsloader.INMSLoader; import com.bgsoftware.common.nmsloader.NMSHandlersFactory; import com.bgsoftware.common.nmsloader.NMSLoadException; import com.bgsoftware.common.nmsloader.config.NMSConfiguration; import com.bgsoftware.common.updater.Updater; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.modules.ModuleLoadTime; import com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher; import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandsManagerImpl; import com.bgsoftware.superiorskyblock.commands.admin.AdminCommandsMap; import com.bgsoftware.superiorskyblock.commands.player.PlayerCommandsMap; import com.bgsoftware.superiorskyblock.config.SettingsManagerImpl; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PluginLoadingStage; import com.bgsoftware.superiorskyblock.core.PluginReloadReason; import com.bgsoftware.superiorskyblock.core.database.DataManager; import com.bgsoftware.superiorskyblock.core.engine.EnginesFactory; import com.bgsoftware.superiorskyblock.core.engine.NashornEngineDownloader; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.factory.FactoriesManagerImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls; import com.bgsoftware.superiorskyblock.core.key.KeysManagerImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.MenusManagerImpl; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlocksManagerImpl; import com.bgsoftware.superiorskyblock.core.stackedblocks.container.DefaultStackedBlocksContainer; import com.bgsoftware.superiorskyblock.core.stats.StatsClient; import com.bgsoftware.superiorskyblock.core.task.CalcTask; import com.bgsoftware.superiorskyblock.core.task.ShutdownTask; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.values.BlockValuesManagerImpl; import com.bgsoftware.superiorskyblock.core.values.container.BlockValuesContainer; import com.bgsoftware.superiorskyblock.external.ProvidersManagerImpl; import com.bgsoftware.superiorskyblock.island.GridManagerImpl; import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import com.bgsoftware.superiorskyblock.island.container.DefaultIslandsContainer; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.preview.DefaultIslandPreviews; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.purge.DefaultIslandsPurger; import com.bgsoftware.superiorskyblock.island.role.RolesManagerImpl; import com.bgsoftware.superiorskyblock.island.role.container.DefaultRolesContainer; import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.island.upgrade.UpgradesManagerImpl; import com.bgsoftware.superiorskyblock.island.upgrade.container.DefaultUpgradesContainer; import com.bgsoftware.superiorskyblock.island.upgrade.loaders.PlaceholdersUpgradeCostLoader; import com.bgsoftware.superiorskyblock.island.upgrade.loaders.VaultUpgradeCostLoader; import com.bgsoftware.superiorskyblock.listener.BukkitListeners; import com.bgsoftware.superiorskyblock.mission.MissionsManagerImpl; import com.bgsoftware.superiorskyblock.mission.container.DefaultMissionsContainer; import com.bgsoftware.superiorskyblock.module.ModulesManagerImpl; import com.bgsoftware.superiorskyblock.module.container.DefaultModulesContainer; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; import com.bgsoftware.superiorskyblock.nms.NMSDragonFightChooser; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import com.bgsoftware.superiorskyblock.nms.NMSHolograms; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.nms.NMSWorld; import com.bgsoftware.superiorskyblock.platform.event.GameEventsDispatcher; import com.bgsoftware.superiorskyblock.player.PlayersManagerImpl; import com.bgsoftware.superiorskyblock.player.container.DefaultPlayersContainer; import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import com.bgsoftware.superiorskyblock.player.respawn.RespawnActions; import com.bgsoftware.superiorskyblock.service.ServicesHandler; import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.bgsoftware.superiorskyblock.world.schematic.SchematicsManagerImpl; import com.bgsoftware.superiorskyblock.world.schematic.container.DefaultSchematicsContainer; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.bukkit.plugin.java.JavaPlugin; import java.util.Locale; import java.util.Optional; public class SuperiorSkyblockPlugin extends JavaPlugin implements SuperiorSkyblock { private static SuperiorSkyblockPlugin plugin; /* Managers */ private final DataManager dataHandler = new DataManager(this); private final FactoriesManagerImpl factoriesHandler = new FactoriesManagerImpl(); private final GridManagerImpl gridHandler = new GridManagerImpl(this, new DefaultIslandsPurger(), new DefaultIslandPreviews()); private final StackedBlocksManagerImpl stackedBlocksHandler = new StackedBlocksManagerImpl(this, new DefaultStackedBlocksContainer()); private final BlockValuesManagerImpl blockValuesHandler = new BlockValuesManagerImpl(this, new BlockValuesContainer(), new BlockValuesContainer()); private final SchematicsManagerImpl schematicsHandler = new SchematicsManagerImpl(this, new DefaultSchematicsContainer()); private final PlayersManagerImpl playersHandler = new PlayersManagerImpl(this); private final RolesManagerImpl rolesHandler = new RolesManagerImpl(this, new DefaultRolesContainer()); private final MissionsManagerImpl missionsHandler = new MissionsManagerImpl(this, new DefaultMissionsContainer()); private final MenusManagerImpl menusHandler = new MenusManagerImpl(this); private final KeysManagerImpl keysHandler = new KeysManagerImpl(this); private final ProvidersManagerImpl providersHandler = new ProvidersManagerImpl(this); private final UpgradesManagerImpl upgradesHandler = new UpgradesManagerImpl(this, new DefaultUpgradesContainer()); private final CommandsManagerImpl commandsHandler = new CommandsManagerImpl(this, new PlayerCommandsMap(this), new AdminCommandsMap(this)); private final ModulesManagerImpl modulesHandler = new ModulesManagerImpl(this, new DefaultModulesContainer(this)); private final ServicesHandler servicesHandler = new ServicesHandler(this); private final SettingsManagerImpl settingsHandler = new SettingsManagerImpl(this); /* Global handlers */ private final Updater updater = new Updater(this, "superiorskyblock2"); private final BukkitListeners bukkitListeners = new BukkitListeners(this); private final PluginEventsDispatcher pluginEventsDispatcher = new PluginEventsDispatcher(this); private final GameEventsDispatcher gameEventsDispatcher = new GameEventsDispatcher(this); private IScriptEngine scriptEngine = EnginesFactory.createDefaultEngine(); @Nullable private IEventsDispatcher eventsDispatcher = null; /* NMS */ @Nullable private NMSAlgorithms nmsAlgorithms; private NMSChunks nmsChunks; private NMSDragonFight nmsDragonFight; private NMSEntities nmsEntities; private NMSHolograms nmsHolograms; private NMSPlayers nmsPlayers; private NMSTags nmsTags; private NMSWorld nmsWorld; private PluginLoadingStage loadingStage = PluginLoadingStage.START; public static SuperiorSkyblockPlugin getPlugin() { return plugin; } @Override public void onLoad() { plugin = this; pluginEventsDispatcher.registerDefaultListeners(); DependenciesManager.inject(this); bukkitListeners.registerListenerFailureFilter(); try { SuperiorSkyblockAPI.setPluginInstance(this); } catch (UnsupportedOperationException error) { Log.error("The API instance was already initialized. This can be caused by a reload or another plugin initializing it."); return; } loadingStage = PluginLoadingStage.API_INITIALIZED; String serverVersion = Bukkit.getVersion(); if (serverVersion.toLowerCase(Locale.ENGLISH).contains("arclight")) { Log.error("The plugin does not support this server software: " + serverVersion); return; } loadingStage = PluginLoadingStage.SUPPORTED_SERVER_SOFTWARE; if (!loadNMSAdapter()) { return; } loadingStage = PluginLoadingStage.NMS_INITIALIZED; Runtime.getRuntime().addShutdownHook(new ShutdownTask(this)); IslandPrivileges.registerPrivileges(); SortingTypes.registerSortingTypes(this); IslandFlags.registerFlags(); ClearActions.registerActions(); RespawnActions.registerActions(); IslandCacheKeys.registerCacheKeys(); try { SortingComparators.initializeTopIslandMembersSorting(); } catch (IllegalArgumentException error) { Log.error("The TopIslandMembersSorting was already initialized. This can be caused by a reload or another plugin initializing it."); return; } this.servicesHandler.loadDefaultServices(this); new Metrics(this, 4119); StatsClient client = StatsClient.getInstance(); client.start(); loadingStage = PluginLoadingStage.LOADED; } @Override public void onEnable() { try { if (loadingStage != PluginLoadingStage.LOADED) { ManagerLoadException.handle(new ManagerLoadException("Failed to load " + getDescription().getName() + ".\n" + "Failed on " + loadingStage.next() + "\n\n" + "Shutting down the server...", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN)); return; } loadingStage = PluginLoadingStage.START_ENABLE; BukkitExecutor.init(this); loadUpgradeCostLoaders(); try { settingsHandler.loadData(); } catch (ManagerLoadException ex) { if (!ManagerLoadException.handle(ex)) { return; } } loadingStage = PluginLoadingStage.SETTINGS_INITIALIZED; modulesHandler.loadData(); loadingStage = PluginLoadingStage.MODULES_INITIALIZED; commandsHandler.loadData(); loadingStage = PluginLoadingStage.COMMANDS_INITIALIZED; modulesHandler.runModuleLifecycle(ModuleLoadTime.PLUGIN_INITIALIZE, false); PluginEvent event = PluginEventsFactory.callPluginInitializeEvent(); this.playersHandler.setPlayersContainer(Optional.ofNullable(event.getArgs().playersContainer).orElse(new DefaultPlayersContainer())); this.gridHandler.setIslandsContainer(Optional.ofNullable(event.getArgs().islandsContainer).orElse(new DefaultIslandsContainer(this))); modulesHandler.runModuleLifecycle(ModuleLoadTime.BEFORE_WORLD_CREATION, false); try { providersHandler.getWorldsProvider().prepareWorlds(); } catch (RuntimeException ex) { ManagerLoadException handlerError = new ManagerLoadException(ex, ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); Log.error(handlerError, "An error occurred while preparing worlds:"); Bukkit.shutdown(); return; } loadingStage = PluginLoadingStage.WORLDS_PREPARED; modulesHandler.runModuleLifecycle(ModuleLoadTime.NORMAL, false); try { reloadPlugin(PluginReloadReason.STARTUP); } catch (ManagerLoadException error) { Log.error(error, "An unexpected error occurred while starting up the plugin:"); ManagerLoadException.handle(error); return; } loadingStage = PluginLoadingStage.MANAGERS_INITIALIZED; ChunksProvider.start(); loadingStage = PluginLoadingStage.CHUNKS_PROVIDER_INITIALIZED; // Check for updates asynchronously BukkitExecutor.async(() -> { if (updater.isOutdated()) { Log.info(""); Log.info("A new version is available (v", updater.getLatestVersion(), ")!"); Log.info("Version's description: \"", updater.getVersionDescription(), "\""); Log.info(""); } }); // Calculate the maximum amount of islands that fit into the world. long maxIslands = calculateMaxPossibleIslands(); if (maxIslands < 1000) { Log.warn("It seems like you configured your max-world-size in server.properties to be a small number (", nmsAlgorithms.getMaxWorldSize(), ")."); Log.warn("This can lead to weird behaviors when new islands are generated beyond this limit."); Log.warn("Increase the value to for better experience (Default: 29999984)"); } BukkitExecutor.sync(() -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { for (Player player : Bukkit.getOnlinePlayers()) { SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player); superiorPlayer.updateLastTimeStatus(); Island island = gridHandler.getIslandAt(player.getLocation(wrapper.getHandle())); Island playerIsland = superiorPlayer.getIsland(); if (superiorPlayer.hasIslandFlyEnabled()) { if (island != null && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { player.setAllowFlight(true); player.setFlying(true); } else { superiorPlayer.toggleIslandFly(); } } if (playerIsland != null) playerIsland.setCurrentlyActive(true); if (island != null) island.setPlayerInside(superiorPlayer, true); } } }, 1L); PluginEventsFactory.callPluginInitializedEvent(); loadingStage = PluginLoadingStage.ENABLED; PluginEventsFactory.callSettingsUpdateEvent(); } catch (Throwable error) { Log.error(error, "An unexpected error occurred while enabling the plugin:"); Bukkit.shutdown(); } } @Override public void onDisable() { try { if (loadingStage.isAtLeast(PluginLoadingStage.START_ENABLE)) BukkitExecutor.prepareShutdown(); if (loadingStage.isAtLeast(PluginLoadingStage.CHUNKS_PROVIDER_INITIALIZED)) ChunksProvider.stop(); if (loadingStage.isAtLeast(PluginLoadingStage.MANAGERS_INITIALIZED)) { dataHandler.saveDatabase(false); gridHandler.disablePlugin(); for (Island island : gridHandler.getIslandsToPurge()) island.disbandIsland(); playersHandler.savePlayers(); gridHandler.saveIslands(); } if (loadingStage.isAtLeast(PluginLoadingStage.MODULES_INITIALIZED)) { modulesHandler.getModules().forEach(modulesHandler::unregisterModule); } // Shutdown task is running from another thread, causing closing of inventories to cause errors. // This check should prevent it. if (Bukkit.isPrimaryThread()) { Bukkit.getOnlinePlayers().forEach(player -> { SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player); player.closeInventory(); superiorPlayer.updateWorldBorder(null); if (superiorPlayer.hasIslandFlyEnabled()) { player.setAllowFlight(false); player.setFlying(false); } }); } } catch (Exception error) { Log.error(error, "An unexpected error occurred while disabling the plugin:"); } finally { Log.info("Shutting down stats client..."); StatsClient.getIfExists().ifPresent(StatsClient::shutdown); if (loadingStage.isAtLeast(PluginLoadingStage.MANAGERS_INITIALIZED)) { Log.info("Shutting down calculation task..."); CalcTask.cancelTask(); } if (loadingStage.isAtLeast(PluginLoadingStage.NMS_INITIALIZED)) nmsChunks.shutdown(); if (loadingStage.isAtLeast(PluginLoadingStage.START_ENABLE)) { Log.info("Shutting down executor"); BukkitExecutor.close(plugin); } if (loadingStage.isAtLeast(PluginLoadingStage.MANAGERS_INITIALIZED)) { Log.info("Closing database. This may hang the server. Do not shut it down, or data may get lost."); dataHandler.closeConnection(); } } } @Override public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { return WorldGenerator.getWorldGenerator(settingsHandler.getWorlds().getDefaultWorldDimension()); } public Updater getUpdater() { return updater; } public ClassLoader getPluginClassLoader() { return super.getClassLoader(); } private boolean loadNMSAdapter() { try { INMSLoader nmsLoader = NMSHandlersFactory.createNMSLoader(this, NMSConfiguration.forPlugin(this)); this.nmsAlgorithms = nmsLoader.loadNMSHandler(NMSAlgorithms.class); this.nmsChunks = nmsLoader.loadNMSHandler(NMSChunks.class); this.nmsEntities = nmsLoader.loadNMSHandler(NMSEntities.class); this.nmsHolograms = nmsLoader.loadNMSHandler(NMSHolograms.class); this.nmsPlayers = nmsLoader.loadNMSHandler(NMSPlayers.class); this.nmsTags = nmsLoader.loadNMSHandler(NMSTags.class); this.nmsWorld = nmsLoader.loadNMSHandler(NMSWorld.class); this.nmsDragonFight = new NMSDragonFightChooser(plugin, () -> nmsLoader.loadNMSHandler(NMSDragonFight.class)); return true; } catch (NMSLoadException error) { new ManagerLoadException(error, "The plugin doesn't support your minecraft version.\n" + "Please try a different version.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN).printStackTrace(); return false; } } private boolean checkScriptEngine() { return testScriptEngine() || (NashornEngineDownloader.downloadEngine(this) && testScriptEngine()); } private boolean testScriptEngine() { try { scriptEngine.eval("1+1"); return true; } catch (Exception ex) { return false; } } public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadException { if (reloadReason == PluginReloadReason.COMMAND) { bukkitListeners.unregisterListeners(); } providersHandler.loadData(); ItemSkulls.readTextures(this); if (reloadReason == PluginReloadReason.COMMAND) { // The reload was requested by a command. We want to reload the commands, settings and call the // module lifecycles that are not called regularly. If the reload was due to a startup, then // all of that is called already in the onEnable callback of the plugin. settingsHandler.loadData(); commandsHandler.loadData(); modulesHandler.runModuleLifecycle(ModuleLoadTime.PLUGIN_INITIALIZE, true); modulesHandler.runModuleLifecycle(ModuleLoadTime.BEFORE_WORLD_CREATION, true); modulesHandler.runModuleLifecycle(ModuleLoadTime.NORMAL, true); } if (!checkScriptEngine()) { 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); } blockValuesHandler.loadData(); upgradesHandler.loadData(); rolesHandler.loadData(); Message.reload(); if (reloadReason == PluginReloadReason.STARTUP) { playersHandler.loadData(); gridHandler.loadData(); schematicsHandler.loadData(); } else { BukkitExecutor.sync(gridHandler::updateSpawn, 1L); gridHandler.syncUpgrades(); schematicsHandler.loadSchematics(); } menusHandler.loadData(); missionsHandler.loadData(); if (reloadReason == PluginReloadReason.STARTUP) { dataHandler.loadData(); stackedBlocksHandler.loadData(); } BukkitExecutor.sync(schematicsHandler::cacheSchematics); modulesHandler.runModuleLifecycle(ModuleLoadTime.AFTER_MODULE_DATA_LOAD, reloadReason == PluginReloadReason.COMMAND); BukkitExecutor.sync(() -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { for (Player player : Bukkit.getOnlinePlayers()) { SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player); Island island = gridHandler.getIslandAt(player.getLocation(wrapper.getHandle())); superiorPlayer.updateWorldBorder(island); if (island != null) island.applyEffects(superiorPlayer); } } }); CalcTask.startTask(); modulesHandler.runModuleLifecycle(ModuleLoadTime.AFTER_HANDLERS_LOADING, reloadReason == PluginReloadReason.COMMAND); if (reloadReason == PluginReloadReason.STARTUP) { modulesHandler.loadModulesData(this); } try { bukkitListeners.registerListeners(); } catch (RuntimeException ex) { throw new ManagerLoadException("Cannot load plugin due to a missing event: " + ex.getMessage() + " - contact @Ome_R!", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } } @Override public GridManagerImpl getGrid() { return gridHandler; } @Override public StackedBlocksManagerImpl getStackedBlocks() { return stackedBlocksHandler; } @Override public BlockValuesManagerImpl getBlockValues() { return blockValuesHandler; } @Override public SchematicsManagerImpl getSchematics() { return schematicsHandler; } @Override public PlayersManagerImpl getPlayers() { return playersHandler; } @Override public RolesManagerImpl getRoles() { return rolesHandler; } @Override public MissionsManagerImpl getMissions() { return missionsHandler; } @Override public MenusManagerImpl getMenus() { return menusHandler; } @Override public KeysManagerImpl getKeys() { return keysHandler; } @Override public ProvidersManagerImpl getProviders() { return providersHandler; } @Override public UpgradesManagerImpl getUpgrades() { return upgradesHandler; } @Override public CommandsManagerImpl getCommands() { return commandsHandler; } @Override public SettingsManagerImpl getSettings() { return settingsHandler; } @Override public FactoriesManagerImpl getFactory() { return factoriesHandler; } @Override public ModulesManagerImpl getModules() { return modulesHandler; } @Override public IScriptEngine getScriptEngine() { return scriptEngine; } @Override public void setScriptEngine(@Nullable IScriptEngine scriptEngine) { this.scriptEngine = scriptEngine == null ? EnginesFactory.createDefaultEngine() : scriptEngine; } @Nullable @Override public IEventsDispatcher getEventsDispatcher() { return this.eventsDispatcher; } @Override public void setEventsDispatcher(@Nullable IEventsDispatcher eventsDispatcher) { this.eventsDispatcher = eventsDispatcher; } public PluginEventsDispatcher getPluginEventsDispatcher() { return pluginEventsDispatcher; } public GameEventsDispatcher getGameEventsDispatcher() { return gameEventsDispatcher; } public ServicesHandler getServices() { return servicesHandler; } public NMSAlgorithms getNMSAlgorithms() { return nmsAlgorithms; } public NMSChunks getNMSChunks() { return nmsChunks; } public NMSDragonFight getNMSDragonFight() { return nmsDragonFight; } public NMSEntities getNMSEntities() { return nmsEntities; } public NMSHolograms getNMSHolograms() { return nmsHolograms; } public NMSPlayers getNMSPlayers() { return nmsPlayers; } public NMSTags getNMSTags() { return nmsTags; } public NMSWorld getNMSWorld() { return nmsWorld; } public String getFileName() { return getFile().getName(); } private void loadUpgradeCostLoaders() { upgradesHandler.registerUpgradeCostLoader("money", new VaultUpgradeCostLoader()); upgradesHandler.registerUpgradeCostLoader("placeholders", new PlaceholdersUpgradeCostLoader()); } private long calculateMaxPossibleIslands() { int islandDistance = settingsHandler.getMaxIslandSize() * 3; long worldDistance = nmsAlgorithms.getMaxWorldSize() * 2L; long islandsPerSide = worldDistance / islandDistance; return islandsPerSide * islandsPerSide; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java ================================================ package com.bgsoftware.superiorskyblock.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffectType; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.IntStream; import java.util.stream.Stream; public class CommandTabCompletes { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private CommandTabCompletes() { } public static List getPlayerIslandsExceptSender(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument, boolean hideVanish) { return getPlayerIslandsExceptSender(plugin, sender, argument, hideVanish, (onlinePlayer, onlineIsland) -> true); } public static List getPlayerIslandsExceptSender(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument, boolean hideVanish, BiPredicate islandPredicate) { SuperiorPlayer superiorPlayer = sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null; Island island = superiorPlayer == null ? null : superiorPlayer.getIsland(); return getOnlinePlayersAndIslands(plugin, argument, hideVanish, (onlinePlayer, onlineIsland) -> onlineIsland != null && (superiorPlayer == null || island == null || !island.equals(onlineIsland)) && islandPredicate.test(onlinePlayer, onlineIsland)); } public static List getIslandMembersWithLowerRole(Island island, String argument, PlayerRole maxRole) { return getIslandMembers(island, argument, islandMember -> islandMember.getPlayerRole().isLessThan(maxRole)); } public static List getIslandMembers(Island island, String argument, Predicate predicate) { return getPlayers(island.getIslandMembers(false), argument, predicate); } public static List getIslandMembers(Island island, String argument) { return getPlayers(island.getIslandMembers(false), argument); } public static List getOnlinePlayersWithIsland(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanished, Predicate predicate) { return getOnlinePlayers(plugin, argument, hideVanished, (onlinePlayer) -> onlinePlayer != null && onlinePlayer.hasIsland() && predicate.test(onlinePlayer)); } public static List getOnlinePlayers(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanish) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(onlinePlayer -> (!hideVanish || onlinePlayer.isShownAsOnline()) && onlinePlayer.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(getOnlineSuperiorPlayers(plugin), SuperiorPlayer::getName); } public static List getOnlinePlayers(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanish, Predicate predicate) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(onlinePlayer -> (!hideVanish || onlinePlayer.isShownAsOnline()) && predicate.test(onlinePlayer) && onlinePlayer.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(getOnlineSuperiorPlayers(plugin), SuperiorPlayer::getName); } public static List getOnlinePlayersAndIslands(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanish, @Nullable BiPredicate predicate) { List tabArguments = new LinkedList<>(); String lowerArgument = argument.toLowerCase(Locale.ENGLISH); for (Player player : Bukkit.getOnlinePlayers()) { SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(player); if (!hideVanish || onlinePlayer.isShownAsOnline()) { Island onlineIsland = onlinePlayer.getIsland(); if (onlineIsland != null && (predicate == null || predicate.test(onlinePlayer, onlineIsland))) { if (onlinePlayer.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) tabArguments.add(onlinePlayer.getName()); if (onlineIsland.getStrippedName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) tabArguments.add(onlineIsland.getStrippedName()); } } } return Collections.unmodifiableList(tabArguments); } public static List getIslandWarps(Island island, String argument) { return filterByArgument(island.getIslandWarps().keySet(), argument.toLowerCase(Locale.ENGLISH)); } public static List getIslandVisitors(Island island, String argument, boolean hideVanish) { return getPlayers(island.getIslandVisitors(!hideVanish), argument); } public static List getCustomComplete(String argument, String... tabVariables) { return getCustomComplete(argument, Arrays.asList(tabVariables)); } public static List getCustomComplete(String argument, Collection tabVariables) { return filterByArgument(tabVariables, argument.toLowerCase(Locale.ENGLISH)); } public static List getCustomComplete(String argument, Predicate predicate, String... tabVariables) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(var -> var.contains(lowerArgument) && predicate.test(var)) .build(Arrays.asList(tabVariables)); } public static List getCustomComplete(String argument, IntStream tabVariables) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(var -> var.contains(lowerArgument)) .build(Stream.of(tabVariables).map(i -> i + "")); } public static List getSchematics(SuperiorSkyblockPlugin plugin, String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(schematic -> !schematic.endsWith("_nether") && !schematic.endsWith("_normal") && !schematic.endsWith("_the_end") && schematic.toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .build(plugin.getSchematics().getSchematics()); } public static List getIslandBannedPlayers(Island island, String argument) { return getPlayers(island.getBannedPlayers(), argument); } public static List getUpgrades(SuperiorSkyblockPlugin plugin, String argument) { return filterByArgument(plugin.getUpgrades().getUpgrades(), Upgrade::getName, argument.toLowerCase(Locale.ENGLISH)); } public static List getPlayerRoles(SuperiorSkyblockPlugin plugin, String argument, Predicate predicate) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(playerRole -> (predicate == null || predicate.test(playerRole)) && playerRole.toString().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(plugin.getRoles().getRoles(), PlayerRole::getName); } public static List getMaterials(String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder().build(Materials.getBlocksNonLegacy().stream() .filter(material -> material.isBlock() && !Materials.isLegacy(material)) .map(material -> material.name().toLowerCase(Locale.ENGLISH)) .filter(materialName -> materialName.contains(lowerArgument))); } public static List getPotionEffects(String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(potionEffectType -> { try { return potionEffectType != null && potionEffectType.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument); } catch (Exception ex) { return false; } }) .map(PotionEffectType.values(), potionEffectType -> { String name = potionEffectType.getName(); if (name.startsWith("minecraft:")) { name = name.substring("minecraft:".length()).toLowerCase(Locale.ENGLISH); } else { name = name.toLowerCase(Locale.ENGLISH); } return name; }); } public static List getEntitiesForLimit(String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder().build(Stream.of(EntityType.values()) .filter(BukkitEntities::canHaveLimit) .map(entityType -> entityType.name().toLowerCase(Locale.ENGLISH)) .filter(entityTypeName -> entityTypeName.contains(lowerArgument))); } public static List getMaterialsForGenerators(String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder().build(Materials.getSolids().stream() .map(material -> material.name().toLowerCase(Locale.ENGLISH)) .filter(materialName -> materialName.contains(lowerArgument))); } public static List getMissions(SuperiorSkyblockPlugin plugin, String argument, Predicate> predicate) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder().build(plugin.getMissions().getAllMissions().stream() .filter(mission -> predicate.test(mission) && mission.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(mission -> mission.getName().toLowerCase(Locale.ENGLISH))); } public static List getMissionCategories(SuperiorSkyblockPlugin plugin, String argument, Predicate predicate) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder().build(plugin.getMissions().getMissionCategories().stream() .filter(category -> predicate.test(category) && category.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(category -> category.getName().toLowerCase(Locale.ENGLISH))); } public static List getCustomMenus(SuperiorSkyblockPlugin plugin, String argument) { return filterByArgument(plugin.getMenus().getCustomMenus().values(), menu -> menu.getIdentifier().substring(MenuIdentifiers.MENU_CUSTOM_PREFIX.length()), argument.toLowerCase(Locale.ENGLISH)); } public static List getBiomes(String argument) { NMSAlgorithms.EnumBridge biomeEnumBridge = plugin.getNMSAlgorithms().getBiomeBridge(); return filterByArgument(biomeEnumBridge.getValues(), biomeEnumBridge::getName, argument.toLowerCase(Locale.ENGLISH)); } public static List getWorlds(String argument) { return filterByArgument(Bukkit.getWorlds(), World::getName, argument.toLowerCase(Locale.ENGLISH)); } public static List getIslandPrivileges(String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(name -> name.contains(lowerArgument)) .build(IslandPrivilege.values(), islandPrivilege -> islandPrivilege.getName().toLowerCase(Locale.ENGLISH)); } public static List getRatedPlayers(SuperiorSkyblockPlugin plugin, Island island, String argument) { return filterByArgument(island.getRatings().keySet(), playerUUID -> plugin.getPlayers().getSuperiorPlayer(playerUUID).getName(), argument.toLowerCase(Locale.ENGLISH)); } public static List getRatings(String argument) { return getFromEnum(Arrays.asList(Rating.values()), argument.toLowerCase(Locale.ENGLISH)); } public static List getIslandFlags(String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(name -> name.contains(lowerArgument)) .build(IslandFlag.values(), islandFlag -> islandFlag.getName().toLowerCase(Locale.ENGLISH)); } public static List getDimensions(SuperiorSkyblockPlugin plugin, String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder().build(Dimension.values().stream() .filter(dimension -> plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && dimension.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(dimension -> dimension.getName().toLowerCase(Locale.ENGLISH))); } public static List getBorderColors(String argument) { return getFromEnum(Arrays.asList(BorderColor.values()), argument.toLowerCase(Locale.ENGLISH)); } public static List getModules(SuperiorSkyblockPlugin plugin, String argument) { return filterByArgument(plugin.getModules().getModules(), PluginModule::getName, argument.toLowerCase(Locale.ENGLISH)); } private static List getPlayers(Collection players, String argument) { return filterByArgument(players, SuperiorPlayer::getName, argument.toLowerCase(Locale.ENGLISH)); } private static List getPlayers(Collection players, String argument, Predicate predicate) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(player -> predicate.test(player) && player.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(players, SuperiorPlayer::getName); } private static List getOnlineSuperiorPlayers(SuperiorSkyblockPlugin plugin) { return new SequentialListBuilder() .mutable() .build(Bukkit.getOnlinePlayers(), player -> plugin.getPlayers().getSuperiorPlayer(player)); } private static List filterByArgument(Collection collection, String argument) { return new SequentialListBuilder() .filter(name -> name.toLowerCase(Locale.ENGLISH).contains(argument)) .build(collection); } private static List filterByArgument(Collection collection, Function mapper, String argument) { return new SequentialListBuilder() .filter(name -> name.toLowerCase(Locale.ENGLISH).contains(argument)) .build(collection, mapper); } private static List filterByArgument(E[] collection, Function mapper, String argument) { return new SequentialListBuilder() .filter(name -> name.toLowerCase(Locale.ENGLISH).contains(argument)) .build(collection, mapper); } private static List getFromEnum(Collection> enums, String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() .filter(name -> name.contains(lowerArgument)) .build(enums, enumElement -> enumElement.name().toLowerCase(Locale.ENGLISH)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsHelper.java ================================================ package com.bgsoftware.superiorskyblock.commands; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.core.Text; import org.bukkit.command.CommandSender; public class CommandsHelper { private CommandsHelper() { } public static boolean shouldDisplayCommandForPlayer(SuperiorCommand superiorCommand, CommandSender executor) { return superiorCommand.displayCommand() && hasCommandAccess(superiorCommand, executor); } public static boolean hasCommandAccess(SuperiorCommand superiorCommand, CommandSender executor) { String permission = superiorCommand.getPermission(); return Text.isBlank(permission) || executor.hasPermission(permission); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.handlers.CommandsManager; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.FileClassLoader; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.io.JarFiles; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.entity.Player; import java.io.File; import java.lang.reflect.Constructor; import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; public class CommandsManagerImpl extends Manager implements CommandsManager { private final Map> commandsCooldown = new HashMap<>(); private final CommandsMap playerCommandsMap; private final CommandsMap adminCommandsMap; private Set pendingCommands = new HashSet<>(); private PluginCommand pluginCommand; private String label = null; public CommandsManagerImpl(SuperiorSkyblockPlugin plugin, CommandsMap playerCommandsMap, CommandsMap adminCommandsMap) { super(plugin); this.playerCommandsMap = playerCommandsMap; this.adminCommandsMap = adminCommandsMap; } @Override public void loadData() { String islandCommand = plugin.getSettings().getIslandCommand(); label = islandCommand.split(",")[0]; pluginCommand = new PluginCommand(label); String[] commandSections = islandCommand.split(","); if (commandSections.length > 1) { pluginCommand.setAliases(Arrays.asList(Arrays.copyOfRange(commandSections, 1, commandSections.length))); } plugin.getNMSAlgorithms().registerCommand(pluginCommand); playerCommandsMap.loadDefaultCommands(); adminCommandsMap.loadDefaultCommands(); loadCommands(); if (this.pendingCommands != null) { Set pendingCommands = new HashSet<>(this.pendingCommands); this.pendingCommands = null; pendingCommands.forEach(Runnable::run); } } @Override public void registerCommand(SuperiorCommand superiorCommand) { Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); if (pendingCommands != null) { pendingCommands.add(() -> registerCommand(superiorCommand)); return; } playerCommandsMap.registerCommand(superiorCommand); } @Override public void unregisterCommand(SuperiorCommand superiorCommand) { playerCommandsMap.unregisterCommand(superiorCommand); } @Override public void registerAdminCommand(SuperiorCommand superiorCommand) { if (pendingCommands != null) { pendingCommands.add(() -> registerAdminCommand(superiorCommand)); return; } Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); adminCommandsMap.registerCommand(superiorCommand); } @Override public void unregisterAdminCommand(SuperiorCommand superiorCommand) { Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); adminCommandsMap.unregisterCommand(superiorCommand); } @Override public List getSubCommands() { return getSubCommands(false); } @Override public List getSubCommands(boolean includeDisabled) { return playerCommandsMap.getSubCommands(includeDisabled); } @Nullable @Override public SuperiorCommand getCommand(String commandLabel) { return playerCommandsMap.getCommand(commandLabel); } @Override public List getAdminSubCommands() { return adminCommandsMap.getSubCommands(true); } @Nullable @Override public SuperiorCommand getAdminCommand(String commandLabel) { return adminCommandsMap.getCommand(commandLabel); } @Override public void dispatchSubCommand(CommandSender sender, String subCommand) { dispatchSubCommand(sender, subCommand, null); } @Override public void dispatchSubCommand(CommandSender sender, String subCommand, @Nullable String args) { // We first check that the sub command is enabled. if (getCommand(subCommand) == null) { Bukkit.dispatchCommand(sender, this.label + " " + subCommand + (args == null ? "" : " " + args)); return; } String[] argsSplit = args == null ? null : args.split(" "); String[] commandArguments; if (argsSplit == null || (argsSplit.length == 1 && argsSplit[0].isEmpty())) { commandArguments = new String[1]; commandArguments[0] = subCommand; } else { commandArguments = new String[argsSplit.length + 1]; commandArguments[0] = subCommand; System.arraycopy(argsSplit, 0, commandArguments, 1, argsSplit.length); } pluginCommand.execute(sender, "", commandArguments); } public String getLabel() { return label; } @SuppressWarnings("ResultOfMethodCallIgnored") private void loadCommands() { File commandsFolder = new File(plugin.getDataFolder(), "commands"); if (!commandsFolder.exists()) { commandsFolder.mkdirs(); return; } List folderFiles = Files.listFolderFiles(commandsFolder, false, file -> file.getName().endsWith(".jar")); if (folderFiles.isEmpty()) return; try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(commandsFolder)) { for (File file : folderFiles) { try { String fileName = file.getName(); file = filesLookup.getFile(fileName); FileClassLoader classLoader = new FileClassLoader(file, plugin.getPluginClassLoader(), plugin.getNMSAlgorithms().getClassProcessor()); //noinspection deprecation Class commandClass = JarFiles.getClass(file.toURL(), SuperiorCommand.class, classLoader).getLeft(); if (commandClass == null) continue; SuperiorCommand superiorCommand = createInstance(commandClass); if (file.getName().toLowerCase(Locale.ENGLISH).contains("admin")) { registerAdminCommand(superiorCommand); Log.info("Successfully loaded external admin command: ", file.getName().split("\\.")[0]); } else { registerCommand(superiorCommand); Log.info("Successfully loaded external command: ", file.getName().split("\\.")[0]); } } catch (Exception error) { Log.error(error, "An unexpected error occurred while loading an external command ", file.getName(), ":"); } } } } private SuperiorCommand createInstance(Class clazz) throws Exception { Preconditions.checkArgument(SuperiorCommand.class.isAssignableFrom(clazz), "Class " + clazz + " is not a SuperiorCommand."); for (Constructor constructor : clazz.getConstructors()) { if (constructor.getParameterCount() == 0) { if (!constructor.isAccessible()) constructor.setAccessible(true); return (SuperiorCommand) constructor.newInstance(); } } throw new IllegalArgumentException("Class " + clazz + " has no valid constructors."); } private class PluginCommand extends BukkitCommand { PluginCommand(String islandCommandLabel) { super(islandCommandLabel); } @Override public boolean execute(CommandSender sender, String label, String[] args) { java.util.Locale locale = PlayerLocales.getLocale(sender); String executedSubCommand; if (args.length > 0) { executedSubCommand = args[0]; Log.debug(Debug.EXECUTE_COMMAND, sender.getName(), executedSubCommand); SuperiorCommand command = playerCommandsMap.getCommand(executedSubCommand); if (command != null) { if (!(sender instanceof Player) && !command.canBeExecutedByConsole()) { Message.CUSTOM.send(sender, "&cCan be executed only by players!", true); return false; } if (!CommandsHelper.hasCommandAccess(command, sender)) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Missing Permission", command.getPermission()); if (!plugin.getSettings().isHelpOnNoPermission()) Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission()); else if (!"help".equalsIgnoreCase(executedSubCommand)) dispatchSubCommand(sender, "help"); return false; } if (args.length < command.getMinArgs() || args.length > command.getMaxArgs()) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Incorrect Usage", command.getUsage(locale)); Message.COMMAND_USAGE.send(sender, locale, getLabel() + " " + command.getUsage(locale)); return false; } if (sender instanceof Player) { UUID uuid = ((Player) sender).getUniqueId(); SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); if (!superiorPlayer.hasPermission("superior.admin.bypass.cooldowns")) { Pair commandCooldown = getCooldown(command); if (commandCooldown != null) { String commandLabel = command.getAliases().get(0); Map playerCooldowns = commandsCooldown.get(uuid); long timeNow = System.currentTimeMillis(); if (playerCooldowns != null) { Long timeToExecute = playerCooldowns.get(commandLabel); if (timeToExecute != null) { if (timeNow < timeToExecute) { String formattedTime = Formatters.TIME_FORMATTER.format(Duration.ofMillis(timeToExecute - timeNow), locale); Log.debugResult(Debug.EXECUTE_COMMAND, "Return Cooldown", formattedTime); Message.COMMAND_COOLDOWN_FORMAT.send(sender, locale, formattedTime); return false; } } } commandsCooldown.computeIfAbsent(uuid, u -> new HashMap<>()).put(commandLabel, timeNow + commandCooldown.getKey()); } } } command.execute(plugin, sender, args); return false; } if (!plugin.getSettings().isHelpOnInvalidCommand()) Message.INVALID_COMMAND.send(sender, locale, executedSubCommand); else if (!"help".equalsIgnoreCase(executedSubCommand)) dispatchSubCommand(sender, "help"); return false; } if (sender instanceof Player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (superiorPlayer != null) { String subCommandToExecute; if (!superiorPlayer.hasIsland()) subCommandToExecute = "create"; else if (superiorPlayer.hasToggledPanel()) subCommandToExecute = "panel"; else subCommandToExecute = "tp"; dispatchSubCommand(sender, subCommandToExecute); return false; } } return false; } @Override public List tabComplete(CommandSender sender, String label, String[] args) { if (args.length > 0) { SuperiorCommand command = playerCommandsMap.getCommand(args[0]); if (command != null) { return CommandsHelper.shouldDisplayCommandForPlayer(command, sender) ? command.tabComplete(plugin, sender, args) : Collections.emptyList(); } } List list = new LinkedList<>(); for (SuperiorCommand subCommand : getSubCommands()) { if (CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) { List aliases = new LinkedList<>(subCommand.getAliases()); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(aliases.get(0).toLowerCase(Locale.ENGLISH), Collections.emptyList())); for (String alias : aliases) { if (alias.contains(args[0].toLowerCase(Locale.ENGLISH))) { list.add(alias); } } } } return list; } } @Nullable private Pair getCooldown(SuperiorCommand command) { for (String alias : command.getAliases()) { Pair commandCooldown = plugin.getSettings().getCommandsCooldown().get(alias); if (commandCooldown != null) return commandCooldown; } return null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java ================================================ package com.bgsoftware.superiorskyblock.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.google.common.base.Preconditions; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TreeMap; public abstract class CommandsMap { private static Set DISABLED_COMMANDS_CACHE; private static void onSettingsUpdate() { DISABLED_COMMANDS_CACHE = new HashSet<>(); SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); plugin.getSettings().getDisabledCommands().forEach(commandLabel -> { SuperiorCommand superiorCommand = plugin.getCommands().getCommand(commandLabel); if (superiorCommand != null && !(superiorCommand instanceof IAdminIslandCommand)) DISABLED_COMMANDS_CACHE.add(superiorCommand.getAliases().get(0).toLowerCase(Locale.ENGLISH)); }); } public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CommandsMap::onSettingsUpdate); } private final Map subCommands = new TreeMap<>(); private final Map> aliasesToCommand = new HashMap<>(); protected final SuperiorSkyblockPlugin plugin; protected CommandsMap(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } public abstract void loadDefaultCommands(); public void registerCommand(SuperiorCommand superiorCommand) { List aliases = new LinkedList<>(superiorCommand.getAliases()); String label = aliases.remove(0).toLowerCase(Locale.ENGLISH); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList())); removeCommand(label); subCommands.put(label, superiorCommand); for (String alias : aliases) { aliasesToCommand.computeIfAbsent(alias.toLowerCase(Locale.ENGLISH), a -> new LinkedList<>()).add(superiorCommand); } PluginEventsFactory.callCommandsUpdateEvent(); } public void unregisterCommand(SuperiorCommand superiorCommand) { Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); List aliases = new LinkedList<>(superiorCommand.getAliases()); String label = aliases.remove(0).toLowerCase(Locale.ENGLISH); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList())); removeCommand(label); PluginEventsFactory.callCommandsUpdateEvent(); } @Nullable public SuperiorCommand getCommand(String label) { label = label.toLowerCase(Locale.ENGLISH); SuperiorCommand superiorCommand = subCommands.get(label); if (superiorCommand != null && isCommandEnabled(superiorCommand)) return superiorCommand; List commandAliases = aliasesToCommand.getOrDefault(label, Collections.emptyList()); for (SuperiorCommand commandAlias : commandAliases) { if (isCommandEnabled(commandAlias)) { return commandAlias; } } return null; } public List getSubCommands(boolean includeDisabled) { SequentialListBuilder listBuilder = new SequentialListBuilder<>(); if (!includeDisabled) listBuilder.filter(this::isCommandEnabled); return listBuilder.build(this.subCommands.values()); } protected void clearCommands() { this.subCommands.clear(); this.aliasesToCommand.clear(); } private boolean isCommandEnabled(SuperiorCommand superiorCommand) { return superiorCommand instanceof IAdminIslandCommand || !DISABLED_COMMANDS_CACHE.contains(superiorCommand.getAliases().get(0).toLowerCase(Locale.ENGLISH)); } private void removeCommand(String label) { if (subCommands.remove(label) != null) { aliasesToCommand.values().forEach(commandsList -> commandsList.removeIf(sC -> sC.getAliases().get(0).equalsIgnoreCase(label))); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/IAdminIslandCommand.java ================================================ package com.bgsoftware.superiorskyblock.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.commands.arguments.IslandsListArgument; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.LinkedList; import java.util.List; public interface IAdminIslandCommand extends ISuperiorCommand { @Override default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { if (!supportMultipleIslands()) { IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[2]); if (arguments.getIsland() != null) execute(plugin, sender, arguments.getSuperiorPlayer(), arguments.getIsland(), args); } else { IslandsListArgument arguments = CommandArguments.getMultipleIslands(plugin, sender, args[2]); if (!arguments.getIslands().isEmpty()) execute(plugin, sender, arguments.getSuperiorPlayer(), arguments.getIslands(), args); } } @Override default List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { List tabVariables = new LinkedList<>(); if (args.length == 3) { if (supportMultipleIslands() && "*".contains(args[2])) tabVariables.add("*"); tabVariables.addAll(CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false, null)); } else if (args.length > 3) { if (supportMultipleIslands()) { tabVariables = adminTabComplete(plugin, sender, null, args); } else { SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[2]); Island island = targetPlayer == null ? plugin.getGrid().getIsland(args[2]) : targetPlayer.getIsland(); if (island != null) { tabVariables = adminTabComplete(plugin, sender, island, args); if (tabVariables.isEmpty()) tabVariables = adminTabComplete(plugin, sender, island, args); } } } return tabVariables == null ? Collections.emptyList() : Collections.unmodifiableList(tabVariables); } boolean supportMultipleIslands(); default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { // Not all commands should implement this method. } default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { // Not all commands should implement this method. } default List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/IAdminPlayerCommand.java ================================================ package com.bgsoftware.superiorskyblock.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; public interface IAdminPlayerCommand extends ISuperiorCommand { @Override default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { if (!supportMultiplePlayers()) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[2]); if (targetPlayer != null) { Island playerIsland = targetPlayer.getIsland(); if (requireIsland() && playerIsland == null) { Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName()); return; } execute(plugin, sender, targetPlayer, args); } } else { List players = CommandArguments.getMultiplePlayers(plugin, sender, args[2]); if (!players.isEmpty()) execute(plugin, sender, players, args); } } @Override default List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { List tabVariables = new LinkedList<>(); if (args.length == 3) { if (supportMultiplePlayers() && "*".contains(args[2])) tabVariables.add("*"); tabVariables.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[2], false)); } else if (args.length > 3) { if (supportMultiplePlayers()) { tabVariables = adminTabComplete(plugin, sender, null, args); } else { SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[2]); if (targetPlayer != null) { tabVariables = adminTabComplete(plugin, sender, targetPlayer, args); } } } return Collections.unmodifiableList(tabVariables); } boolean supportMultiplePlayers(); default boolean requireIsland() { return false; } default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { // Not all commands should implement this method. } default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, List targetPlayers, String[] args) { // Not all commands should implement this method. } default List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/IPermissibleCommand.java ================================================ package com.bgsoftware.superiorskyblock.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public interface IPermissibleCommand extends ISuperiorCommand { @Override default void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Island island = null; SuperiorPlayer superiorPlayer = null; if (!canBeExecutedByConsole() || sender instanceof Player) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); island = arguments.getIsland(); if (island == null) return; superiorPlayer = arguments.getSuperiorPlayer(); if (!superiorPlayer.hasPermission(getPrivilege())) { getPermissionLackMessage().send(superiorPlayer, island.getRequiredPlayerRole(getPrivilege())); return; } } execute(plugin, superiorPlayer, island, args); } @Override default List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Island island = null; SuperiorPlayer superiorPlayer = null; if (!canBeExecutedByConsole() || sender instanceof Player) { superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); island = superiorPlayer.getIsland(); } return superiorPlayer == null || (island != null && superiorPlayer.hasPermission(getPrivilege())) ? tabComplete(plugin, superiorPlayer, island, args) : Collections.emptyList(); } IslandPrivilege getPrivilege(); Message getPermissionLackMessage(); void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args); default List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/ISuperiorCommand.java ================================================ package com.bgsoftware.superiorskyblock.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import org.bukkit.command.CommandSender; import java.util.List; public interface ISuperiorCommand extends SuperiorCommand { @Override default boolean displayCommand() { return true; } default void execute(SuperiorSkyblock plugin, CommandSender sender, String[] args) { execute((SuperiorSkyblockPlugin) plugin, sender, args); } default List tabComplete(SuperiorSkyblock plugin, CommandSender sender, String[] args) { return tabComplete((SuperiorSkyblockPlugin) plugin, sender, args); } void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args); List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.commands.CommandsMap; public class AdminCommandsMap extends CommandsMap { public AdminCommandsMap(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override public void loadDefaultCommands() { clearCommands(); registerCommand(new CmdAdminAdd()); registerCommand(new CmdAdminAddBonus()); if (plugin.getSettings().isCoopMembers()) registerCommand(new CmdAdminAddCoopLimit()); registerCommand(new CmdAdminAddDisbands()); registerCommand(new CmdAdminAddSize()); registerCommand(new CmdAdminAddTeamLimit()); registerCommand(new CmdAdminAddWarpsLimit()); registerCommand(new CmdAdminBypass()); registerCommand(new CmdAdminChest()); registerCommand(new CmdAdminClose()); registerCommand(new CmdAdminCmdAll()); registerCommand(new CmdAdminCount()); registerCommand(new CmdAdminData()); registerCommand(new CmdAdminDebug()); registerCommand(new CmdAdminDelWarp()); registerCommand(new CmdAdminDemote()); registerCommand(new CmdAdminDisband()); registerCommand(new CmdAdminFly()); registerCommand(new CmdAdminIgnore()); registerCommand(new CmdAdminJoin()); registerCommand(new CmdAdminKick()); registerCommand(new CmdAdminModules()); registerCommand(new CmdAdminMsg()); registerCommand(new CmdAdminMsgAll()); registerCommand(new CmdAdminName()); registerCommand(new CmdAdminOpen()); registerCommand(new CmdAdminOpenMenu()); registerCommand(new CmdAdminPromote()); registerCommand(new CmdAdminPurge()); registerCommand(new CmdAdminRecalc()); registerCommand(new CmdAdminReload()); registerCommand(new CmdAdminRemoveRatings()); registerCommand(new CmdAdminResetPermissions()); registerCommand(new CmdAdminResetSettings()); registerCommand(new CmdAdminResetWorld()); registerCommand(new CmdAdminSchematic()); registerCommand(new CmdAdminSetBiome()); registerCommand(new CmdAdminSetBlockAmount()); registerCommand(new CmdAdminSetBonus()); registerCommand(new CmdAdminSetChestRow()); if (plugin.getSettings().isCoopMembers()) registerCommand(new CmdAdminSetCoopLimit()); registerCommand(new CmdAdminSetDisbands()); registerCommand(new CmdAdminSetIslandPreview()); registerCommand(new CmdAdminSetLeader()); registerCommand(new CmdAdminSetPermission()); registerCommand(new CmdAdminSetRate()); registerCommand(new CmdAdminSetRoleLimit()); registerCommand(new CmdAdminSetSettings()); registerCommand(new CmdAdminSetSize()); registerCommand(new CmdAdminSetSpawn()); registerCommand(new CmdAdminSetTeamLimit()); registerCommand(new CmdAdminSettings()); registerCommand(new CmdAdminSetWarpsLimit()); registerCommand(new CmdAdminShow()); registerCommand(new CmdAdminSpawn()); registerCommand(new CmdAdminSpy()); registerCommand(new CmdAdminStats()); registerCommand(new CmdAdminSyncBonus()); registerCommand(new CmdAdminTeleport()); registerCommand(new CmdAdminTitle()); registerCommand(new CmdAdminTitleAll()); registerCommand(new CmdAdminUnignore()); registerCommand(new CmdAdminUnlockWorld()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAdd implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("add"); } @Override public String getPermission() { return "superior.admin.add"; } @Override public String getUsage(java.util.Locale locale) { return "admin add <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[3]); if (targetPlayer == null) return; if (targetPlayer.getIsland() != null) { Message.PLAYER_ALREADY_IN_ISLAND.send(sender); return; } if (!PluginEventsFactory.callIslandJoinEvent(island, targetPlayer, IslandJoinEvent.Cause.ADMIN)) return; IslandUtils.sendMessage(island, Message.JOIN_ANNOUNCEMENT, Collections.emptyList(), targetPlayer.getName()); island.addMember(targetPlayer, SPlayerRole.defaultRole()); if (superiorPlayer == null) { Message.JOINED_ISLAND_NAME.send(targetPlayer, island.getName()); Message.ADMIN_ADD_PLAYER_NAME.send(sender, targetPlayer.getName(), island.getName()); } else { Message.JOINED_ISLAND.send(targetPlayer, superiorPlayer.getName()); Message.ADMIN_ADD_PLAYER.send(sender, targetPlayer.getName(), superiorPlayer.getName()); } } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getOnlinePlayers(plugin, args[3], false, superiorPlayer -> superiorPlayer.getIsland() == null) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; import java.util.Locale; public class CmdAdminAddBonus implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addbonus"); } @Override public String getPermission() { return "superior.admin.addbonus"; } @Override public String getUsage(java.util.Locale locale) { return "admin addbonus <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_BONUS.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { boolean isWorthBonus; if (args[3].equalsIgnoreCase("worth")) { isWorthBonus = true; } else if (args[3].equalsIgnoreCase("level")) { isWorthBonus = false; } else { Locale locale = PlayerLocales.getLocale(sender); Message.COMMAND_USAGE.send(sender, locale, plugin.getCommands().getLabel() + " " + getUsage(locale)); return; } BigDecimal bonus = CommandArguments.getBigDecimalAmount(sender, args[4]); if (bonus == null) return; int islandsChangedCount = 0; for (Island island : islands) { if (isWorthBonus) { PluginEvent event = PluginEventsFactory.callIslandChangeWorthBonusEvent( island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, island.getBonusWorth().add(bonus)); if (!event.isCancelled()) { island.setBonusWorth(event.getArgs().worthBonus); ++islandsChangedCount; } } else { PluginEvent event = PluginEventsFactory.callIslandChangeLevelBonusEvent( island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, island.getBonusLevel().add(bonus)); if (!event.isCancelled()) { island.setBonusLevel(event.getArgs().levelBonus); ++islandsChangedCount; } } } if (islandsChangedCount <= 0) return; if (isWorthBonus) { if (islandsChangedCount > 1) Message.CHANGED_BONUS_WORTH_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_BONUS_WORTH_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_BONUS_WORTH.send(sender, targetPlayer.getName()); } else { if (islandsChangedCount > 1) Message.CHANGED_BONUS_LEVEL_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_BONUS_LEVEL_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_BONUS_LEVEL.send(sender, targetPlayer.getName()); } } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "worth", "level") : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddCoopLimit.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddCoopLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addcooplimit"); } @Override public String getPermission() { return "superior.admin.addcooplimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin addcooplimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getLimit(sender, args[3]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeCoopLimitEvent( island, sender, island.getCoopLimit() + limit); if (!event.isCancelled()) { island.setCoopLimit(event.getArgs().coopLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_COOP_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_COOP_LIMIT_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_COOP_LIMIT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddDisbands.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.List; public class CmdAdminAddDisbands implements IAdminPlayerCommand { @Override public List getAliases() { return Arrays.asList("adddisbands", "givedisbands"); } @Override public String getPermission() { return "superior.admin.givedisbands"; } @Override public String getUsage(java.util.Locale locale) { return "admin adddisbands <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_PLAYERS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, List targetPlayers, String[] args) { NumberArgument arguments = CommandArguments.getLimit(sender, args[3]); if (!arguments.isSucceed()) return; int amount = arguments.getNumber(); targetPlayers.forEach(superiorPlayer -> superiorPlayer.setDisbands(superiorPlayer.getDisbands() + amount)); if (targetPlayers.size() > 1) { Message.DISBAND_GIVE_ALL.send(sender, amount); } else if (!sender.equals(targetPlayers.get(0).asPlayer())) Message.DISBAND_GIVE_OTHER.send(sender, targetPlayers.get(0).getName(), amount); targetPlayers.forEach(superiorPlayer -> Message.DISBAND_GIVE.send(superiorPlayer, amount)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddSize implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addsize"); } @Override public String getPermission() { return "superior.admin.addsize"; } @Override public String getUsage(java.util.Locale locale) { return "admin addsize <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_SIZE.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_SIZE.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getSize(sender, args[3]); if (!arguments.isSucceed()) return; int size = arguments.getNumber(); if (size > plugin.getSettings().getMaxIslandSize()) { Message.SIZE_BIGGER_MAX.send(sender); return; } int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeBorderSizeEvent( island, sender, island.getIslandSize() + size); if (!event.isCancelled()) { island.setIslandSize(event.getArgs().borderSize); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_ISLAND_SIZE_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_ISLAND_SIZE_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_ISLAND_SIZE.send(sender, targetPlayer.getName()); if (plugin.getSettings().isBuildOutsideIsland()) Message.CHANGED_ISLAND_SIZE_BUILD_OUTSIDE.send(sender); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddTeamLimit.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddTeamLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addteamlimit"); } @Override public String getPermission() { return "superior.admin.addteamlimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin addteamlimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getLimit(sender, args[3]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeMembersLimitEvent( island, sender, island.getTeamLimit() + limit); if (!event.isCancelled()) { island.setTeamLimit(event.getArgs().membersLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_TEAM_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_TEAM_LIMIT_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_TEAM_LIMIT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddWarpsLimit.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddWarpsLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addwarpslimit"); } @Override public String getPermission() { return "superior.admin.addwarpslimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin addwarpslimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getLimit(sender, args[3]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); if (limit <= 0) { Message.INVALID_AMOUNT.send(sender); return; } int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeWarpsLimitEvent( island, sender, island.getWarpsLimit() + limit); if (!event.isCancelled()) { island.setWarpsLimit(event.getArgs().warpsLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_WARPS_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_WARPS_LIMIT_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_WARPS_LIMIT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminBypass.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminBypass implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("bypass"); } @Override public String getPermission() { return "superior.admin.bypass"; } @Override public String getUsage(java.util.Locale locale) { return "admin bypass"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_BYPASS.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (!PluginEventsFactory.callPlayerToggleBypassEvent(superiorPlayer)) return; if (superiorPlayer.hasBypassModeEnabled()) { Message.TOGGLED_BYPASS_OFF.send(superiorPlayer); } else { Message.TOGGLED_BYPASS_ON.send(superiorPlayer); } superiorPlayer.toggleBypassMode(); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminChest.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminChest implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("chest"); } @Override public String getPermission() { return "superior.admin.chest"; } @Override public String getUsage(java.util.Locale locale) { return "admin chest <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_CHEST.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); plugin.getMenus().openIslandChest(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminClose implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("close", "lock"); } @Override public String getPermission() { return "superior.admin.close"; } @Override public String getUsage(java.util.Locale locale) { return "admin close <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_CLOSE.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { if (island.isLocked()) { Message.ISLAND_ALREADY_CLOSED.send(sender); } else if (PluginEventsFactory.callIslandCloseEvent(island, sender)) { island.setLocked(true); Message.ISLAND_CLOSED.send(sender); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 3 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false, (superiorPlayer, island) -> !island.isLocked()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCmdAll.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminCmdAll implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("cmdall"); } @Override public String getPermission() { return "superior.admin.cmdall"; } @Override public String getUsage(java.util.Locale locale) { return "admin cmdall <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_COMMAND.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_CMD_ALL.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { String command = CommandArguments.buildLongString(args, 4, false); boolean onlyOnline = Boolean.parseBoolean(args[3]); islands.forEach(island -> island.executeCommand(command, onlyOnline)); if (targetPlayer == null) Message.GLOBAL_COMMAND_EXECUTED_NAME.send(sender, islands.size() == 1 ? islands.get(0).getName() : "all"); else Message.GLOBAL_COMMAND_EXECUTED.send(sender, targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "true", "false") : null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.math.BigInteger; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; public class CmdAdminCount implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("count"); } @Override public String getPermission() { return "superior.admin.count"; } @Override public String getUsage(java.util.Locale locale) { return "admin count <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> [" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_MATERIALS.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_COUNT.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { if (args.length == 3) { if (!(sender instanceof Player)) { Message.CUSTOM.send(sender, "&cYou must be a player in order to open the counts menu.", true); return; } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); plugin.getMenus().openCounts(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); return; } String materialName = args[3].toUpperCase(Locale.ENGLISH); if (materialName.equals("*")) { StringBuilder materialsBuilder = new StringBuilder(); java.util.Locale locale = PlayerLocales.getLocale(sender); if (!Message.BLOCK_COUNTS_CHECK_MATERIAL.isEmpty(locale)) { for (Map.Entry entry : island.getBlockCountsAsBigInteger().entrySet()) { materialsBuilder.append(", ").append(Message.BLOCK_COUNTS_CHECK_MATERIAL .getMessage(locale, Formatters.NUMBER_FORMATTER.format(entry.getValue()), Formatters.CAPITALIZED_FORMATTER.format(entry.getKey().toString()))); } } if (materialsBuilder.length() == 0) { Message.BLOCK_COUNTS_CHECK_EMPTY.send(sender); } else { Message.BLOCK_COUNTS_CHECK.send(sender, materialsBuilder.substring(1)); } } else { Material material = CommandArguments.getMaterial(sender, materialName); if (material == null) return; BigInteger blockCount = island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(materialName)); if (blockCount.compareTo(BigInteger.ONE) > 0) materialName = materialName + "s"; Message.BLOCK_COUNT_CHECK.send(sender, Formatters.NUMBER_FORMATTER.format(blockCount), Formatters.CAPITALIZED_FORMATTER.format(materialName)); } } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { if (args.length != 4) return Collections.emptyList(); List list = new LinkedList<>(CommandTabCompletes.getMaterials(args[3])); if ("*".contains(args[3])) list.add("*"); return Collections.unmodifiableList(list); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.persistence.IPersistentDataHolder; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.serialization.impl.PersistentDataSerializer; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.google.common.collect.ImmutableMap; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; public class CmdAdminData implements ISuperiorCommand { private static final Map subCommands = new ImmutableMap.Builder() .put("set", new SetSubCommand()) .put("get", new GetSubCommand()) .put("remove", new RemoveSubCommand()) .build(); @Override public List getAliases() { return Collections.singletonList("data"); } @Override public String getPermission() { return "superior.admin.data"; } @Override public String getUsage(java.util.Locale locale) { return "admin data <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_DATA.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SubCommand subCommand = subCommands.get(args[2].toLowerCase(Locale.ENGLISH)); if (subCommand == null) { Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + " " + getUsage(PlayerLocales.getLocale(sender))); return; } if (args.length < subCommand.getMinArgs() || args.length > subCommand.getMaxArgs()) { Locale senderLocale = PlayerLocales.getLocale(sender); Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + " " + getUsage(senderLocale) + subCommand.getUsage(senderLocale)); return; } IPersistentDataHolder persistentDataHolder; if (args[3].equalsIgnoreCase("island")) { IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[4]); persistentDataHolder = arguments.getIsland(); } else if (args[3].equalsIgnoreCase("player")) { persistentDataHolder = CommandArguments.getPlayer(plugin, sender, args[4]); } else { Locale senderLocale = PlayerLocales.getLocale(sender); Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + " " + getUsage(senderLocale) + subCommand.getUsage(senderLocale)); return; } if (persistentDataHolder != null) subCommand.execute(plugin, sender, persistentDataHolder, args); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { switch (args.length) { case 3: return CommandTabCompletes.getCustomComplete(args[2], "get", "set", "remove"); case 4: { SubCommand subCommand = subCommands.get(args[2].toLowerCase(Locale.ENGLISH)); return subCommand == null ? Collections.emptyList() : CommandTabCompletes.getCustomComplete(args[3], "island", "player"); } case 5: { SubCommand subCommand = subCommands.get(args[2].toLowerCase(Locale.ENGLISH)); if (subCommand != null && args[3].equalsIgnoreCase("island")) return CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[4], false, null); else if (subCommand != null && args[3].equalsIgnoreCase("player")) CommandTabCompletes.getOnlinePlayers(plugin, args[4], false); else return Collections.emptyList(); } default: { return Collections.emptyList(); } } } interface SubCommand { String getUsage(Locale locale); int getMinArgs(); int getMaxArgs(); void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, IPersistentDataHolder persistentDataHolder, String[] args); } private static class GetSubCommand implements SubCommand { @Override public String getUsage(Locale locale) { return " [" + Message.COMMAND_ARGUMENT_PATH.getMessage(locale) + "]"; } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 6; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, IPersistentDataHolder persistentDataHolder, String[] args) { if (persistentDataHolder.isPersistentDataContainerEmpty()) { Message.PERSISTENT_DATA_EMPTY.send(sender); return; } Locale locale = PlayerLocales.getLocale(sender); PersistentDataSerializer serializer = new PersistentDataSerializer(locale); PersistentDataContainer dataContainer = persistentDataHolder.getPersistentDataContainer(); String serializedValue; if (args.length == 6) { if (!dataContainer.has(args[5])) { Message.PERSISTENT_DATA_EMPTY.send(sender); return; } serializedValue = serializer.serialize(dataContainer.get(args[5])); } else { if (dataContainer.isEmpty()) { Message.PERSISTENT_DATA_EMPTY.send(sender); return; } StringBuilder dataMessageBuilder = new StringBuilder(); dataContainer.forEach((key, value) -> { String valueSerialized = serializer.serialize(value); if (valueSerialized.isEmpty()) return; if (dataMessageBuilder.length() != 0) dataMessageBuilder.append(Message.PERSISTENT_DATA_SHOW_SPACER.getMessage(locale)); dataMessageBuilder.append(Message.PERSISTENT_DATA_SHOW_PATH.getMessage(locale, key)).append(valueSerialized); }); if (dataMessageBuilder.length() < 2) { Message.PERSISTENT_DATA_EMPTY.send(sender); return; } serializedValue = dataMessageBuilder.toString(); } Message.PERSISTENT_DATA_SHOW.send(sender, args[4], serializedValue); } } private static class SetSubCommand implements SubCommand { @Override public String getUsage(Locale locale) { return " "; } @Override public int getMinArgs() { return 7; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, IPersistentDataHolder persistentDataHolder, String[] args) { PersistentDataContainer dataContainer = persistentDataHolder.getPersistentDataContainer(); PersistentDataSerializer serializer = new PersistentDataSerializer(PlayerLocales.getLocale(sender)); String path = args[5]; // noinspection unchecked Pair> value = (Pair>) serializer.deserialize(String.join(" ", Arrays.copyOfRange(args, 6, args.length))); assert value != null; dataContainer.remove(path); Object oldValue = dataContainer.put(path, value.getValue(), value.getKey()); if (!value.getKey().equals(oldValue)) persistentDataHolder.savePersistentDataContainer(); Message.PERSISTENT_DATA_MODIFY.send(sender, args[4], path, serializer.serialize(value.getKey())); } } private static class RemoveSubCommand implements SubCommand { @Override public String getUsage(Locale locale) { return " "; } @Override public int getMinArgs() { return 6; } @Override public int getMaxArgs() { return 6; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, IPersistentDataHolder persistentDataHolder, String[] args) { if (persistentDataHolder.isPersistentDataContainerEmpty()) { Message.PERSISTENT_DATA_EMPTY.send(sender); return; } PersistentDataContainer dataContainer = persistentDataHolder.getPersistentDataContainer(); if (!dataContainer.has(args[5])) { Message.PERSISTENT_DATA_EMPTY.send(sender); return; } Object oldValue = dataContainer.remove(args[5]); if (oldValue != null) persistentDataHolder.savePersistentDataContainer(); Message.PERSISTENT_DATA_REMOVED.send(sender, args[4], args[5]); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDebug.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; import java.util.Locale; public class CmdAdminDebug implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("debug"); } @Override public String getPermission() { return "superior.admin.debug"; } @Override public String getUsage(java.util.Locale locale) { return "admin debug [filter]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_DEBUG.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean displayCommand() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { boolean originalDebugMode = Log.isDebugMode(); Debug debugFilter; if (args.length == 2) { if (originalDebugMode) { debugFilter = null; } else { Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + " " + getUsage(PlayerLocales.getLocale(sender))); return; } } else { debugFilter = EnumHelper.getEnum(Debug.class, args[2].toUpperCase(Locale.ENGLISH)); } boolean newDebugMode = debugFilter != null; if (originalDebugMode != newDebugMode) { Log.toggleDebugMode(); if (newDebugMode) { Message.DEBUG_MODE_ENABLED.send(sender); } else { Message.DEBUG_MODE_DISABLED.send(sender); } } if (debugFilter != null) { if (Log.isDebugged(debugFilter)) { Message.DEBUG_MODE_FILTER_REMOVE.send(sender, Formatters.CAPITALIZED_FORMATTER.format(debugFilter.name())); } else { Message.DEBUG_MODE_FILTER_ADD.send(sender, Formatters.CAPITALIZED_FORMATTER.format(debugFilter.name())); } } else { Message.DEBUG_MODE_FILTER_CLEAR.send(sender); } Log.setDebugFilter(debugFilter); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length <= 2 ? Collections.emptyList() : CommandTabCompletes.getCustomComplete(args[2], Debug.getDebugNames()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.warp.SignWarp; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminDelWarp implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("delwarp"); } @Override public String getPermission() { return "superior.admin.delwarp"; } @Override public String getUsage(java.util.Locale locale) { return "admin delwarp <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_WARP_NAME.getMessage(locale) + "...>"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_DEL_WARP.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { IslandWarp islandWarp = CommandArguments.getWarp(sender, island, args, 3); if (islandWarp == null) return; if (!PluginEventsFactory.callIslandDeleteWarpEvent(islandWarp.getIsland(), sender, islandWarp)) return; island.deleteWarp(islandWarp.getName()); Message.DELETE_WARP.send(sender, islandWarp.getName()); SignWarp.trySignWarpBreak(islandWarp, sender); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getIslandWarps(island, args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminDemote implements IAdminPlayerCommand { @Override public List getAliases() { return Collections.singletonList("demote"); } @Override public String getPermission() { return "superior.admin.demote"; } @Override public String getUsage(java.util.Locale locale) { return "admin demote <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_DEMOTE.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { Island island = targetPlayer.getIsland(); if (island == null) { Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName()); return; } PlayerRole currentRole = targetPlayer.getPlayerRole(); if (currentRole.isLastRole()) { Message.DEMOTE_LEADER.send(sender); return; } PlayerRole previousRole = currentRole; int roleLimit; do { previousRole = previousRole.getPreviousRole(); roleLimit = previousRole == null ? -1 : island.getRoleLimit(previousRole); } while (previousRole != null && !previousRole.isFirstRole() && roleLimit >= 0 && roleLimit >= island.getIslandMembers(previousRole).size()); if (previousRole == null) { Message.LAST_ROLE_DEMOTE.send(sender); return; } if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, previousRole)) return; targetPlayer.setPlayerRole(previousRole); Message.DEMOTED_MEMBER.send(sender, targetPlayer.getName(), targetPlayer.getPlayerRole()); Message.GOT_DEMOTED.send(targetPlayer, targetPlayer.getPlayerRole()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false, superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer) && !superiorPlayer.getPlayerRole().isFirstRole()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class CmdAdminDisband implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("disband"); } @Override public String getPermission() { return "superior.admin.disband"; } @Override public String getUsage(java.util.Locale locale) { return "admin disband <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_DISBAND.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { if (!PluginEventsFactory.callIslandDisbandEvent(island, targetPlayer)) return; IslandUtils.sendMessage(island, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), sender.getName()); if (targetPlayer == null) Message.DISBANDED_ISLAND_OTHER_NAME.send(sender, island.getName()); else Message.DISBANDED_ISLAND_OTHER.send(sender, targetPlayer.getName()); if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); Message.DISBAND_ISLAND_BALANCE_REFUND.send(island.getOwner(), Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance().multiply(disbandRefund))); } island.disbandIsland(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminFly.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Location; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminFly implements IAdminPlayerCommand { private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); } }; @Override public List getAliases() { return Collections.singletonList("fly"); } @Override public String getPermission() { return "superior.admin.fly"; } @Override public String getUsage(java.util.Locale locale) { return "admin fly <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> [flying[true/false]]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_FLY.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { if (args.length == 4) { boolean enableFlying = Boolean.parseBoolean(args[3]); if (enableFlying == targetPlayer.hasIslandFlyEnabled()) { // Nothing changes, let's just send message to sender and return if (enableFlying) { Message.TOGGLED_FLY_ON_OTHER.send(sender, targetPlayer.getName()); } else { Message.TOGGLED_FLY_OFF_OTHER.send(sender, targetPlayer.getName()); } return; } } if (!PluginEventsFactory.callPlayerToggleFlyEvent(targetPlayer)) return; if (targetPlayer.hasIslandFlyEnabled()) { targetPlayer.runIfOnline(player -> { player.setAllowFlight(false); player.setFlying(false); }); Message.TOGGLED_FLY_OFF.send(targetPlayer); Message.TOGGLED_FLY_OFF_OTHER.send(sender, targetPlayer.getName()); } else { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(targetPlayer.getLocation(wrapper.getHandle())); } if (island != null && island.hasPermission(targetPlayer, IslandPrivileges.FLY)) { targetPlayer.runIfOnline(player -> { player.setAllowFlight(true); player.setFlying(true); }); } Message.TOGGLED_FLY_ON.send(targetPlayer); Message.TOGGLED_FLY_ON_OTHER.send(sender, targetPlayer.getName()); } targetPlayer.toggleIslandFly(); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "true", "false") : null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminIgnore.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminIgnore implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("ignore"); } @Override public String getPermission() { return "superior.admin.ignore"; } @Override public String getUsage(java.util.Locale locale) { return "admin ignore <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_IGNORE.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { island.setIgnored(true); if (targetPlayer == null) Message.IGNORED_ISLAND_NAME.send(sender, island.getName()); else Message.IGNORED_ISLAND.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminJoin implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("join"); } @Override public String getPermission() { return "superior.admin.join"; } @Override public String getUsage(java.util.Locale locale) { return "admin join <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_JOIN.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (superiorPlayer.getIsland() != null) { Message.ALREADY_IN_ISLAND.send(superiorPlayer); return; } if (!PluginEventsFactory.callIslandJoinEvent(island, superiorPlayer, IslandJoinEvent.Cause.ADMIN)) return; IslandUtils.sendMessage(island, Message.JOIN_ADMIN_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); island.addMember(superiorPlayer, SPlayerRole.defaultRole()); if (targetPlayer == null) Message.JOINED_ISLAND_NAME.send(superiorPlayer, island.getName()); else Message.JOINED_ISLAND.send(superiorPlayer, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminKick.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdAdminKick implements IAdminPlayerCommand { @Override public List getAliases() { return Collections.singletonList("kick"); } @Override public String getPermission() { return "superior.admin.kick"; } @Override public String getUsage(java.util.Locale locale) { return "admin kick <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_KICK.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { Island targetIsland = targetPlayer.getIsland(); if (targetIsland == null) { Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName()); return; } if (targetIsland.getOwner() == targetPlayer) { Message.KICK_ISLAND_LEADER.send(sender); return; } IslandUtils.handleKickPlayer(sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null, sender.getName(), targetIsland, targetPlayer); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false, superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer)) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminModules.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.io.File; import java.util.Collections; import java.util.List; import java.util.Locale; public class CmdAdminModules implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("modules"); } @Override public String getPermission() { return "superior.admin.modules"; } @Override public String getUsage(java.util.Locale locale) { return "admin modules [<" + Message.COMMAND_ARGUMENT_MODULE_NAME.getMessage(locale) + "> [load/unload]]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_MODULES.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { if (args.length == 2) { StringBuilder modulesList = new StringBuilder(); java.util.Locale senderLocale = PlayerLocales.getLocale(sender); String moduleSeparator = Message.MODULES_LIST_SEPARATOR.getMessage(senderLocale); for (PluginModule pluginModule : plugin.getModules().getModules()) { modulesList.append(moduleSeparator).append(Message.MODULES_LIST_MODULE_NAME .getMessage(senderLocale, pluginModule.getName(), pluginModule.getAuthor())); } Message.MODULES_LIST.send(sender, plugin.getModules().getModules().size(), modulesList.substring(moduleSeparator.length())); } else { PluginModule pluginModule = plugin.getModules().getModule(args[2]); if (args.length == 3) { if (pluginModule == null) { Message.INVALID_MODULE.send(sender, args[2]); return; } Message.MODULE_INFO.send(sender, pluginModule.getName(), pluginModule.getAuthor(), ""); } else { String command = args[3].toLowerCase(Locale.ENGLISH); switch (command) { case "load": pluginModule = BuiltinModules.getBuiltinModule(args[2]); if (pluginModule == null) { File moduleFile = new File(plugin.getDataFolder(), "modules/" + args[2] + ".jar"); try { pluginModule = plugin.getModules().registerModule(moduleFile); } catch (Exception error) { Log.error(error, "An unexpected error occurred while loading the module ", args[2], ":"); Message.MODULE_LOADED_FAILURE.send(sender, args[2]); return; } } else { if (pluginModule.isInitialized()) { Message.MODULE_ALREADY_INITIALIZED.send(sender); return; } plugin.getModules().registerModule(pluginModule); } plugin.getModules().enableModule(pluginModule); Message.MODULE_LOADED_SUCCESS.send(sender, pluginModule.getName()); break; case "unload": if (pluginModule == null) { Message.INVALID_MODULE.send(sender, args[2]); return; } plugin.getModules().unregisterModule(pluginModule); Message.MODULE_UNLOADED_SUCCESS.send(sender); break; default: Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + " " + getUsage(PlayerLocales.getLocale(sender))); break; } } } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length != 3 ? Collections.emptyList() : CommandTabCompletes.getModules(plugin, args[2]); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminMsg.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminMsg implements IAdminPlayerCommand { private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); } }; @Override public List getAliases() { return Collections.singletonList("msg"); } @Override public String getPermission() { return "superior.admin.msg"; } @Override public String getUsage(java.util.Locale locale) { return "admin msg <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_MSG.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { String message = CommandArguments.buildLongString(args, 3, true); if (!Text.isBlank(message)) message = placeholdersService.get().parsePlaceholders(targetPlayer.asOfflinePlayer(), message); Message.CUSTOM.send(targetPlayer, message, false); Message.MESSAGE_SENT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminMsgAll.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminMsgAll implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("msgall"); } @Override public String getPermission() { return "superior.admin.msgall"; } @Override public String getUsage(java.util.Locale locale) { return "admin msgall <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_MSG_ALL.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { String message = CommandArguments.buildLongString(args, 3, true); islands.forEach(island -> island.sendMessage(message)); if (targetPlayer == null) Message.GLOBAL_MESSAGE_SENT_NAME.send(sender, islands.size() == 1 ? islands.get(0).getName() : "all"); else Message.GLOBAL_MESSAGE_SENT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandNames; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.List; public class CmdAdminName implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("name", "setname", "rename"); } @Override public String getPermission() { return "superior.admin.name"; } @Override public String getUsage(java.util.Locale locale) { return "admin name <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_NAME.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { PluginEvent event = PluginEventsFactory.callIslandRenameEvent(island, sender, args[3]); if (event.isCancelled()) return; String islandName = event.getArgs().islandName; if (!IslandNames.isValidName(sender, island, islandName)) return; String oldName = island.getName(); island.setName(islandName); String coloredName = island.getName(); if (targetPlayer == null) { IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT_OTHER_NAME, sender.getName(), oldName, coloredName); Message.CHANGED_NAME_OTHER_NAME.send(sender, oldName, coloredName); } else { IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT_OTHER, sender.getName(), targetPlayer.getName(), coloredName); Message.CHANGED_NAME_OTHER.send(sender, targetPlayer.getName(), coloredName); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminOpen implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("open", "unlock"); } @Override public String getPermission() { return "superior.admin.open"; } @Override public String getUsage(java.util.Locale locale) { return "admin open <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_OPEN.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { if (!island.isLocked()) { Message.ISLAND_ALREADY_OPENED.send(sender); } else if (PluginEventsFactory.callIslandOpenEvent(island, sender)) { island.setLocked(false); Message.ISLAND_OPENED.send(sender); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 3 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false, (superiorPlayer, island) -> island.isLocked()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpenMenu.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuCustom; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminOpenMenu implements IAdminPlayerCommand { @Override public List getAliases() { return Arrays.asList("openmenu", "menu"); } @Override public String getPermission() { return "superior.admin.openmenu"; } @Override public String getUsage(java.util.Locale locale) { return "admin openmenu <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MENU.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_OPEN_MENU.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { String menuIdentifier = MenuIdentifiers.MENU_CUSTOM_PREFIX + args[3]; Menu menu = plugin.getMenus().getMenu(menuIdentifier); if (!(menu instanceof MenuCustom)) { Message.INVALID_MENU.send(sender, menuIdentifier); return; } menu.createView(targetPlayer, EmptyViewArgs.INSTANCE); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { return args.length == 4 ? CommandTabCompletes.getCustomMenus(plugin, args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminPromote implements IAdminPlayerCommand { @Override public List getAliases() { return Collections.singletonList("promote"); } @Override public String getPermission() { return "superior.admin.promote"; } @Override public String getUsage(java.util.Locale locale) { return "admin promote <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_PROMOTE.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public boolean requireIsland() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { Island island = targetPlayer.getIsland(); if (island == null) { Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName()); return; } PlayerRole currentRole = targetPlayer.getPlayerRole(); if (currentRole.isLastRole()) { Message.LAST_ROLE_PROMOTE.send(sender); return; } PlayerRole nextRole = currentRole; int roleLimit; do { nextRole = nextRole.getNextRole(); roleLimit = nextRole == null ? -1 : island.getRoleLimit(nextRole); } while (nextRole != null && !nextRole.isLastRole() && roleLimit >= 0 && island.getIslandMembers(nextRole).size() >= roleLimit); if (nextRole == null || nextRole.isLastRole()) { Message.LAST_ROLE_PROMOTE.send(sender); return; } if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, nextRole)) return; targetPlayer.setPlayerRole(nextRole); Message.PROMOTED_MEMBER.send(sender, targetPlayer.getName(), targetPlayer.getPlayerRole()); Message.GOT_PROMOTED.send(targetPlayer, targetPlayer.getPlayerRole()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false, superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer) && !superiorPlayer.getPlayerRole().getNextRole().isLastRole()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPurge.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.command.CommandSender; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class CmdAdminPurge implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("purge"); } @Override public String getPermission() { return "superior.admin.purge"; } @Override public String getUsage(java.util.Locale locale) { return "admin purge "; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_PURGE.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { if (args[2].equalsIgnoreCase("cancel")) { plugin.getGrid().getIslandsToPurge().forEach(island -> plugin.getGrid().removeIslandFromPurge(island)); Message.PURGE_CLEAR.send(sender); } else { long timeToPurge = parseLongSafe(args[2]); long currentTime = System.currentTimeMillis() / 1000; List islands = new SequentialListBuilder().filter(island -> { long lastTimeUpdate = island.getLastTimeUpdate(); return lastTimeUpdate != -1 && currentTime - lastTimeUpdate >= timeToPurge; }).build(plugin.getGrid().getIslands()); if (islands.isEmpty()) { Message.NO_ISLANDS_TO_PURGE.send(sender); } else { BukkitExecutor.async(() -> islands.forEach(island -> plugin.getGrid().addIslandToPurge(island))); Message.PURGED_ISLANDS.send(sender, islands.size()); } } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 3 ? CommandTabCompletes.getCustomComplete(args[2], "cancel") : Collections.emptyList(); } private static long parseLongSafe(String value) { try { return Long.parseLong(value); } catch (Exception error) { return 0; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRecalc.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.List; public class CmdAdminRecalc implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("recalc", "recalculate", "level"); } @Override public String getPermission() { return "superior.admin.recalc"; } @Override public String getUsage(java.util.Locale locale) { return "admin recalc <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_RECALC.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { if (islands.size() > 1) { Message.RECALC_ALL_ISLANDS.send(sender); plugin.getGrid().calcAllIslands(() -> Message.RECALC_ALL_ISLANDS_DONE.send(sender)); } else { Island island = islands.get(0); if (island.isBeingRecalculated()) { Message.RECALC_ALREADY_RUNNING_OTHER.send(sender); return; } Message.RECALC_PROCCESS_REQUEST.send(sender); island.calcIslandWorth(sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminReload.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.PluginReloadReason; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminReload implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("reload"); } @Override public String getPermission() { return "superior.admin.reload"; } @Override public String getUsage(java.util.Locale locale) { return "admin reload"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_RELOAD.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Message.RELOAD_PROCCESS_REQUEST.send(sender); try { plugin.reloadPlugin(PluginReloadReason.COMMAND); } catch (ManagerLoadException error) { Log.error(error, "An unexpected error occurred while reloading the plugin:"); if (!ManagerLoadException.handle(error)) return; } Message.RELOAD_COMPLETED.send(sender); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveRatings.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collection; import java.util.List; public class CmdAdminRemoveRatings implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("removeratings", "rratings", "rr"); } @Override public String getPermission() { return "superior.admin.removeratings"; } @Override public String getUsage(java.util.Locale locale) { return "admin removeratings <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { boolean removingAllRatings = targetPlayer == null; Collection iterIslands = removingAllRatings ? islands : plugin.getGrid().getIslands(); int islandsChangedCount = 0; for (Island island : iterIslands) { if (removingAllRatings) { if (PluginEventsFactory.callIslandClearRatingsEvent(island, sender)) { ++islandsChangedCount; island.removeRatings(); } } else if (PluginEventsFactory.callIslandRemoveRatingEvent(island, sender, targetPlayer)) { ++islandsChangedCount; island.removeRating(targetPlayer); } } if (islandsChangedCount <= 0) return; if (!removingAllRatings) Message.RATE_REMOVE_ALL.send(sender, targetPlayer.getName()); else if (islands.size() == 1) Message.RATE_REMOVE_ALL.send(sender, islands.get(0).getName()); else Message.RATE_REMOVE_ALL_ISLANDS.send(sender); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetPermissions.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminResetPermissions implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("resetpermissions"); } @Override public String getPermission() { return "superior.admin.resetpermissions"; } @Override public String getUsage(java.util.Locale locale) { return "admin resetpermissions <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { int islandsChangedCount = 0; for (Island island : islands) { if (PluginEventsFactory.callIslandClearRolesPrivilegesEvent(island, sender)) { ++islandsChangedCount; island.resetPermissions(); } } if (islandsChangedCount <= 0) return; if (islands.size() != 1) Message.PERMISSIONS_RESET_ALL.send(sender); else if (targetPlayer == null) Message.PERMISSIONS_RESET_NAME.send(sender, islands.get(0).getName()); else Message.PERMISSIONS_RESET.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetSettings.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminResetSettings implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("resetsettings"); } @Override public String getPermission() { return "superior.admin.resetsettings"; } @Override public String getUsage(java.util.Locale locale) { return "admin resetsettings <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { int islandsChangedCount = 0; for (Island island : islands) { if (PluginEventsFactory.callIslandClearFlagsEvent(island, sender)) { ++islandsChangedCount; island.resetSettings(); } } if (islandsChangedCount <= 0) return; if (islands.size() != 1) Message.SETTINGS_RESET_ALL.send(sender); else if (targetPlayer == null) Message.SETTINGS_RESET_NAME.send(sender, islands.get(0).getName()); else Message.SETTINGS_RESET.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.BlockFace; import org.bukkit.command.CommandSender; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; public class CmdAdminResetWorld implements IAdminIslandCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference dragonBattleService = new LazyReference() { @Override protected DragonBattleService create() { return plugin.getServices().getService(DragonBattleService.class); } }; @Override public List getAliases() { return Arrays.asList("resetworld", "rworld"); } @Override public String getPermission() { return "superior.admin.resetworld"; } @Override public String getUsage(java.util.Locale locale) { return "admin resetworld <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_RESET_WORLD.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Dimension dimension = CommandArguments.getDimension(sender, args[3]); if (dimension == null) return; int islandsChangedCount = 0; for (Island island : islands) { if (!PluginEventsFactory.callIslandWorldResetEvent(island, sender, dimension)) continue; ++islandsChangedCount; IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifLeft(world -> resetChunksInternal(island, world, dimension)); }); } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.RESET_WORLD_SUCCEED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3])); else if (targetPlayer == null) Message.RESET_WORLD_SUCCEED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), islands.get(0).getName()); else Message.RESET_WORLD_SUCCEED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), targetPlayer.getName()); } private static void resetChunksInternal(Island island, World world, Dimension dimension) { boolean isDefaultDimension = dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension(); try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { // Sending the players that are in that world to the main island. // If the world that will be reset is the normal world, they will be teleported to spawn. Island teleportIsland = isDefaultDimension ? plugin.getGrid().getSpawnIsland() : island; for (SuperiorPlayer superiorPlayer : strategy.getSuperiorPlayers(WorldInfo.of(world))) { superiorPlayer.teleport(teleportIsland); } } // Resetting the chunks island.resetChunks(dimension, IslandChunkFlags.ONLY_PROTECTED, isDefaultDimension ? null : () -> island.calcIslandWorth(null)); if (isDefaultDimension) { String islandSchematic = island.getSchematicName(); Schematic schematic = plugin.getSchematics().getSchematic(islandSchematic); if (schematic != null) { regenerateSchematicInternal(island, dimension, schematic); return; } } island.setSchematicGenerate(dimension, false); } private static void regenerateSchematicInternal(Island island, Dimension dimension, Schematic schematic) { Location centerLocation = island.getCenter(dimension); Location schematicPlacementLocation = centerLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(); schematic.pasteSchematic(island, schematicPlacementLocation, () -> { island.setSchematicGenerate(dimension); Location homeLocation = schematic.adjustRotation(centerLocation); island.setIslandHome(homeLocation); if (dimension.getEnvironment() == World.Environment.THE_END) { dragonBattleService.get().resetEnderDragonBattle(island, dimension); } island.calcIslandWorth(null); }, Throwable::printStackTrace); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminSchematic implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("schematic", "schem"); } @Override public String getPermission() { return "superior.admin.schematic"; } @Override public String getUsage(java.util.Locale locale) { return "admin schematic [" + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + "] [" + Message.COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR.getMessage(locale) + "[true/false]]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SCHEMATIC.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (args.length == 2) { if (superiorPlayer.hasSchematicModeEnabled()) { Message.TOGGLED_SCHEMATIC_OFF.send(superiorPlayer); } else { Message.TOGGLED_SCHEMATIC_ON.send(superiorPlayer); } superiorPlayer.toggleSchematicMode(); } else { if (superiorPlayer.getSchematicPos1() == null || superiorPlayer.getSchematicPos2() == null) { Message.SCHEMATIC_NOT_READY.send(superiorPlayer); return; } String schematicName = args[2]; boolean saveAir = args.length == 4 && Boolean.parseBoolean(args[3]); Message.SCHEMATIC_PROCCESS_REQUEST.send(superiorPlayer); plugin.getSchematics().saveSchematic(superiorPlayer, schematicName, saveAir); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "true", "false") : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBiome.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.block.Biome; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminSetBiome implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("setbiome", "biome"); } @Override public String getPermission() { return "superior.admin.setbiome"; } @Override public String getUsage(java.util.Locale locale) { return "admin setbiome <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_BIOME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_BIOME.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Biome biome = CommandArguments.getBiome(plugin, sender, args[3]); if (biome == null) return; islands.forEach(island -> island.setBiome(biome)); if (islands.size() > 1) Message.CHANGED_BIOME_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(biome.name())); else if (targetPlayer == null) Message.CHANGED_BIOME_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(biome.name()), islands.get(0).getName()); else Message.CHANGED_BIOME_OTHER.send(sender, Formatters.CAPITALIZED_FORMATTER.format(biome.name()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getBiomes(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockAmount.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class CmdAdminSetBlockAmount implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("setblockamount", "setblocksize"); } @Override public String getPermission() { return "superior.admin.setblockamount"; } @Override public String getUsage(java.util.Locale locale) { return "admin setblockamount <" + Message.COMMAND_ARGUMENT_WORLD.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT.getMessage(locale); } @Override public int getMinArgs() { return 7; } @Override public int getMaxArgs() { return 7; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { World world = CommandArguments.getWorld(sender, args[2]); if (world == null) return; Location location = CommandArguments.getLocation(sender, world, args[3], args[4], args[5]); if (location == null) return; NumberArgument arguments = CommandArguments.getAmount(sender, args[6]); if (!arguments.isSucceed()) return; int amount = arguments.getNumber(); plugin.getStackedBlocks().setStackedBlock(location.getBlock(), amount); String formattedLocation = args[2] + ", " + args[3] + ", " + args[4] + ", " + args[5]; Message.CHANGED_BLOCK_AMOUNT.send(sender, formattedLocation, amount); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { List list = new LinkedList<>(); if (args.length == 3) { list = CommandTabCompletes.getWorlds(args[2]); } else if (sender instanceof Player) { String blockX; String blockY; String blockZ; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = ((Player) sender).getLocation(wrapper.getHandle()); blockX = String.valueOf(location.getBlockX()); blockY = String.valueOf(location.getBlockY()); blockZ = String.valueOf(location.getBlockZ()); } if (args.length == 4) { if (blockX.contains(args[3])) list.add(blockX); } else if (args.length == 5) { if (blockY.contains(args[4])) list.add(blockY); } else if (args.length == 6) { if (blockZ.contains(args[5])) list.add(blockZ); } } return Collections.unmodifiableList(list); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; public class CmdAdminSetBonus implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("setbonus", "bonus"); } @Override public String getPermission() { return "superior.admin.bonus"; } @Override public String getUsage(java.util.Locale locale) { return "admin setbonus <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_BONUS.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { boolean isWorthBonus; if (args[3].equalsIgnoreCase("worth")) { isWorthBonus = true; } else if (args[3].equalsIgnoreCase("level")) { isWorthBonus = false; } else { Locale locale = PlayerLocales.getLocale(sender); Message.COMMAND_USAGE.send(sender, locale, plugin.getCommands().getLabel() + " " + getUsage(locale)); return; } BigDecimal bonus = CommandArguments.getBigDecimalAmount(sender, args[4]); if (bonus == null) return; int islandsChangedCount = 0; for (Island island : islands) { if (isWorthBonus) { PluginEvent event = PluginEventsFactory.callIslandChangeWorthBonusEvent( island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, bonus); if (!event.isCancelled()) { island.setBonusWorth(event.getArgs().worthBonus); ++islandsChangedCount; } } else { PluginEvent event = PluginEventsFactory.callIslandChangeLevelBonusEvent( island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, bonus); if (!event.isCancelled()) { island.setBonusLevel(event.getArgs().levelBonus); ++islandsChangedCount; } } } if (islandsChangedCount <= 0) return; if (isWorthBonus) { if (islandsChangedCount > 1) Message.CHANGED_BONUS_WORTH_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_BONUS_WORTH_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_BONUS_WORTH.send(sender, targetPlayer.getName()); } else { if (islandsChangedCount > 1) Message.CHANGED_BONUS_LEVEL_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_BONUS_LEVEL_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_BONUS_LEVEL.send(sender, targetPlayer.getName()); } } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "worth", "level") : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetChestRow.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; import java.util.stream.IntStream; public class CmdAdminSetChestRow implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setchestrow"); } @Override public String getPermission() { return "superior.admin.setchestrow"; } @Override public String getUsage(java.util.Locale locale) { return "admin setchestrow <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_PAGE.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_ROWS.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument pageArguments = CommandArguments.getPage(sender, args[3]); if (!pageArguments.isSucceed()) return; int page = pageArguments.getNumber(); NumberArgument rowsArguments = CommandArguments.getRows(sender, args[4]); if (!rowsArguments.isSucceed()) return; int rows = rowsArguments.getNumber(); if (rows < 1 || rows > 6) { Message.INVALID_ROWS.send(sender, args[4]); return; } islands.forEach(island -> island.setChestRows(page - 1, rows)); if (islands.size() > 1) Message.CHANGED_CHEST_SIZE_ALL.send(sender, page, rows); else if (targetPlayer == null) Message.CHANGED_CHEST_SIZE_NAME.send(sender, page, rows, islands.get(0).getName()); else Message.CHANGED_CHEST_SIZE.send(sender, page, rows, targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 && island != null ? CommandTabCompletes.getCustomComplete(args[3], IntStream.range(1, island.getChestSize() + 1)) : args.length == 5 && island != null ? CommandTabCompletes.getCustomComplete(args[4], IntStream.range(1, 7)) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetCoopLimit.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetCoopLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setcooplimit"); } @Override public String getPermission() { return "superior.admin.setcooplimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin setcooplimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getLimit(sender, args[3]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeCoopLimitEvent( island, sender, island.getCoopLimit() + limit); if (!event.isCancelled()) { island.setCoopLimit(event.getArgs().coopLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_COOP_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_COOP_LIMIT_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_COOP_LIMIT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetDisbands.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetDisbands implements IAdminPlayerCommand { @Override public List getAliases() { return Collections.singletonList("setdisbands"); } @Override public String getPermission() { return "superior.admin.setdisbands"; } @Override public String getUsage(java.util.Locale locale) { return "admin setdisbands <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_PLAYERS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, List targetPlayers, String[] args) { NumberArgument arguments = CommandArguments.getLimit(sender, args[3]); if (!arguments.isSucceed()) return; int amount = arguments.getNumber(); targetPlayers.forEach(superiorPlayer -> superiorPlayer.setDisbands(amount)); if (targetPlayers.size() > 1) { Message.DISBAND_SET_ALL.send(sender, amount); } else if (!sender.equals(targetPlayers.get(0).asPlayer())) Message.DISBAND_SET_OTHER.send(sender, targetPlayers.get(0).getName(), amount); targetPlayers.forEach(superiorPlayer -> Message.DISBAND_SET.send(superiorPlayer, amount)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminSetIslandPreview implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("setislandpreview", "setschematicpreview"); } @Override public String getPermission() { return "superior.admin.setislandpreview"; } @Override public String getUsage(java.util.Locale locale) { return "admin setislandpreview <" + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Schematic schematic = CommandArguments.getSchematic(plugin, sender, args[2]); if (schematic == null) return; Player player = (Player) sender; String schematicPreviewLocation; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = player.getLocation(wrapper.getHandle()); location.setX(location.getBlockX()); location.setY(location.getBlockY()); location.setZ(location.getBlockZ()); // Fix to corner of a block location.add(0.5, 0, 0.5); schematicPreviewLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(location); } try { plugin.getSettings().updateValue("island-previews.locations." + schematic.getName(), schematicPreviewLocation); } catch (Exception error) { Log.entering("ENTER", schematicPreviewLocation); Log.error(error, "An unexpected error occurred while setting schematic preview:"); } Message.ISLAND_PREVIEW_SET.send(sender, schematic.getName(), schematicPreviewLocation); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 3 ? CommandTabCompletes.getSchematics(plugin, args[2]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetLeader.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetLeader implements IAdminPlayerCommand { @Override public List getAliases() { return Collections.singletonList("setleader"); } @Override public String getPermission() { return "superior.admin.setleader"; } @Override public String getUsage(java.util.Locale locale) { return "admin setleader <" + Message.COMMAND_ARGUMENT_LEADER.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_NEW_LEADER.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_LEADER.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public boolean requireIsland() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer leader, String[] args) { SuperiorPlayer newLeader = CommandArguments.getPlayer(plugin, sender, args[3]); if (newLeader == null) return; Island island = leader.getIsland(); assert island != null; // requireIsland is true if (!island.getOwner().getUniqueId().equals(leader.getUniqueId())) { Message.TRANSFER_ADMIN_NOT_LEADER.send(sender); return; } if (leader.getUniqueId().equals(newLeader.getUniqueId())) { Message.TRANSFER_ADMIN_ALREADY_LEADER.send(sender, newLeader.getName()); return; } if (!island.isMember(newLeader)) { Message.TRANSFER_ADMIN_DIFFERENT_ISLAND.send(sender); return; } if (island.transferIsland(newLeader)) { Message.TRANSFER_ADMIN.send(sender, leader.getName(), newLeader.getName()); IslandUtils.sendMessage(island, Message.TRANSFER_BROADCAST, Collections.emptyList(), newLeader.getName()); } } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { Island playerIsland = targetPlayer.getIsland(); return args.length != 4 ? Collections.emptyList() : CommandTabCompletes.getOnlinePlayers(plugin, args[2], false, onlinePlayer -> { Island onlineIsland = onlinePlayer.getIsland(); return !onlinePlayer.equals(targetPlayer) && onlineIsland != null && !onlineIsland.equals(playerIsland) && onlineIsland.getOwner().equals(onlinePlayer); }); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminSetPermission implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("setpermission", "setperm"); } @Override public String getPermission() { return "superior.admin.setpermission"; } @Override public String getUsage(java.util.Locale locale) { return "admin setpermission <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_PERMISSION.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_ISLAND_ROLE.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { IslandPrivilege islandPrivilege = CommandArguments.getIslandPrivilege(sender, args[3]); if (islandPrivilege == null) return; PlayerRole playerRole = islandPrivilege.getType() == IslandPrivilege.Type.COMMAND ? CommandArguments.getPlayerRoleFromLadder(sender, args[4]) : CommandArguments.getPlayerRole(sender, args[4]); if (playerRole == null) return; int islandsChangedCount = 0; for (Island island : islands) { if (PluginEventsFactory.callIslandChangeRolePrivilegeEvent(island, sender, playerRole)) { island.setPermission(playerRole, islandPrivilege); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.PERMISSION_CHANGED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName())); else if (targetPlayer == null) Message.PERMISSION_CHANGED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName()), islands.get(0).getName()); else Message.PERMISSION_CHANGED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { switch (args.length) { case 4: return CommandTabCompletes.getIslandPrivileges(args[3]); case 5: { IslandPrivilege islandPrivilege = getIslandPrivilegeSafe(args[3]); if (islandPrivilege == null) return Collections.emptyList(); else if (islandPrivilege.getType() == IslandPrivilege.Type.COMMAND) return CommandTabCompletes.getPlayerRoles(plugin, args[4], PlayerRole::isRoleLadder); else return CommandTabCompletes.getPlayerRoles(plugin, args[4], null); } default: return Collections.emptyList(); } } @Nullable private static IslandPrivilege getIslandPrivilegeSafe(String name) { try { return IslandPrivilege.getByName(name); } catch (NullPointerException error) { return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class CmdAdminSetRate implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setrate"); } @Override public String getPermission() { return "superior.admin.setrate"; } @Override public String getUsage(java.util.Locale locale) { return "admin setrate <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_RATING.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_RATE.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[3]); if (targetPlayer == null) return; Rating rating = CommandArguments.getRating(sender, args[4]); if (rating == null) return; if (rating == Rating.UNKNOWN) { if (PluginEventsFactory.callIslandRemoveRatingEvent(island, sender, superiorPlayer)) { island.removeRating(targetPlayer); Message.RATE_REMOVE_ALL.send(sender, targetPlayer.getName()); } } else if (PluginEventsFactory.callIslandRateEvent(island, sender, superiorPlayer, rating)) { island.setRating(targetPlayer, rating); Message.RATE_CHANGE_OTHER.send(sender, targetPlayer.getName(), Formatters.CAPITALIZED_FORMATTER.format(rating.name())); } } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { switch (args.length) { case 4: { List tabCompletes = new LinkedList<>(); tabCompletes.addAll(CommandTabCompletes.getRatedPlayers(plugin, island, args[3])); tabCompletes.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[3], false)); return tabCompletes.isEmpty() ? Collections.emptyList() : tabCompletes; } case 5: return CommandTabCompletes.getRatings(args[4]); default: return Collections.emptyList(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetRoleLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setrolelimit"); } @Override public String getPermission() { return "superior.admin.setrolelimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin setrolelimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_ISLAND_ROLE.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { PlayerRole playerRole = CommandArguments.getPlayerRoleForLimit(sender, args[3]); if (playerRole == null) return; NumberArgument arguments = CommandArguments.getLimit(sender, args[4]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { if (limit <= 0) { if (PluginEventsFactory.callIslandRemoveRoleLimitEvent(island, sender, playerRole)) { ++islandsChangedCount; island.removeRoleLimit(playerRole); } } else { PluginEvent event = PluginEventsFactory.callIslandChangeRoleLimitEvent( island, sender, playerRole, limit); if (!event.isCancelled()) { island.setRoleLimit(playerRole, event.getArgs().roleLimit); ++islandsChangedCount; } } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_ROLE_LIMIT_ALL.send(sender, playerRole); else if (targetPlayer == null) Message.CHANGED_ROLE_LIMIT_NAME.send(sender, playerRole, islands.get(0).getName()); else Message.CHANGED_ROLE_LIMIT.send(sender, playerRole, targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getPlayerRoles(plugin, args[3], IslandUtils::isValidRoleForLimit) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSettings.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetSettings implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setsettings"); } @Override public String getPermission() { return "superior.admin.setsettings"; } @Override public String getUsage(java.util.Locale locale) { return "admin setsettings <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_SETTINGS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_VALUE.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { IslandFlag islandFlag = CommandArguments.getIslandFlag(sender, args[3]); if (islandFlag == null) return; boolean value = args[4].equalsIgnoreCase("true"); int islandsChangedCount = 0; for (Island island : islands) { if (island.hasSettingsEnabled(islandFlag) == value) { ++islandsChangedCount; continue; } if (value) { if (PluginEventsFactory.callIslandEnableFlagEvent(island, sender, islandFlag)) { ++islandsChangedCount; island.enableSettings(islandFlag); } } else if (PluginEventsFactory.callIslandDisableFlagEvent(island, sender, islandFlag)) { ++islandsChangedCount; island.disableSettings(islandFlag); } } if (islandsChangedCount <= 0) return; if (islands.size() != 1) Message.SETTINGS_UPDATED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandFlag.getName())); else if (targetPlayer == null) Message.SETTINGS_UPDATED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandFlag.getName()), islands.get(0).getName()); else Message.SETTINGS_UPDATED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandFlag.getName()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getIslandFlags(args[3]) : args.length == 5 ? CommandTabCompletes.getCustomComplete(args[4], "true", "false") : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSize.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.List; public class CmdAdminSetSize implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("setsize", "setislandsize", "setbordersize"); } @Override public String getPermission() { return "superior.admin.setsize"; } @Override public String getUsage(java.util.Locale locale) { return "admin setsize <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_SIZE.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_SIZE.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getSize(sender, args[3]); if (!arguments.isSucceed()) return; int size = arguments.getNumber(); if (size > plugin.getSettings().getMaxIslandSize()) { Message.SIZE_BIGGER_MAX.send(sender); return; } int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeBorderSizeEvent(island, sender, size); if (!event.isCancelled()) { island.setIslandSize(event.getArgs().borderSize); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_ISLAND_SIZE_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_ISLAND_SIZE_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_ISLAND_SIZE.send(sender, targetPlayer.getName()); if (plugin.getSettings().isBuildOutsideIsland()) Message.CHANGED_ISLAND_SIZE_BUILD_OUTSIDE.send(sender); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdAdminSetSpawn implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("setspawn"); } @Override public String getPermission() { return "superior.admin.setspawn"; } @Override public String getUsage(java.util.Locale locale) { return "admin setspawn"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_SPAWN.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Player player = (Player) sender; String newSpawnLocation; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = player.getLocation(wrapper.getHandle()); location.setX(location.getBlockX()); location.setY(location.getBlockY()); location.setZ(location.getBlockZ()); // Fix to corner of a block location.add(0.5, 0, 0.5); newSpawnLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(location); } try { plugin.getSettings().updateValue("spawn.location", newSpawnLocation); plugin.getGrid().updateSpawn(); } catch (Exception error) { Log.entering("ENTER", newSpawnLocation); Log.error(error, "An unexpected error occurred while setting spawn:"); } Message.SPAWN_SET_SUCCESS.send(sender, newSpawnLocation); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetTeamLimit.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetTeamLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setteamlimit"); } @Override public String getPermission() { return "superior.admin.setteamlimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin setteamlimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getLimit(sender, args[3]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeMembersLimitEvent(island, sender, limit); if (!event.isCancelled()) { island.setTeamLimit(event.getArgs().membersLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_TEAM_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_TEAM_LIMIT_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_TEAM_LIMIT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetWarpsLimit.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetWarpsLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setwarpslimit"); } @Override public String getPermission() { return "superior.admin.setwarpslimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin setwarpslimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getLimit(sender, args[3]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); if (limit < 0) { Message.INVALID_AMOUNT.send(sender); return; } int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeWarpsLimitEvent(island, sender, limit); if (!event.isCancelled()) { island.setWarpsLimit(event.getArgs().warpsLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_WARPS_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_WARPS_LIMIT_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_WARPS_LIMIT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSettings.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuConfigEditor; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSettings implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("settings"); } @Override public String getPermission() { return "superior.admin.settings"; } @Override public String getUsage(java.util.Locale locale) { return "admin settings"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SETTINGS.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Menus.MENU_CONFIG_EDITOR.createView(plugin.getPlayers().getSuperiorPlayer(sender), MenuConfigEditor.Args.ROOT); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeBlockLimits; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeMobDrops; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeSpawnerRates; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import org.bukkit.potion.PotionEffectType; import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; public class CmdAdminShow implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("show", "info"); } @Override public String getPermission() { return "superior.admin.show"; } @Override public String getUsage(java.util.Locale locale) { return "admin show [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SHOW.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Island island = args.length == 2 ? CommandArguments.getIslandWhereStanding(plugin, sender).getIsland() : CommandArguments.getIsland(plugin, sender, args[2]).getIsland(); if (island == null) return; java.util.Locale locale = PlayerLocales.getLocale(sender); long lastTime = island.getLastTimeUpdate(); StringBuilder infoMessage = new StringBuilder(); if (!Message.ISLAND_INFO_HEADER.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_HEADER.getMessage(locale)).append("\n"); // Island owner if (!Message.ISLAND_INFO_OWNER.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_OWNER.getMessage(locale, island.getOwner().getName())).append("\n"); // Island name if (!Message.ISLAND_INFO_NAME.isEmpty(locale) && !island.getName().isEmpty()) infoMessage.append(Message.ISLAND_INFO_NAME.getMessage(locale, island.getName())).append("\n"); // Island location if (!Message.ISLAND_INFO_LOCATION.isEmpty(locale)) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); infoMessage.append(Message.ISLAND_INFO_LOCATION.getMessage(locale, Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), worldInfo))).append("\n"); } // Island last time updated if (lastTime != -1) { if (!Message.ISLAND_INFO_LAST_TIME_UPDATED.isEmpty(locale)) { infoMessage.append(Message.ISLAND_INFO_LAST_TIME_UPDATED.getMessage(locale, Formatters.TIME_FORMATTER.format( Duration.ofMillis(System.currentTimeMillis() - (lastTime * 1000)), locale))).append("\n"); } } else { if (!Message.ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE.isEmpty(locale)) { infoMessage.append(Message.ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE.getMessage(locale)).append("\n"); } } // Island rate if (!Message.ISLAND_INFO_RATE.isEmpty(locale)) { double rating = island.getTotalRating(); infoMessage.append(Message.ISLAND_INFO_RATE.getMessage(locale, Formatters.RATING_FORMATTER.format(rating, locale), Formatters.NUMBER_FORMATTER.format(rating), island.getRatingAmount())).append("\n"); } if (BuiltinModules.BANK.isEnabled()) { // Island balance if (!Message.ISLAND_INFO_BANK.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_BANK.getMessage(locale, island.getIslandBank().getBalance())).append("\n"); } // Island bonus worth if (!Message.ISLAND_INFO_BONUS.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_BONUS.getMessage(locale, island.getBonusWorth())).append("\n"); // Island bonus level if (!Message.ISLAND_INFO_BONUS_LEVEL.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_BONUS_LEVEL.getMessage(locale, island.getBonusLevel())).append("\n"); // Island worth if (!Message.ISLAND_INFO_WORTH.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_WORTH.getMessage(locale, island.getWorth())).append("\n"); // Island level if (!Message.ISLAND_INFO_LEVEL.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_LEVEL.getMessage(locale, island.getIslandLevel())).append("\n"); // Island discord if (!Message.ISLAND_INFO_DISCORD.isEmpty(locale) && !"None".equals(island.getDiscord())) { infoMessage.append(Message.ISLAND_INFO_DISCORD.getMessage(locale, island.getDiscord())).append("\n"); } // Island paypal if (!Message.ISLAND_INFO_PAYPAL.isEmpty(locale) && !"None".equals(island.getPaypal())) { infoMessage.append(Message.ISLAND_INFO_PAYPAL.getMessage(locale, island.getPaypal())).append("\n"); } boolean upgradesModule = BuiltinModules.UPGRADES.isEnabled(); if (upgradesModule) { // Island upgrades if (!Message.ISLAND_INFO_ADMIN_UPGRADES.isEmpty(locale) && !Message.ISLAND_INFO_ADMIN_UPGRADE_LINE.isEmpty(locale)) { StringBuilder upgradesString = new StringBuilder(); for (Upgrade upgrade : plugin.getUpgrades().getUpgrades()) { upgradesString.append(Message.ISLAND_INFO_ADMIN_UPGRADE_LINE.getMessage(locale, upgrade.getName(), island.getUpgradeLevel(upgrade).getLevel())).append("\n"); } infoMessage.append(Message.ISLAND_INFO_ADMIN_UPGRADES.getMessage(locale, upgradesString)); } } // Island admin size collectIslandData(locale, infoMessage, island::getIslandSize, island::getIslandSizeRaw, Message.ISLAND_INFO_ADMIN_SIZE); // Island team limit collectIslandData(locale, infoMessage, island::getTeamLimit, island::getTeamLimitRaw, Message.ISLAND_INFO_ADMIN_TEAM_LIMIT); // Island warps limit collectIslandData(locale, infoMessage, island::getWarpsLimit, island::getWarpsLimitRaw, Message.ISLAND_INFO_ADMIN_WARPS_LIMIT); // Island coop limit if (plugin.getSettings().isCoopMembers()) collectIslandData(locale, infoMessage, island::getCoopLimit, island::getCoopLimitRaw, Message.ISLAND_INFO_ADMIN_COOP_LIMIT); // Island bank limit if (BuiltinModules.BANK.isEnabled()) collectIslandData(locale, infoMessage, island::getBankLimit, island::getBankLimitRaw, Message.ISLAND_INFO_ADMIN_BANK_LIMIT, Formatters.NUMBER_FORMATTER::format); if (upgradesModule) { // Island spawners multiplier if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeSpawnerRates.class)) { collectIslandData(locale, infoMessage, island::getSpawnerRatesMultiplier, island::getSpawnerRatesRaw, Message.ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER); } // Island drops multiplier if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeMobDrops.class)) { collectIslandData(locale, infoMessage, island::getMobDropsMultiplier, island::getMobDropsRaw, Message.ISLAND_INFO_ADMIN_DROPS_MULTIPLIER); } // Island crops multiplier if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class)) { collectIslandData(locale, infoMessage, island::getCropGrowthMultiplier, island::getCropGrowthRaw, Message.ISLAND_INFO_ADMIN_CROPS_MULTIPLIER); } // Island entity limits if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class)) { collectIslandData(locale, island::getEntitiesLimitsAsKeys, island::getCustomEntitiesLimits, Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS, Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE) .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS.getMessage(locale, message))); } // Island block limits if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeBlockLimits.class)) { collectIslandData(locale, island::getBlocksLimits, island::getCustomBlocksLimits, Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS, Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE) .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS.getMessage(locale, message))); } } if (BuiltinModules.GENERATORS.isEnabled()) { // Island generator rates if (!Message.ISLAND_INFO_ADMIN_GENERATOR_RATES.isEmpty(locale) && !Message.ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE.isEmpty(locale)) { for (Dimension dimension : Dimension.values()) { Map customGeneratorValues = island.getCustomGeneratorAmounts(dimension); StringBuilder generatorString = new StringBuilder(); for (Map.Entry entry : island.getGeneratorPercentages(dimension).entrySet()) { Key key = Keys.ofMaterialAndData(entry.getKey()); generatorString.append(Message.ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE.getMessage(locale, Formatters.CAPITALIZED_FORMATTER.format(entry.getKey()), Formatters.NUMBER_FORMATTER.format(IslandUtils.getGeneratorPercentageDecimal(island, key, dimension)), island.getGeneratorAmount(key, dimension)) ); if (!customGeneratorValues.containsKey(key)) generatorString.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); generatorString.append("\n"); } if (generatorString.length() > 0) infoMessage.append(Message.ISLAND_INFO_ADMIN_GENERATOR_RATES.getMessage(locale, generatorString, Formatters.CAPITALIZED_FORMATTER.format(dimension.getName()))); } } } // Island effects if (upgradesModule && BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class)) { collectIslandData(locale, island::getPotionEffects, island::getCustomPotionEffects, Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS, Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE, PotionEffectType::getName) .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS.getMessage(locale, message))); } // Island role limits collectIslandData(locale, island::getRoleLimits, island::getCustomRoleLimits, Message.ISLAND_INFO_ADMIN_ROLE_LIMITS, Message.ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE) .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ROLE_LIMITS.getMessage(locale, message))); // Island members if (!Message.ISLAND_INFO_ROLES.isEmpty(locale)) { Map rolesStrings = new LinkedHashMap<>(); List members = island.getIslandMembers(false); if (!Message.ISLAND_INFO_PLAYER_LINE.isEmpty(locale)) { members.forEach(superiorPlayer -> rolesStrings.computeIfAbsent(superiorPlayer.getPlayerRole(), role -> new StringBuilder()) .append(Message.ISLAND_INFO_PLAYER_LINE.getMessage(locale, superiorPlayer.getName())).append("\n")); } rolesStrings.keySet().stream() .sorted(Collections.reverseOrder(Comparator.comparingInt(PlayerRole::getWeight))) .forEach(playerRole -> { StringBuilder players = rolesStrings.get(playerRole); if (players != null && players.length() > 0) infoMessage.append(Message.ISLAND_INFO_ROLES.getMessage(locale, playerRole, players)); }); } if (!Message.ISLAND_INFO_FOOTER.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_FOOTER.getMessage(locale)); Message.CUSTOM.send(sender, infoMessage.toString(), false); } private static Optional collectIslandData(Locale locale, Supplier> dataFunction, Supplier> customDataFunction, Message dataMessage, Message dataLineMessage) { return collectIslandData(locale, dataFunction, customDataFunction, dataMessage, dataLineMessage, null); } private static Optional collectIslandData(Locale locale, Supplier> dataFunction, Supplier> customDataFunction, Message dataMessage, Message dataLineMessage, @Nullable Function formatter) { if (dataMessage.isEmpty(locale) || dataLineMessage.isEmpty(locale)) return Optional.empty(); StringBuilder dataValue = new StringBuilder(); Map islandData = dataFunction.get(); Map islandCustomData = customDataFunction.get(); islandData.forEach((key, value) -> { String keyStringValue = formatter == null ? key.toString() : formatter.apply(key); dataValue.append(dataLineMessage.getMessage(locale, Formatters.CAPITALIZED_FORMATTER.format(keyStringValue), value)); if (!islandCustomData.containsKey(key)) dataValue.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); dataValue.append("\n"); }); return dataValue.length() > 0 ? Optional.of(dataValue) : Optional.empty(); } private static void collectIslandData(Locale locale, StringBuilder message, Supplier dataFunction, Supplier customDataFunction, Message dataLineMessage) { collectIslandData(locale, message, dataFunction, customDataFunction, dataLineMessage, null); } private static void collectIslandData(Locale locale, StringBuilder message, Supplier dataFunction, Supplier customDataFunction, Message dataLineMessage, @Nullable Function formatter) { if (dataLineMessage.isEmpty(locale)) return; T islandData = dataFunction.get(); T islandCustomData = customDataFunction.get(); Object formattedIslandData = formatter == null ? islandData : formatter.apply(islandData); message.append(dataLineMessage.getMessage(locale, formattedIslandData)); if (!Objects.equals(islandData, islandCustomData)) message.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); message.append("\n"); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSpawn.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdAdminSpawn implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("spawn"); } @Override public String getPermission() { return "superior.admin.spawn"; } @Override public String getUsage(java.util.Locale locale) { return "admin spawn [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SPAWN.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer targetPlayer = null; if (!(sender instanceof Player) && args.length == 2) { sender.sendMessage(ChatColor.RED + "You must specify a player to teleport."); return; } else if (args.length == 3) { targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[2]); if (targetPlayer != null && !targetPlayer.isOnline()) targetPlayer = null; } else if (sender instanceof Player) { targetPlayer = plugin.getPlayers().getSuperiorPlayer((Player) sender); } if (targetPlayer == null) { Message.INVALID_PLAYER.send(sender, args[2]); return; } targetPlayer.teleport(plugin.getGrid().getSpawnIsland()); Message.SPAWN_TELEPORT_SUCCESS.send(sender, targetPlayer.getName()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 3 ? CommandTabCompletes.getOnlinePlayers(plugin, args[2], false) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSpy.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSpy implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("spy"); } @Override public String getPermission() { return "superior.admin.spy"; } @Override public String getUsage(java.util.Locale locale) { return "admin spy"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SPY.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (!PluginEventsFactory.callPlayerToggleSpyEvent(superiorPlayer)) return; if (superiorPlayer.hasAdminSpyEnabled()) { Message.TOGGLED_SPY_OFF.send(superiorPlayer); } else { Message.TOGGLED_SPY_ON.send(superiorPlayer); } superiorPlayer.toggleAdminSpy(); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminStats.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminStats implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("stats"); } @Override public String getPermission() { return "superior.admin.stats"; } @Override public String getUsage(java.util.Locale locale) { return "admin stats"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_STATS.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { sender.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "SuperiorSkyblock" + ChatColor.GRAY + " Stats:\n" + " - Islands: " + plugin.getGrid().getSize() + "\n"); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; public class CmdAdminSyncBonus implements IAdminIslandCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Override public List getAliases() { return Collections.singletonList("syncbonus"); } @Override public String getPermission() { return "superior.admin.syncbonus"; } @Override public String getUsage(java.util.Locale locale) { return "admin syncbonus <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> "; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { boolean isWorthBonus = !args[3].equalsIgnoreCase("level"); int islandsChangedCount = 0; for (Island island : islands) { BigDecimal currentBonus = isWorthBonus ? island.getBonusWorth() : island.getBonusLevel(); BigDecimal newBonus = calculateValue(island, isWorthBonus); if (!newBonus.equals(currentBonus)) { if (isWorthBonus) { PluginEvent event = PluginEventsFactory.callIslandChangeWorthBonusEvent( island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, newBonus); if (!event.isCancelled()) { island.setBonusWorth(event.getArgs().worthBonus); ++islandsChangedCount; } } else { PluginEvent event = PluginEventsFactory.callIslandChangeLevelBonusEvent( island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, newBonus); if (!event.isCancelled()) { island.setBonusLevel(event.getArgs().levelBonus); ++islandsChangedCount; } } } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.BONUS_SYNC_ALL.send(sender); else if (targetPlayer == null) Message.BONUS_SYNC_NAME.send(sender, islands.get(0).getName()); else Message.BONUS_SYNC.send(sender, targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "worth", "level") : Collections.emptyList(); } private static BigDecimal calculateValue(Island island, boolean calculateWorth) { BigDecimal value = BigDecimal.ZERO; String generatedSchematic = island.getSchematicName(); for (Dimension dimension : Dimension.values()) { if (island.wasSchematicGenerated(dimension)) { String suffix = dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension() ? "" : "_" + dimension.getName().toLowerCase(Locale.ENGLISH); Schematic schematic = plugin.getSchematics().getSchematic(generatedSchematic + suffix); if (schematic != null) { value = value.add(_calculateValues(schematic.getBlockCounts(), calculateWorth)); } } } return value.negate(); } private static BigDecimal _calculateValues(Map blockCounts, boolean calculateWorth) { BigDecimal value = BigDecimal.ZERO; for (Map.Entry blockEntry : blockCounts.entrySet()) { BigDecimal blockValue = calculateWorth ? plugin.getBlockValues().getBlockWorth(blockEntry.getKey()) : plugin.getBlockValues().getBlockLevel(blockEntry.getKey()); if (blockValue.compareTo(BigDecimal.ZERO) > 0) { value = value.add(blockValue.multiply(new BigDecimal(blockEntry.getValue()))); } } return value; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminTeleport implements IAdminIslandCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference portalsManager = new LazyReference() { @Override protected PortalsManagerService create() { return plugin.getServices().getService(PortalsManagerService.class); } }; @Override public List getAliases() { return Arrays.asList("tp", "teleport", "go", "visit"); } @Override public String getPermission() { return "superior.admin.teleport"; } @Override public String getUsage(java.util.Locale locale) { return "admin teleport <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> [" + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_TELEPORT.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Dimension dimension; if (args.length != 4) { dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); } else { dimension = CommandArguments.getDimension(sender, args[3]); if (dimension == null) return; } if (plugin.getGrid().getIslandsWorldInfo(island, dimension) == null) { Message.WORLD_NOT_ENABLED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(dimension.getName())); return; } if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) { if (!island.wasSchematicGenerated(dimension)) { IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { Location simulatedPortalLocation = island.getCenter( plugin.getSettings().getWorlds().getDefaultWorldDimension()); Location destinationLocation = island.getCenter(dimension); portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, simulatedPortalLocation, PortalType.CUSTOM, destinationLocation, false); }); }); return; } } superiorPlayer.teleport(island, dimension, result -> { if (!result) { superiorPlayer.teleport(island.getIslandHome(dimension)); } }); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTitle.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; import java.util.Map; public class CmdAdminTitle implements IAdminPlayerCommand { private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); } }; @Override public List getAliases() { return Collections.singletonList("title"); } @Override public String getPermission() { return "superior.admin.title"; } @Override public String getUsage(java.util.Locale locale) { return "admin title <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_TITLE_FADE_IN.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_TITLE_DURATION.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_TITLE_FADE_OUT.getMessage(locale) + "> " + "-title [" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + "] " + "-subtitle [" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_TITLE.getMessage(locale); } @Override public int getMinArgs() { return 8; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { if (!targetPlayer.isOnline()) { Message.PLAYER_NOT_ONLINE.send(sender); return; } NumberArgument fadeIn = CommandArguments.getInterval(sender, args[3]); if (!fadeIn.isSucceed()) return; NumberArgument duration = CommandArguments.getInterval(sender, args[4]); if (!duration.isSucceed()) return; NumberArgument fadeOut = CommandArguments.getInterval(sender, args[5]); if (!fadeOut.isSucceed()) return; Map parsedArguments = CommandArguments.parseArguments(args); String title = parsedArguments.get("title"); String subtitle = parsedArguments.get("subtitle"); if (title == null && subtitle == null) { Message.INVALID_TITLE.send(sender); return; } Player player = targetPlayer.asPlayer(); if (!Text.isBlank(title)) title = placeholdersService.get().parsePlaceholders(player, title); if (!Text.isBlank(subtitle)) subtitle = placeholdersService.get().parsePlaceholders(player, subtitle); plugin.getNMSPlayers().sendTitle(player, title == null ? null : Formatters.COLOR_FORMATTER.format(title), subtitle == null ? null : Formatters.COLOR_FORMATTER.format(subtitle), fadeIn.getNumber(), duration.getNumber(), fadeOut.getNumber()); Message.TITLE_SENT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTitleAll.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; import java.util.Map; public class CmdAdminTitleAll implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("titleall"); } @Override public String getPermission() { return "superior.admin.titleall"; } @Override public String getUsage(java.util.Locale locale) { return "admin titleall <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_TITLE_FADE_IN.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_TITLE_DURATION.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_TITLE_FADE_OUT.getMessage(locale) + "> " + "-title [" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + "] " + "-subtitle [" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_TITLE_ALL.getMessage(locale); } @Override public int getMinArgs() { return 8; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument fadeIn = CommandArguments.getInterval(sender, args[3]); if (!fadeIn.isSucceed()) return; NumberArgument duration = CommandArguments.getInterval(sender, args[4]); if (!duration.isSucceed()) return; NumberArgument fadeOut = CommandArguments.getInterval(sender, args[5]); if (!fadeOut.isSucceed()) return; Map parsedArguments = CommandArguments.parseArguments(args); String title = parsedArguments.get("title"); String subtitle = parsedArguments.get("subtitle"); if (title == null && subtitle == null) { Message.INVALID_TITLE.send(sender); return; } islands.forEach(island -> island.sendTitle(title == null ? null : Formatters.COLOR_FORMATTER.format(title), subtitle == null ? null : Formatters.COLOR_FORMATTER.format(subtitle), fadeIn.getNumber(), duration.getNumber(), fadeOut.getNumber())); if (targetPlayer == null) Message.GLOBAL_TITLE_SENT_NAME.send(sender, islands.size() == 1 ? islands.get(0).getName() : "all"); else Message.GLOBAL_TITLE_SENT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnignore.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminUnignore implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("unignore"); } @Override public String getPermission() { return "superior.admin.unignore"; } @Override public String getUsage(java.util.Locale locale) { return "admin unignore <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_UNIGNORE.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { island.setIgnored(false); if (targetPlayer == null) Message.UNIGNORED_ISLAND_NAME.send(sender, island.getName()); else Message.UNIGNORED_ISLAND.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java ================================================ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminUnlockWorld implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("unlockworld", "world", "uworld"); } @Override public String getPermission() { return "superior.admin.world"; } @Override public String getUsage(java.util.Locale locale) { return "admin unlockworld <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "> "; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Dimension dimension = CommandArguments.getDimension(sender, args[3]); if (dimension == null) return; if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { Message.INVALID_ENVIRONMENT.send(sender, args[3]); return; } boolean unlockWorld = Boolean.parseBoolean(args[4]); if (unlockWorld) { handleWorldUnlock(sender, islands, dimension, targetPlayer, args[3]); } else { handleWorldLock(sender, islands, dimension, targetPlayer, args[3]); } } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : args.length == 5 ? CommandTabCompletes.getCustomComplete(args[4], "true", "false") : Collections.emptyList(); } private void handleWorldUnlock(CommandSender sender, List islands, Dimension dimension, @Nullable SuperiorPlayer targetPlayer, String worldType) { int islandsChangedCount = 0; for (Island island : islands) { if (!PluginEventsFactory.callIslandUnlockWorldEvent(island, sender, dimension)) continue; island.setDimensionEnabled(dimension, true); ++islandsChangedCount; } if (islandsChangedCount > 1) Message.UNLOCK_WORLD_ANNOUNCEMENT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType)); else if (targetPlayer == null) Message.UNLOCK_WORLD_ANNOUNCEMENT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), islands.get(0).getName()); else Message.UNLOCK_WORLD_ANNOUNCEMENT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), targetPlayer.getName()); } private void handleWorldLock(CommandSender sender, List islands, Dimension dimension, @Nullable SuperiorPlayer targetPlayer, String worldType) { int islandsChangedCount = 0; for (Island island : islands) { if (!PluginEventsFactory.callIslandLockWorldEvent(island, sender, dimension)) continue; island.setDimensionEnabled(dimension, false); ++islandsChangedCount; } if (islandsChangedCount > 1) Message.LOCK_WORLD_ANNOUNCEMENT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType)); else if (targetPlayer == null) Message.LOCK_WORLD_ANNOUNCEMENT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), islands.get(0).getName()); else Message.LOCK_WORLD_ANNOUNCEMENT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/Argument.java ================================================ package com.bgsoftware.superiorskyblock.commands.arguments; public abstract class Argument { protected final K k; protected final V v; protected Argument(K k, V v) { this.k = k; this.v = v; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java ================================================ package com.bgsoftware.superiorskyblock.commands.arguments; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; public class CommandArguments { private CommandArguments() { } public static IslandArgument getIsland(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(argument); Island island = targetPlayer == null ? plugin.getGrid().getIsland(argument) : targetPlayer.getIsland(); if (island == null) { if (argument.equalsIgnoreCase(sender.getName())) Message.INVALID_ISLAND.send(sender); else if (targetPlayer == null) Message.INVALID_ISLAND_OTHER_NAME.send(sender, Formatters.STRIP_COLOR_FORMATTER.format(argument)); else Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName()); } return new IslandArgument(island, targetPlayer); } public static IslandsListArgument getMultipleIslands(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { List islands = new LinkedList<>(); SuperiorPlayer targetPlayer; if (argument.equals("*")) { targetPlayer = null; islands = plugin.getGrid().getIslands(); } else { IslandArgument arguments = getIsland(plugin, sender, argument); targetPlayer = arguments.getSuperiorPlayer(); if (arguments.getIsland() != null) islands.add(arguments.getIsland()); } return new IslandsListArgument(Collections.unmodifiableList(islands), targetPlayer); } public static IslandArgument getSenderIsland(SuperiorSkyblockPlugin plugin, CommandSender sender) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Island island = superiorPlayer.getIsland(); if (island == null) Message.INVALID_ISLAND.send(superiorPlayer); return new IslandArgument(island, superiorPlayer); } public static SuperiorPlayer getPlayer(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, String argument) { return getPlayer(plugin, superiorPlayer.asPlayer(), argument); } public static SuperiorPlayer getPlayer(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(argument); if (targetPlayer == null) Message.INVALID_PLAYER.send(sender, argument); return targetPlayer; } public static List getMultiplePlayers(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { List players = new LinkedList<>(); if (argument.equals("*")) { players = plugin.getPlayers().getAllPlayers(); } else { SuperiorPlayer targetPlayer = getPlayer(plugin, sender, argument); if (targetPlayer != null) players.add(targetPlayer); } return Collections.unmodifiableList(players); } public static IslandArgument getIslandWhereStanding(SuperiorSkyblockPlugin plugin, CommandSender sender) { if (!(sender instanceof Player)) { Message.CUSTOM.send(sender, "&cYou must specify a player's name.", true); return IslandArgument.EMPTY; } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Island locationIsland = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle())); island = locationIsland == null || locationIsland.isSpawn() ? superiorPlayer.getIsland() : locationIsland; } if (island == null) Message.INVALID_ISLAND.send(sender); return new IslandArgument(island, superiorPlayer); } public static Mission getMission(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, String argument) { return getMission(plugin, superiorPlayer.asPlayer(), argument); } public static Mission getMission(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { Mission mission = plugin.getMissions().getMission(argument); if (mission == null) Message.INVALID_MISSION.send(sender, argument); return mission; } public static List> getMultipleMissions(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { List> missions = new LinkedList<>(); if (argument.equals("*")) { missions = plugin.getMissions().getAllMissions(); } else { Mission mission = getMission(plugin, sender, argument); if (mission != null) missions.add(mission); } return Collections.unmodifiableList(missions); } public static MissionCategory getMissionCategory(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { MissionCategory missionCategory = plugin.getMissions().getMissionCategory(argument); if (missionCategory == null) Message.INVALID_MISSION_CATEGORY.send(sender, argument); return missionCategory; } public static Upgrade getUpgrade(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, String argument) { return getUpgrade(plugin, superiorPlayer.asPlayer(), argument); } public static Upgrade getUpgrade(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { Upgrade upgrade = plugin.getUpgrades().getUpgrade(argument); if (upgrade == null) { Message.INVALID_UPGRADE.send(sender, argument, plugin.getUpgrades().getUpgradesNames()); } return upgrade; } public static String buildLongString(String[] args, int start, boolean colorize) { StringBuilder stringBuilder = new StringBuilder(); for (int i = start; i < args.length; i++) stringBuilder.append(" ").append(args[i]); return colorize ? Formatters.COLOR_FORMATTER.format(stringBuilder.substring(1)) : stringBuilder.substring(1); } public static PlayerRole getPlayerRole(CommandSender sender, String argument) { PlayerRole playerRole = null; try { playerRole = SPlayerRole.of(argument); } catch (IllegalArgumentException ignored) { } if (playerRole == null) { Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getAllRoleNames()); } return playerRole; } public static PlayerRole getPlayerRoleFromLadder(CommandSender sender, String argument) { PlayerRole playerRole = null; try { playerRole = SPlayerRole.of(argument); } catch (IllegalArgumentException ignored) { } if (playerRole == null || !playerRole.isRoleLadder()) { Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getRolesLadderNames()); playerRole = null; } return playerRole; } public static PlayerRole getPlayerRoleForLimit(CommandSender sender, String argument) { PlayerRole playerRole = null; try { playerRole = SPlayerRole.of(argument); } catch (IllegalArgumentException ignored) { } if (playerRole == null || !IslandUtils.isValidRoleForLimit(playerRole)) { Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getRoleLimitsNames()); playerRole = null; } return playerRole; } public static NumberArgument getLimit(CommandSender sender, String argument) { return getInt(sender, argument, Message.INVALID_LIMIT); } public static BigDecimal getBigDecimalAmount(CommandSender sender, String argument) { BigDecimal amount = null; try { amount = new BigDecimal(argument); } catch (NumberFormatException ex) { Message.INVALID_AMOUNT.send(sender); } return amount; } public static NumberArgument getAmount(CommandSender sender, String argument) { return getInt(sender, argument, Message.INVALID_AMOUNT); } public static NumberArgument getMultiplier(CommandSender sender, String argument) { double multiplier = 0; boolean status = true; try { multiplier = Double.parseDouble(argument); // Makes sure the multiplier is rounded. multiplier = Math.round(multiplier * 100) / 100D; } catch (IllegalArgumentException ex) { Message.INVALID_MULTIPLIER.send(sender, argument); status = false; } return new NumberArgument<>(multiplier, status); } public static PotionEffectType getPotionEffect(CommandSender sender, String argument) { PotionEffectType potionEffectType = PotionEffectType.getByName(argument.toUpperCase(Locale.ENGLISH)); if (potionEffectType == null) Message.INVALID_EFFECT.send(sender, argument); return potionEffectType; } public static NumberArgument getLevel(CommandSender sender, String argument) { return getInt(sender, argument, Message.INVALID_LEVEL); } public static Material getMaterial(CommandSender sender, String argument) { Material material = null; try { material = Material.valueOf(argument.split(":")[0].toUpperCase(Locale.ENGLISH)); } catch (Exception ex) { Message.INVALID_MATERIAL.send(sender, argument); } return material; } public static NumberArgument getSize(CommandSender sender, String argument) { return getInt(sender, argument, Message.INVALID_SIZE); } public static IslandWarp getWarp(CommandSender sender, Island island, String[] args, int start) { String warpName = buildLongString(args, start, false); IslandWarp islandWarp = island.getWarp(warpName); if (islandWarp == null) Message.INVALID_WARP.send(sender, warpName); return islandWarp; } public static Biome getBiome(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { Biome biome = plugin.getNMSAlgorithms().getBiome(argument); if (biome == null) { Message.INVALID_BIOME.send(sender, argument); } return biome; } public static World getWorld(CommandSender sender, String argument) { World world = Bukkit.getWorld(argument); if (world == null) Message.INVALID_WORLD.send(sender, argument); return world; } public static Location getLocation(CommandSender sender, World world, String x, String y, String z) { Location location = null; try { location = new Location(world, Integer.parseInt(x), Integer.parseInt(y), Integer.parseInt(z)); } catch (Throwable ex) { Message.INVALID_BLOCK.send(sender, world.getName() + ", " + x + ", " + y + ", " + z); } return location; } public static NumberArgument getPage(CommandSender sender, String argument) { return getInt(sender, argument, Message.INVALID_PAGE); } public static NumberArgument getRows(CommandSender sender, String argument) { return getInt(sender, argument, Message.INVALID_ROWS); } public static IslandPrivilege getIslandPrivilege(CommandSender sender, String argument) { IslandPrivilege islandPrivilege = null; try { islandPrivilege = IslandPrivilege.getByName(argument); } catch (NullPointerException ignored) { } if (islandPrivilege == null) { Message.INVALID_ISLAND_PERMISSION.send(sender, argument, IslandPrivileges.getPrivilegesNames()); } return islandPrivilege; } public static Rating getRating(CommandSender sender, String argument) { Rating rating = null; try { rating = Rating.valueOf(argument.toUpperCase(Locale.ENGLISH)); } catch (Exception ex) { Message.INVALID_RATE.send(sender, argument, Rating.getValuesString()); } return rating; } public static IslandFlag getIslandFlag(CommandSender sender, String argument) { IslandFlag islandFlag = null; try { islandFlag = IslandFlag.getByName(argument); } catch (NullPointerException ignored) { } if (islandFlag == null) { Message.INVALID_SETTINGS.send(sender, argument, IslandFlags.getFlagsNames()); } return islandFlag; } public static Dimension getDimension(CommandSender sender, String argument) { Dimension dimension = null; try { dimension = Dimension.getByName(argument.toUpperCase(Locale.ENGLISH)); } catch (Exception ignored) { } if (dimension == null) Message.INVALID_ENVIRONMENT.send(sender, argument); return dimension; } public static Schematic getSchematic(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { Schematic schematic = plugin.getSchematics().getSchematic(argument); if (schematic == null || argument.endsWith("_nether") || argument.endsWith("_normal") || argument.endsWith("_the_end")) { Message.INVALID_SCHEMATIC.send(sender, argument); return null; } return schematic; } public static NumberArgument getInterval(CommandSender sender, String argument) { NumberArgument interval = getInt(sender, argument, Message.INVALID_INTERVAL); if (interval.isSucceed() && interval.getNumber() < 0) { Message.INVALID_INTERVAL.send(sender, argument); return new NumberArgument<>(interval.getNumber(), false); } return interval; } public static Map parseArguments(String[] args) { Map parsedArgs = new HashMap<>(); String currentKey = null; StringBuilder stringBuilder = new StringBuilder(); for (String arg : args) { if (arg.startsWith("-")) { if (currentKey != null && stringBuilder.length() > 0) { parsedArgs.put(currentKey, stringBuilder.substring(1)); } currentKey = arg.substring(1).toLowerCase(Locale.ENGLISH); stringBuilder = new StringBuilder(); } else if (currentKey != null) { stringBuilder.append(" ").append(arg); } } if (currentKey != null && stringBuilder.length() > 0) { parsedArgs.put(currentKey, stringBuilder.substring(1)); } return parsedArgs; } public static BorderColor getBorderColor(CommandSender sender, String argument) { BorderColor borderColor = null; try { borderColor = BorderColor.valueOf(argument.toUpperCase(Locale.ENGLISH)); } catch (Exception ignored) { } if (borderColor == null) Message.INVALID_BORDER_COLOR.send(sender, argument); return borderColor; } private static NumberArgument getInt(CommandSender sender, String argument, Message locale) { int i = 0; boolean status = true; try { i = Integer.parseInt(argument); } catch (IllegalArgumentException ex) { locale.send(sender, argument); status = false; } return new NumberArgument<>(i, status); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/IslandArgument.java ================================================ package com.bgsoftware.superiorskyblock.commands.arguments; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public class IslandArgument extends Argument { public static final IslandArgument EMPTY = new IslandArgument(null, null); public IslandArgument(@Nullable Island island, SuperiorPlayer superiorPlayer) { super(island, superiorPlayer); } @Nullable public Island getIsland() { return super.k; } public SuperiorPlayer getSuperiorPlayer() { return super.v; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/IslandsListArgument.java ================================================ package com.bgsoftware.superiorskyblock.commands.arguments; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.List; public class IslandsListArgument extends Argument, SuperiorPlayer> { public IslandsListArgument(List islands, @Nullable SuperiorPlayer superiorPlayer) { super(islands, superiorPlayer); } public List getIslands() { return super.k; } @Nullable public SuperiorPlayer getSuperiorPlayer() { return super.v; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/NumberArgument.java ================================================ package com.bgsoftware.superiorskyblock.commands.arguments; public class NumberArgument extends Argument { public NumberArgument(N number, boolean succeed) { super(number, succeed); } public N getNumber() { return super.k; } public boolean isSucceed() { return super.v; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAccept implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("accept", "join"); } @Override public String getPermission() { return "superior.island.accept"; } @Override public String getUsage(java.util.Locale locale) { return "accept [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ACCEPT.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); SuperiorPlayer targetPlayer; Island island; if (args.length == 1) { List playerPendingInvites = superiorPlayer.getInvites(); island = playerPendingInvites.isEmpty() ? null : playerPendingInvites.get(0); targetPlayer = null; } else { targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[1]); island = targetPlayer == null ? plugin.getGrid().getIsland(args[1]) : targetPlayer.getIsland(); } if (island == null || !island.isInvited(superiorPlayer)) { Message.NO_ISLAND_INVITE.send(superiorPlayer); return; } if (superiorPlayer.getIsland() != null) { Message.JOIN_WHILE_IN_ISLAND.send(superiorPlayer); return; } int teamLimit = island.getTeamLimit(); if (teamLimit >= 0 && island.getIslandMembers(true).size() >= teamLimit) { Message.JOIN_FULL_ISLAND.send(superiorPlayer); island.revokeInvite(superiorPlayer); return; } if (!PluginEventsFactory.callIslandJoinEvent(island, superiorPlayer, IslandJoinEvent.Cause.INVITE)) return; IslandUtils.sendMessage(island, Message.JOIN_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); island.addMember(superiorPlayer, SPlayerRole.defaultRole()); if (targetPlayer == null) Message.JOINED_ISLAND_NAME.send(superiorPlayer, island.getName()); else Message.JOINED_ISLAND.send(superiorPlayer, targetPlayer.getName()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) -> onlineIsland.isInvited(superiorPlayer)) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.commands.CommandsHelper; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; public class CmdAdmin implements ISuperiorCommand { private static final Int2ObjectMapView> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap(); public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CmdAdmin::onCommandsRefresh); dispatcher.registerCallback(PluginEventType.COMMANDS_UPDATE_EVENT, CmdAdmin::onCommandsRefresh); } private static void onCommandsRefresh() { commandsPerPageCache.clear(); } @Override public List getAliases() { return Collections.singletonList("admin"); } @Override public String getPermission() { return "superior.admin"; } @Override public String getUsage(java.util.Locale locale) { return "admin [" + Message.COMMAND_ARGUMENT_PAGE.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { java.util.Locale locale = PlayerLocales.getLocale(sender); if (args.length > 1 && !isNumber(args[1])) { String executedSubCommand = args[1]; Log.debug(Debug.EXECUTE_COMMAND, sender.getName(), executedSubCommand); SuperiorCommand command = plugin.getCommands().getAdminCommand(executedSubCommand); if (command != null) { if (!(sender instanceof Player) && !command.canBeExecutedByConsole()) { Message.CUSTOM.send(sender, "&cCan be executed only by players!", true); return; } if (!CommandsHelper.hasCommandAccess(command, sender)) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Missing Permission", command.getPermission()); if (!plugin.getSettings().isHelpOnNoPermission()) Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission()); else plugin.getCommands().dispatchSubCommand(sender, "admin"); return; } if (args.length < command.getMinArgs() || args.length > command.getMaxArgs()) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Incorrect Usage", command.getUsage(locale)); Message.COMMAND_USAGE.send(sender, locale, plugin.getCommands().getLabel() + " " + command.getUsage(locale)); return; } command.execute(plugin, sender, args); return; } if (!plugin.getSettings().isHelpOnInvalidCommand()) Message.INVALID_COMMAND.send(sender, locale, executedSubCommand); else plugin.getCommands().dispatchSubCommand(sender, "admin"); return; } int page = 1; if (args.length == 2) { try { page = Integer.parseInt(args[1]); } catch (IllegalArgumentException ex) { Message.INVALID_AMOUNT.send(sender, args[1]); return; } } if (page <= 0) { Message.INVALID_AMOUNT.send(sender, page); return; } List subCommands = new SequentialListBuilder() .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) .build(plugin.getCommands().getAdminSubCommands()); if (subCommands.isEmpty()) { Message.NO_COMMAND_PERMISSION.send(sender, locale, getPermission()); return; } int commandsPerPageCount = plugin.getSettings().getCommandsPerPage(); int lastPage; if (commandsPerPageCount > 0) { lastPage = subCommands.size() / commandsPerPageCount; if (subCommands.size() % commandsPerPageCount != 0) lastPage++; } else { lastPage = 1; } if (page > lastPage) { Message.INVALID_AMOUNT.send(sender, page); return; } Message.ADMIN_HELP_HEADER.send(sender, locale, page, lastPage); List commandsOfPage; if (commandsPerPageCount > 0) { commandsOfPage = commandsPerPageCache.get(page); if (commandsOfPage == null) { commandsOfPage = subCommands.subList((page - 1) * commandsPerPageCount, Math.min(subCommands.size(), page * commandsPerPageCount)); commandsPerPageCache.put(page, commandsOfPage); } } else { commandsOfPage = subCommands; } for (SuperiorCommand subCommand : commandsOfPage) { String description = subCommand.getDescription(locale); if (description == null) new NullPointerException("The description of the command " + subCommand.getAliases().get(0) + " is null.").printStackTrace(); Message.ADMIN_HELP_LINE.send(sender, locale, plugin.getCommands().getLabel() + " " + subCommand.getUsage(locale), description); } if (page != lastPage) Message.ADMIN_HELP_NEXT_PAGE.send(sender, locale, page + 1); else Message.ADMIN_HELP_FOOTER.send(sender, locale); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { if (args.length > 1) { SuperiorCommand command = plugin.getCommands().getAdminCommand(args[1]); if (command != null) { return CommandsHelper.hasCommandAccess(command, sender) ? command.tabComplete(plugin, sender, args) : Collections.emptyList(); } } else if (args.length == 1) { return Collections.emptyList(); } List list = new LinkedList<>(); for (SuperiorCommand subCommand : plugin.getCommands().getAdminSubCommands()) { if (CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) { List aliases = new LinkedList<>(subCommand.getAliases()); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(aliases.get(0).toLowerCase(Locale.ENGLISH), Collections.emptyList())); for (String alias : aliases) { if (alias.contains(args[1].toLowerCase(Locale.ENGLISH))) { list.add(alias); } } } } return list.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(list); } private boolean isNumber(String str) { try { Integer.valueOf(str); return true; } catch (NumberFormatException ex) { return false; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Collections; import java.util.List; public class CmdBan implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("ban"); } @Override public String getPermission() { return "superior.island.ban"; } @Override public String getUsage(java.util.Locale locale) { return "ban <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_BAN.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.BAN_MEMBER; } @Override public Message getPermissionLackMessage() { return Message.NO_BAN_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (!IslandUtils.checkBanRestrictions(superiorPlayer, island, targetPlayer)) return; if (plugin.getSettings().isBanConfirm()) { plugin.getMenus().openConfirmBan(superiorPlayer, null, island, targetPlayer); } else { IslandUtils.handleBanPlayer(superiorPlayer, island, targetPlayer); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), onlinePlayer -> !island.isBanned(onlinePlayer) && (!island.isMember(onlinePlayer) || onlinePlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole()))) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBans.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdBans implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("bans", "banlist"); } @Override public String getPermission() { return "superior.island.bans"; } @Override public String getUsage(java.util.Locale locale) { return "bans"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_BANS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); plugin.getMenus().openIslandBannedPlayers(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBiome.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.Arrays; import java.util.List; public class CmdBiome implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("biome", "setbiome"); } @Override public String getPermission() { return "superior.island.biome"; } @Override public String getUsage(java.util.Locale locale) { return "biome"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_BIOME.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.SET_BIOME; } @Override public Message getPermissionLackMessage() { return Message.NO_SET_BIOME_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { plugin.getMenus().openBiomes(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), superiorPlayer.getIsland()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBorder.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdBorder implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("border"); } @Override public String getPermission() { return "superior.island.border"; } @Override public String getUsage(java.util.Locale locale) { return "border [" + Message.COMMAND_ARGUMENT_BORDER_COLOR.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_BORDER.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (args.length != 2) { plugin.getMenus().openBorderColor(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); return; } BorderColor borderColor = CommandArguments.getBorderColor(sender, args[1]); if (borderColor == null) return; IslandUtils.handleBorderColorUpdate(superiorPlayer, borderColor); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length != 2 ? Collections.emptyList() : CommandTabCompletes.getBorderColors(args[1]); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdChest.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.IntStream; public class CmdChest implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("chest", "vault"); } @Override public String getPermission() { return "superior.island.chest"; } @Override public String getUsage(java.util.Locale locale) { return "chest [" + Message.COMMAND_ARGUMENT_PAGE.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_CHEST.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.ISLAND_CHEST; } @Override public Message getPermissionLackMessage() { return Message.NO_ISLAND_CHEST_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { if (args.length == 2) { NumberArgument pageArguments = CommandArguments.getPage(superiorPlayer.asPlayer(), args[1]); if (!pageArguments.isSucceed()) return; int page = pageArguments.getNumber() - 1; IslandChest[] islandChests = island.getChest(); if (page < 0 || page >= islandChests.length) { Message.INVALID_PAGE.send(superiorPlayer, args[1]); return; } islandChests[page].openChest(superiorPlayer); } else { plugin.getMenus().openIslandChest(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { IslandChest[] islandChests = island.getChest(); return args.length == 1 || islandChests.length == 0 ? Collections.emptyList() : CommandTabCompletes.getCustomComplete(args[1], IntStream.range(1, islandChests.length + 1).boxed() .map(Object::toString).toArray(String[]::new)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.List; public class CmdClose implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("close", "lock"); } @Override public String getPermission() { return "superior.island.close"; } @Override public String getUsage(java.util.Locale locale) { return "close"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_CLOSE.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.CLOSE_ISLAND; } @Override public Message getPermissionLackMessage() { return Message.NO_CLOSE_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { if (island.isLocked()) { Message.ISLAND_ALREADY_CLOSED.send(superiorPlayer); } else if (PluginEventsFactory.callIslandCloseEvent(island, superiorPlayer)) { island.setLocked(true); Message.ISLAND_CLOSED.send(superiorPlayer); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdCoop implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("coop", "trust"); } @Override public String getPermission() { return "superior.island.coop"; } @Override public String getUsage(java.util.Locale locale) { return "coop <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_COOP.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.COOP_MEMBER; } @Override public Message getPermissionLackMessage() { return Message.NO_COOP_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (!targetPlayer.isOnline()) { Message.INVALID_PLAYER.send(superiorPlayer, args[1]); return; } if (island.isMember(targetPlayer)) { Message.ALREADY_IN_ISLAND_OTHER.send(superiorPlayer); return; } if (island.isCoop(targetPlayer)) { Message.PLAYER_ALREADY_COOP.send(superiorPlayer); return; } if (island.isBanned(targetPlayer)) { Message.COOP_BANNED_PLAYER.send(superiorPlayer); return; } int coopLimit = island.getCoopLimit(); if (coopLimit >= 0 && island.getCoopPlayers().size() >= coopLimit) { Message.COOP_LIMIT_EXCEED.send(superiorPlayer); return; } if (!PluginEventsFactory.callIslandCoopPlayerEvent(island, superiorPlayer, targetPlayer)) return; island.addCoop(targetPlayer); IslandUtils.sendMessage(island, Message.COOP_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName(), targetPlayer.getName()); if (island.getName().isEmpty()) Message.JOINED_ISLAND_AS_COOP.send(targetPlayer, superiorPlayer.getName()); else Message.JOINED_ISLAND_AS_COOP_NAME.send(targetPlayer, island.getName()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), onlinePlayer -> !island.isMember(onlinePlayer) && !island.isBanned(onlinePlayer) && !island.isCoop(onlinePlayer)) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoops.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdCoops implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("coops"); } @Override public String getPermission() { return "superior.island.coops"; } @Override public String getUsage(java.util.Locale locale) { return "coops"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_COOPS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); plugin.getMenus().openCoops(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCounts.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdCounts implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("counts", "blocks"); } @Override public String getPermission() { return "superior.island.counts"; } @Override public String getUsage(java.util.Locale locale) { return "counts [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_COUNTS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Island island = (args.length == 1 ? CommandArguments.getSenderIsland(plugin, sender) : CommandArguments.getIsland(plugin, sender, args[1])).getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); plugin.getMenus().openCounts(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1], plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandNames; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdCreate implements ISuperiorCommand { private final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Override public List getAliases() { return Collections.singletonList("create"); } @Override public String getPermission() { return "superior.island.create"; } @Override public String getUsage(java.util.Locale locale) { StringBuilder usage = new StringBuilder("create"); if (plugin.getSettings().getIslandNames().isRequiredForCreation()) usage.append(" <").append(Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale)).append(">"); if (plugin.getSettings().isSchematicNameArgument()) usage.append(" [").append(Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale)).append("]"); return usage.toString(); } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_CREATE.getMessage(locale); } @Override public int getMinArgs() { return plugin.getSettings().getIslandNames().isRequiredForCreation() ? 2 : 1; } @Override public int getMaxArgs() { int args = 3; if (!plugin.getSettings().getIslandNames().isRequiredForCreation()) args--; if (!plugin.getSettings().isSchematicNameArgument()) args--; return args; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (superiorPlayer.getIsland() != null) { Message.ALREADY_IN_ISLAND.send(superiorPlayer); return; } if (plugin.getGrid().hasActiveCreateRequest(superiorPlayer)) { Message.ISLAND_CREATE_PROCESS_FAIL.send(superiorPlayer); return; } String islandName = ""; Schematic schematic = null; if (plugin.getSettings().getIslandNames().isRequiredForCreation()) { if (args.length >= 2) { islandName = args[1]; if (!IslandNames.isValidName(sender, null, islandName)) return; } } if (plugin.getSettings().isSchematicNameArgument() && args.length == (plugin.getSettings().getIslandNames().isRequiredForCreation() ? 3 : 2)) { schematic = CommandArguments.getSchematic(plugin, sender, args[plugin.getSettings().getIslandNames().isRequiredForCreation() ? 2 : 1]); if (schematic == null) return; } if (schematic == null) { plugin.getMenus().openIslandCreation(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), islandName); } else { MenuIslandCreationConfig creationConfig = plugin.getProviders().getMenusProvider().getIslandCreationConfig(schematic); MenuActions.simulateIslandCreationClick(superiorPlayer, islandName, creationConfig, false, superiorPlayer.getOpenedView()); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { int argumentLength = plugin.getSettings().getIslandNames().isRequiredForCreation() ? 3 : 2; return plugin.getSettings().isSchematicNameArgument() && args.length == argumentLength ? CommandTabCompletes.getSchematics(plugin, args[argumentLength - 1]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.warp.SignWarp; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdDelWarp implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("delwarp"); } @Override public String getPermission() { return "superior.island.delwarp"; } @Override public String getUsage(java.util.Locale locale) { return "delwarp <" + Message.COMMAND_ARGUMENT_WARP_NAME.getMessage(locale) + "...>"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_DEL_WARP.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.DELETE_WARP; } @Override public Message getPermissionLackMessage() { return Message.NO_DELETE_WARP_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { Player player = superiorPlayer.asPlayer(); IslandWarp islandWarp = CommandArguments.getWarp(player, island, args, 1); if (islandWarp == null) return; if (!PluginEventsFactory.callIslandDeleteWarpEvent(island, superiorPlayer, islandWarp)) return; island.deleteWarp(islandWarp.getName()); Message.DELETE_WARP.send(superiorPlayer, islandWarp.getName()); SignWarp.trySignWarpBreak(islandWarp, player); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getIslandWarps(island, args[1]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import java.util.Collections; import java.util.List; public class CmdDemote implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("demote"); } @Override public String getPermission() { return "superior.island.demote"; } @Override public String getUsage(java.util.Locale locale) { return "demote <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_DEMOTE.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.DEMOTE_MEMBERS; } @Override public Message getPermissionLackMessage() { return Message.NO_DEMOTE_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (!island.isMember(targetPlayer)) { Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer); return; } if (!targetPlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole())) { Message.DEMOTE_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer); return; } PlayerRole previousRole = targetPlayer.getPlayerRole(); int roleLimit; do { previousRole = previousRole.getPreviousRole(); roleLimit = previousRole == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : island.getRoleLimit(previousRole); } while (previousRole != null && !previousRole.isFirstRole() && roleLimit >= 0 && roleLimit >= island.getIslandMembers(previousRole).size()); if (previousRole == null) { Message.LAST_ROLE_DEMOTE.send(superiorPlayer); return; } if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, previousRole)) return; targetPlayer.setPlayerRole(previousRole); Message.DEMOTED_MEMBER.send(superiorPlayer, targetPlayer.getName(), targetPlayer.getPlayerRole()); Message.GOT_DEMOTED.send(targetPlayer, targetPlayer.getPlayerRole()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getIslandMembers(island, args[1], islandMember -> islandMember.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole()) && islandMember.getPlayerRole().getPreviousRole() != null) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import java.math.BigDecimal; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdDisband implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("disband", "reset", "delete"); } @Override public String getPermission() { return "superior.island.disband"; } @Override public String getUsage(java.util.Locale locale) { return "disband"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_DISBAND.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.DISBAND_ISLAND; } @Override public Message getPermissionLackMessage() { return Message.NO_DISBAND_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { if (!superiorPlayer.hasDisbands() && plugin.getSettings().getDisbandCount() >= 0) { Message.NO_MORE_DISBANDS.send(superiorPlayer); return; } if (plugin.getSettings().isDisbandConfirm()) { plugin.getMenus().openConfirmDisband(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } else if (PluginEventsFactory.callIslandDisbandEvent(island, superiorPlayer)) { IslandUtils.sendMessage(island, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); Message.DISBANDED_ISLAND.send(superiorPlayer); if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); Message.DISBAND_ISLAND_BALANCE_REFUND.send(island.getOwner(), Formatters.NUMBER_FORMATTER.format( island.getIslandBank().getBalance().multiply(disbandRefund))); } if (plugin.getSettings().getDisbandCount() >= 0) { superiorPlayer.setDisbands(superiorPlayer.getDisbands() - 1); } island.disbandIsland(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdExpel.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdExpel implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("expel"); } @Override public String getPermission() { return "superior.island.expel"; } @Override public String getUsage(java.util.Locale locale) { return "expel <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_EXPEL.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.EXPEL_PLAYERS; } @Override public Message getPermissionLackMessage() { return Message.NO_EXPEL_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island playerIsland, String[] args) { CommandSender sender = superiorPlayer == null ? Bukkit.getConsoleSender() : superiorPlayer.asPlayer(); SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[1]); if (targetPlayer == null || sender == null) return; Player target = targetPlayer.asPlayer(); if (target == null) { Message.INVALID_PLAYER.send(sender, args[1]); return; } Island targetIsland; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { targetIsland = plugin.getGrid().getIslandAt(target.getLocation(wrapper.getHandle())); } if (targetIsland == null) { Message.PLAYER_NOT_INSIDE_ISLAND.send(sender); return; } // Checking requirements for players if (superiorPlayer != null) { if (!targetIsland.equals(playerIsland)) { Message.PLAYER_NOT_INSIDE_ISLAND.send(sender); return; } if (targetIsland.hasPermission(targetPlayer, IslandPrivileges.EXPEL_BYPASS)) { Message.PLAYER_EXPEL_BYPASS.send(sender); return; } } targetPlayer.teleport(plugin.getGrid().getSpawnIsland()); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { target.getLocation(wrapper.getHandle()).setDirection(plugin.getGrid().getSpawnIsland() .getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getDirection()); } Message.EXPELLED_PLAYER.send(sender, targetPlayer.getName()); Message.GOT_EXPELLED.send(targetPlayer, sender.getName()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { if (args.length != 2) return Collections.emptyList(); if (island != null) return CommandTabCompletes.getIslandVisitors(island, args[1], plugin.getSettings().isTabCompleteHideVanished()); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), onlinePlayer -> plugin.getGrid().getIslandAt(onlinePlayer.getLocation(wrapper.getHandle())) != null); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdFly implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("fly"); } @Override public String getPermission() { return "superior.island.fly"; } @Override public String getUsage(java.util.Locale locale) { return "fly"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_FLY.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (!PluginEventsFactory.callPlayerToggleFlyEvent(superiorPlayer)) return; Player player = (Player) sender; if (superiorPlayer.hasIslandFlyEnabled()) { player.setAllowFlight(false); player.setFlying(false); Message.TOGGLED_FLY_OFF.send(superiorPlayer); } else { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } if (island != null && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { player.setAllowFlight(true); player.setFlying(true); } Message.TOGGLED_FLY_ON.send(superiorPlayer); } superiorPlayer.toggleIslandFly(); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.commands.CommandsHelper; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class CmdHelp implements ISuperiorCommand { private static final Int2ObjectMapView> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap(); public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CmdHelp::onCommandsRefresh); dispatcher.registerCallback(PluginEventType.COMMANDS_UPDATE_EVENT, CmdHelp::onCommandsRefresh); } private static void onCommandsRefresh() { commandsPerPageCache.clear(); } @Override public List getAliases() { return Collections.singletonList("help"); } @Override public String getPermission() { return "superior.island.help"; } @Override public String getUsage(java.util.Locale locale) { return "help [" + Message.COMMAND_ARGUMENT_PAGE.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_HELP.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { int page = 1; if (args.length == 2) { try { page = Integer.parseInt(args[1]); } catch (IllegalArgumentException ex) { Message.INVALID_AMOUNT.send(sender, args[1]); return; } } if (page <= 0) { Message.INVALID_AMOUNT.send(sender, page); return; } List subCommands = new SequentialListBuilder() .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) .build(plugin.getCommands().getSubCommands()); if (subCommands.isEmpty()) { Message.NO_COMMAND_PERMISSION.send(sender, getPermission()); return; } int commandsPerPageCount = plugin.getSettings().getCommandsPerPage(); int lastPage; if (commandsPerPageCount > 0) { lastPage = subCommands.size() / commandsPerPageCount; if (subCommands.size() % commandsPerPageCount != 0) lastPage++; } else { lastPage = 1; } if (page > lastPage) { Message.INVALID_AMOUNT.send(sender, page); return; } Message.ISLAND_HELP_HEADER.send(sender, page, lastPage); java.util.Locale locale = PlayerLocales.getLocale(sender); List commandsOfPage; if (commandsPerPageCount > 0) { commandsOfPage = commandsPerPageCache.get(page); if (commandsOfPage == null) { commandsOfPage = subCommands.subList((page - 1) * commandsPerPageCount, Math.min(subCommands.size(), page * commandsPerPageCount)); commandsPerPageCache.put(page, commandsOfPage); } } else { commandsOfPage = subCommands; } for (SuperiorCommand subCommand : commandsOfPage) { String description = subCommand.getDescription(locale); if (description == null) new NullPointerException("The description of the command " + subCommand.getAliases().get(0) + " is null.").printStackTrace(); Message.ISLAND_HELP_LINE.send(sender, plugin.getCommands().getLabel() + " " + subCommand.getUsage(locale), description == null ? "" : description); } if (page != lastPage) Message.ISLAND_HELP_NEXT_PAGE.send(sender, page + 1); else Message.ISLAND_HELP_FOOTER.send(sender); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { if (args.length != 2) return Collections.emptyList(); List list = new LinkedList<>(); List subCommands = new SequentialListBuilder() .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) .build(plugin.getCommands().getSubCommands()); int commandsPerPageCount = plugin.getSettings().getCommandsPerPage(); int lastPage; if (commandsPerPageCount > 0) { lastPage = subCommands.size() / commandsPerPageCount; if (subCommands.size() % commandsPerPageCount != 0) lastPage++; } else { lastPage = 1; } for (int i = 1; i <= lastPage; i++) list.add(i + ""); return Collections.unmodifiableList(list); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdInvite implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("invite", "add"); } @Override public String getPermission() { return "superior.island.invite"; } @Override public String getUsage(java.util.Locale locale) { return "invite <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_INVITE.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.INVITE_MEMBER; } @Override public Message getPermissionLackMessage() { return Message.NO_INVITE_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (island.isMember(targetPlayer)) { Message.ALREADY_IN_ISLAND_OTHER.send(superiorPlayer); return; } if (island.isBanned(targetPlayer)) { Message.INVITE_BANNED_PLAYER.send(superiorPlayer); return; } Message announcementMessage; if (island.isInvited(targetPlayer)) { island.revokeInvite(targetPlayer); announcementMessage = Message.REVOKE_INVITE_ANNOUNCEMENT; Message.GOT_REVOKED.send(targetPlayer, superiorPlayer.getName()); } else { int teamLimit = island.getTeamLimit(); if (teamLimit >= 0 && island.getIslandMembers(true).size() >= teamLimit) { Message.INVITE_TO_FULL_ISLAND.send(superiorPlayer); return; } if (!PluginEventsFactory.callIslandInviteEvent(island, superiorPlayer, targetPlayer)) return; island.inviteMember(targetPlayer); announcementMessage = Message.INVITE_ANNOUNCEMENT; Message.GOT_INVITE.send(targetPlayer, superiorPlayer.getName()); } IslandUtils.sendMessage(island, announcementMessage, Collections.emptyList(), superiorPlayer.getName(), targetPlayer.getName()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), onlinePlayer -> !island.isMember(onlinePlayer)) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdKick.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdKick implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("kick", "remove"); } @Override public String getPermission() { return "superior.island.kick"; } @Override public String getUsage(java.util.Locale locale) { return "kick <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_KICK.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.KICK_MEMBER; } @Override public Message getPermissionLackMessage() { return Message.NO_KICK_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (!IslandUtils.checkKickRestrictions(superiorPlayer, island, targetPlayer)) return; if (plugin.getSettings().isKickConfirm()) { plugin.getMenus().openConfirmKick(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island, targetPlayer); } else { IslandUtils.handleKickPlayer(superiorPlayer, island, targetPlayer); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getIslandMembersWithLowerRole(island, args[1], superiorPlayer.getPlayerRole()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLang.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdLang implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("lang", "language"); } @Override public String getPermission() { return "superior.island.lang"; } @Override public String getUsage(java.util.Locale locale) { return "lang"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_LANG.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); plugin.getMenus().openPlayerLanguage(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdLeave implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("leave"); } @Override public String getPermission() { return "superior.island.leave"; } @Override public String getUsage(java.util.Locale locale) { return "leave"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_LEAVE.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); if (superiorPlayer.getPlayerRole().getNextRole() == null) { Message.LEAVE_ISLAND_AS_LEADER.send(superiorPlayer); return; } if (plugin.getSettings().isLeaveConfirm()) { plugin.getMenus().openConfirmLeave(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); } else { IslandUtils.handleLeaveIsland(superiorPlayer, island); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdMembers.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdMembers implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("members"); } @Override public String getPermission() { return "superior.island.members"; } @Override public String getUsage(java.util.Locale locale) { return "members"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_MEMBERS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); plugin.getMenus().openMembers(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.List; public class CmdName implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("name", "setname", "rename"); } @Override public String getPermission() { return "superior.island.name"; } @Override public String getUsage(java.util.Locale locale) { return "name <" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_NAME.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.CHANGE_NAME; } @Override public Message getPermissionLackMessage() { return Message.NO_NAME_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { PluginEvent event = PluginEventsFactory.callIslandRenameEvent(island, superiorPlayer, args[1]); if (event.isCancelled()) return; String islandName = event.getArgs().islandName; if (!IslandNames.isValidName(superiorPlayer, island, islandName)) return; island.setName(islandName); String coloredName = island.getName(); IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT, superiorPlayer.getName(), coloredName); Message.CHANGED_NAME.send(superiorPlayer, coloredName); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.List; public class CmdOpen implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("open", "unlock"); } @Override public String getPermission() { return "superior.island.open"; } @Override public String getUsage(java.util.Locale locale) { return "open"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_OPEN.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.OPEN_ISLAND; } @Override public Message getPermissionLackMessage() { return Message.NO_OPEN_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { if (!island.isLocked()) { Message.ISLAND_ALREADY_OPENED.send(superiorPlayer); } else if (PluginEventsFactory.callIslandOpenEvent(island, superiorPlayer)) { island.setLocked(false); Message.ISLAND_OPENED.send(superiorPlayer); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class CmdPanel implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("panel", "manager", "cp"); } @Override public String getPermission() { return "superior.island.panel"; } @Override public String getUsage(java.util.Locale locale) { return "panel [members/visitors] [toggle]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_PANEL.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); if (args.length > 1) { if (args[1].equalsIgnoreCase("members")) { plugin.getCommands().dispatchSubCommand(sender, "members"); return; } else if (args[1].equalsIgnoreCase("visitors")) { plugin.getCommands().dispatchSubCommand(sender, "visitors"); return; } else if (args[1].equalsIgnoreCase("toggle")) { if (!PluginEventsFactory.callPlayerTogglePanelEvent(superiorPlayer)) return; if (superiorPlayer.hasToggledPanel()) { superiorPlayer.setToggledPanel(false); Message.PANEL_TOGGLE_OFF.send(superiorPlayer); } else { superiorPlayer.setToggledPanel(true); Message.PANEL_TOGGLE_ON.send(superiorPlayer); } return; } } plugin.getMenus().openControlPanel(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { if (args.length != 2) return Collections.emptyList(); List extraArgument = new LinkedList<>(); extraArgument.add("toggle"); if (!(sender instanceof Player)) { extraArgument.add("visitors"); extraArgument.add("members"); } else { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (superiorPlayer.hasPermission("superior.island.visitors")) extraArgument.add("visitors"); if (superiorPlayer.hasPermission("superior.island.members")) extraArgument.add("members"); } return CommandTabCompletes.getCustomComplete(args[1], extraArgument); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPardon.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdPardon implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("pardon", "unban"); } @Override public String getPermission() { return "superior.island.pardon"; } @Override public String getUsage(java.util.Locale locale) { return "pardon <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_PARDON.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.BAN_MEMBER; } @Override public Message getPermissionLackMessage() { return Message.NO_BAN_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (!island.isBanned(targetPlayer)) { Message.PLAYER_NOT_BANNED.send(superiorPlayer); return; } if (!PluginEventsFactory.callIslandUnbanEvent(island, superiorPlayer, targetPlayer)) return; island.unbanMember(targetPlayer); IslandUtils.sendMessage(island, Message.UNBAN_ANNOUNCEMENT, Collections.emptyList(), targetPlayer.getName(), superiorPlayer.getName()); Message.GOT_UNBANNED.send(targetPlayer, island.getOwner().getName()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getIslandBannedPlayers(island, args[1]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; public class CmdPermissions implements IPermissibleCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Override public List getAliases() { return Arrays.asList("permissions", "perms", "setpermission", "setperm"); } @Override public String getPermission() { return "superior.island.permissions"; } @Override public String getUsage(java.util.Locale locale) { if (plugin.getSettings().isEditPlayerPermissions()) { return "permissions [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "] [reset]"; } else { return "permissions [reset]"; } } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_PERMISSIONS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return plugin.getSettings().isEditPlayerPermissions() ? 3 : 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.SET_PERMISSION; } @Override public Message getPermissionLackMessage() { return Message.NO_PERMISSION_CHECK_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { Object permissionHolder = SPlayerRole.guestRole(); boolean setToDefault = (args.length == 2 ? args[1] : args.length == 3 ? args[2] : "").equalsIgnoreCase("reset"); if (plugin.getSettings().isEditPlayerPermissions() && ((!setToDefault && args.length == 2) || args.length == 3)) { SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[1]); if (targetPlayer == null) { Message.INVALID_PLAYER.send(superiorPlayer, args[1]); return; } if (island.isMember(targetPlayer) && !superiorPlayer.getPlayerRole().isHigherThan(targetPlayer.getPlayerRole())) { Message.CHANGE_PERMISSION_FOR_HIGHER_ROLE.send(superiorPlayer); return; } permissionHolder = targetPlayer; } if (!setToDefault) { if (permissionHolder instanceof PlayerRole) { plugin.getMenus().openPermissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island, (PlayerRole) permissionHolder); } else { plugin.getMenus().openPermissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island, (SuperiorPlayer) permissionHolder); } } else { if (permissionHolder instanceof PlayerRole) { if (PluginEventsFactory.callIslandClearRolesPrivilegesEvent(island, superiorPlayer)) { island.resetPermissions(); Message.PERMISSIONS_RESET_ROLES.send(superiorPlayer); } } else { if (PluginEventsFactory.callIslandClearPlayerPrivilegesEvent(island, superiorPlayer, (SuperiorPlayer) permissionHolder)) { island.resetPermissions((SuperiorPlayer) permissionHolder); Message.PERMISSIONS_RESET_PLAYER.send(superiorPlayer, ((SuperiorPlayer) permissionHolder).getName()); } } } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { List tabVariables = new LinkedList<>(); if (args.length == 2) { if ("reset".contains(args[1].toLowerCase(Locale.ENGLISH))) tabVariables.add("reset"); if (plugin.getSettings().isEditPlayerPermissions()) { tabVariables.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished())); } } else if (plugin.getSettings().isEditPlayerPermissions() && args.length == 3) { if ("reset".contains(args[2].toLowerCase(Locale.ENGLISH))) tabVariables.add("reset"); } return Collections.unmodifiableList(tabVariables); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import java.util.Collections; import java.util.List; public class CmdPromote implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("promote"); } @Override public String getPermission() { return "superior.island.promote"; } @Override public String getUsage(java.util.Locale locale) { return "promote <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_PROMOTE.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.PROMOTE_MEMBERS; } @Override public Message getPermissionLackMessage() { return Message.NO_PROMOTE_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (!island.isMember(targetPlayer)) { Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer); return; } PlayerRole playerRole = targetPlayer.getPlayerRole(); if (playerRole.isLastRole()) { Message.LAST_ROLE_PROMOTE.send(superiorPlayer); return; } if (!playerRole.isLessThan(superiorPlayer.getPlayerRole())) { Message.PROMOTE_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer); return; } PlayerRole nextRole = playerRole; int roleLimit; do { nextRole = nextRole.getNextRole(); roleLimit = nextRole == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : island.getRoleLimit(nextRole); } while (nextRole != null && !nextRole.isLastRole() && !nextRole.isHigherThan(superiorPlayer.getPlayerRole()) && roleLimit >= 0 && island.getIslandMembers(nextRole).size() >= roleLimit); if (nextRole == null || nextRole.isLastRole()) { Message.LAST_ROLE_PROMOTE.send(superiorPlayer); return; } if (nextRole.isHigherThan(superiorPlayer.getPlayerRole())) { Message.PROMOTE_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer); return; } if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, nextRole)) return; targetPlayer.setPlayerRole(nextRole); Message.PROMOTED_MEMBER.send(superiorPlayer, targetPlayer.getName(), targetPlayer.getPlayerRole()); Message.GOT_PROMOTED.send(targetPlayer, targetPlayer.getPlayerRole()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length != 2 ? Collections.emptyList() : CommandTabCompletes.getIslandMembers(island, args[1], islandMember -> { PlayerRole playerRole = islandMember.getPlayerRole(); PlayerRole nextRole = playerRole.getNextRole(); return nextRole != null && !nextRole.isLastRole() && playerRole.isLessThan(superiorPlayer.getPlayerRole()) && !nextRole.isHigherThan(superiorPlayer.getPlayerRole()); }); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdRate implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("rate"); } @Override public String getPermission() { return "superior.island.rate"; } @Override public String getUsage(java.util.Locale locale) { return "rate [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_RATE.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = args.length == 1 ? CommandArguments.getIslandWhereStanding(plugin, sender) : CommandArguments.getIsland(plugin, sender, args[1]); Island island = arguments.getIsland(); if (island == null) return; if (island.isSpawn()) { Message.INVALID_ISLAND_LOCATION.send(sender); return; } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); RateResult rateResult = canRateIsland(plugin, superiorPlayer, island); switch (rateResult) { case RATE_OWN_ISLAND: Message.RATE_OWN_ISLAND.send(superiorPlayer); return; case ALREADY_RATED: Message.RATE_ALREADY_GIVEN.send(superiorPlayer); return; } plugin.getMenus().openIslandRate(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Island island = superiorPlayer.getIsland(); return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) -> canRateIsland(plugin, superiorPlayer, island, onlineIsland) == RateResult.SUCCESS) : Collections.emptyList(); } private static RateResult canRateIsland(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island) { return canRateIsland(plugin, superiorPlayer, superiorPlayer.getIsland(), island); } private static RateResult canRateIsland(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island playerIsland, Island island) { if (!plugin.getSettings().isRateOwnIsland() && island.equals(playerIsland)) { return RateResult.RATE_OWN_ISLAND; } if (!plugin.getSettings().isChangeIslandRating() && island.getRating(superiorPlayer) != Rating.UNKNOWN) { return RateResult.ALREADY_RATED; } return RateResult.SUCCESS; } private enum RateResult { SUCCESS, RATE_OWN_ISLAND, ALREADY_RATED } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRatings.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Collections; import java.util.List; public class CmdRatings implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("ratings"); } @Override public String getPermission() { return "superior.island.ratings"; } @Override public String getUsage(java.util.Locale locale) { return "ratings"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_RATINGS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.RATINGS_SHOW; } @Override public Message getPermissionLackMessage() { return Message.NO_RATINGS_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { plugin.getMenus().openIslandRatings(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRecalc.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdRecalc implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("recalc", "recalculate", "level"); } @Override public String getPermission() { return "superior.island.recalc"; } @Override public String getUsage(java.util.Locale locale) { return "recalc"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_RECALC.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); if (island.isBeingRecalculated()) { Message.RECALC_ALREADY_RUNNING.send(superiorPlayer); return; } Message.RECALC_PROCCESS_REQUEST.send(superiorPlayer); island.calcIslandWorth(superiorPlayer); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetDiscord.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Collections; import java.util.List; public class CmdSetDiscord implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("setdiscord"); } @Override public String getPermission() { return "superior.island.setdiscord"; } @Override public String getUsage(java.util.Locale locale) { return "setdiscord <" + Message.COMMAND_ARGUMENT_DISCORD.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_SET_DISCORD.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.SET_DISCORD; } @Override public Message getPermissionLackMessage() { return Message.NO_SET_DISCORD_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { String discord = CommandArguments.buildLongString(args, 1, false); PluginEvent event = PluginEventsFactory.callIslandChangeDiscordEvent(island, superiorPlayer, discord); if (event.isCancelled()) return; island.setDiscord(event.getArgs().discord); Message.CHANGED_DISCORD.send(superiorPlayer, event.getArgs().discord); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetPaypal.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Collections; import java.util.List; public class CmdSetPaypal implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("setpaypal"); } @Override public String getPermission() { return "superior.island.setpaypal"; } @Override public String getUsage(java.util.Locale locale) { return "setpaypal <" + Message.COMMAND_ARGUMENT_EMAIL.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_SET_PAYPAL.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.SET_PAYPAL; } @Override public Message getPermissionLackMessage() { return Message.NO_SET_PAYPAL_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { PluginEvent event = PluginEventsFactory.callIslandChangePaypalEvent(island, superiorPlayer, args[1]); if (event.isCancelled()) return; island.setPaypal(event.getArgs().paypal); Message.CHANGED_PAYPAL.send(superiorPlayer, event.getArgs().paypal); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdSetRole implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("setrole"); } @Override public String getPermission() { return "superior.island.setrole"; } @Override public String getUsage(java.util.Locale locale) { return "setrole <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_ISLAND_ROLE.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_SET_ROLE.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.SET_ROLE; } @Override public Message getPermissionLackMessage() { return Message.NO_SET_ROLE_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island playerIsland, String[] args) { CommandSender sender = superiorPlayer == null ? Bukkit.getConsoleSender() : superiorPlayer.asPlayer(); SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, sender, args[1]); if (targetPlayer == null || sender == null) return; if (targetPlayer.getName().equals(sender.getName())) { Message.SELF_ROLE_CHANGE.send(sender); return; } PlayerRole playerRole = CommandArguments.getPlayerRoleFromLadder(sender, args[2]); if (playerRole == null) return; Island targetIsland = targetPlayer.getIsland(); // Checking requirements for players if (superiorPlayer != null) { if (!playerIsland.isMember(targetPlayer)) { Message.PLAYER_NOT_INSIDE_ISLAND.send(sender); return; } targetIsland = playerIsland; if (targetPlayer.getPlayerRole().isHigherThan(superiorPlayer.getPlayerRole()) || !playerRole.isLessThan(superiorPlayer.getPlayerRole())) { Message.CANNOT_SET_ROLE.send(sender, playerRole); return; } } else { if (targetIsland == null) { Message.INVALID_ISLAND_OTHER.send(sender, targetPlayer.getName()); return; } if (playerRole.isLastRole()) { Message.CANNOT_SET_ROLE.send(sender, playerRole); return; } } if (targetPlayer.getPlayerRole().equals(playerRole)) { Message.PLAYER_ALREADY_IN_ROLE.send(sender, targetPlayer.getName(), playerRole); return; } int roleLimit = targetIsland.getRoleLimit(playerRole); if (roleLimit >= 0 && targetIsland.getIslandMembers(playerRole).size() >= roleLimit) { Message.CANNOT_SET_ROLE.send(sender, playerRole); return; } PlayerRole currentRole = targetPlayer.getPlayerRole(); if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, playerRole)) return; targetPlayer.setPlayerRole(playerRole); if (currentRole.isLessThan(playerRole)) { Message.PROMOTED_MEMBER.send(sender, targetPlayer.getName(), targetPlayer.getPlayerRole()); Message.GOT_PROMOTED.send(targetPlayer, targetPlayer.getPlayerRole()); } else { Message.DEMOTED_MEMBER.send(sender, targetPlayer.getName(), targetPlayer.getPlayerRole()); Message.GOT_DEMOTED.send(targetPlayer, targetPlayer.getPlayerRole()); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? island == null ? CommandTabCompletes.getOnlinePlayers(plugin, args[1], false, onlinePlayer -> onlinePlayer.getIsland() != null) : CommandTabCompletes.getIslandMembers(island, args[1]) : args.length == 3 ? CommandTabCompletes.getPlayerRoles(plugin, args[2], PlayerRole::isRoleLadder) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Location; import java.util.Arrays; import java.util.List; public class CmdSetTeleport implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("setteleport", "settp", "setgo", "sethome"); } @Override public String getPermission() { return "superior.island.setteleport"; } @Override public String getUsage(java.util.Locale locale) { return "setteleport"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_SET_TELEPORT.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.SET_HOME; } @Override public Message getPermissionLackMessage() { return Message.NO_SET_HOME_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location newLocation = superiorPlayer.getLocation(wrapper.getHandle()); if (!island.isInsideRange(newLocation)) { Message.TELEPORT_LOCATION_OUTSIDE_ISLAND.send(superiorPlayer); return; } PluginEvent event = PluginEventsFactory.callIslandSetHomeEvent( island, superiorPlayer, newLocation, IslandSetHomeEvent.Reason.SET_HOME_COMMAND); if (event.isCancelled()) return; island.setIslandHome(event.getArgs().islandHome); } Message.CHANGED_TELEPORT_LOCATION.send(superiorPlayer); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.google.common.base.Preconditions; import org.bukkit.Location; import java.util.Collections; import java.util.List; public class CmdSetWarp implements IPermissibleCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Override public List getAliases() { return Collections.singletonList("setwarp"); } @Override public String getPermission() { return "superior.island.setwarp"; } @Override public String getUsage(java.util.Locale locale) { StringBuilder usage = new StringBuilder("setwarp <") .append(Message.COMMAND_ARGUMENT_WARP_NAME.getMessage(locale)).append(">"); if (plugin.getSettings().isWarpCategories()) usage.append(" [").append(Message.COMMAND_ARGUMENT_WARP_CATEGORY.getMessage(locale)).append("]"); return usage.toString(); } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_SET_WARP.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return plugin.getSettings().isWarpCategories() ? 3 : 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.SET_WARP; } @Override public Message getPermissionLackMessage() { return Message.NO_SET_WARP_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { int warpsLimit = island.getWarpsLimit(); if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) { Message.NO_MORE_WARPS.send(superiorPlayer); return; } String warpName = args[1]; if (warpName.isEmpty()) { Message.WARP_ILLEGAL_NAME.send(superiorPlayer); return; } if (!IslandUtils.isWarpNameLengthValid(warpName)) { Message.WARP_NAME_TOO_LONG.send(superiorPlayer); return; } if (island.getWarp(warpName) != null) { Message.WARP_ALREADY_EXIST.send(superiorPlayer); return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (!island.isInsideRange(superiorPlayer.getLocation(wrapper.getHandle()))) { Message.SET_WARP_OUTSIDE.send(superiorPlayer); return; } } String categoryName = null; if (args.length == 3) { categoryName = args[2]; if (categoryName.isEmpty()) { Message.WARP_CATEGORY_ILLEGAL_NAME.send(superiorPlayer); return; } if (!IslandUtils.isWarpNameLengthValid(categoryName)) { Message.WARP_CATEGORY_NAME_TOO_LONG.send(superiorPlayer); return; } if (island.getWarpCategory(categoryName) == null && !PluginEventsFactory.callIslandCreateWarpCategoryEvent(island, superiorPlayer, categoryName)) return; } WarpCategory warpCategory = categoryName == null ? null : island.createWarpCategory(categoryName); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location warpLocation = superiorPlayer.getLocation(wrapper.getHandle()); Preconditions.checkState(warpLocation != null, "Null location for a warp."); if (!PluginEventsFactory.callIslandCreateWarpEvent(island, superiorPlayer, warpName, warpLocation, warpCategory)) return; island.createWarp(warpName, warpLocation, warpCategory); Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(warpLocation)); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Collections; import java.util.List; public class CmdSettings implements IPermissibleCommand { @Override public List getAliases() { return Collections.singletonList("settings"); } @Override public String getPermission() { return "superior.island.settings"; } @Override public String getUsage(java.util.Locale locale) { return "settings [reset]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_SETTINGS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.SET_SETTINGS; } @Override public Message getPermissionLackMessage() { return Message.NO_SET_SETTINGS_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { if (args.length == 2 && args[1].equalsIgnoreCase("reset")) { if (PluginEventsFactory.callIslandClearFlagsEvent(island, superiorPlayer)) { island.resetSettings(); Message.SETTINGS_RESET_SELF.send(superiorPlayer); } return; } plugin.getMenus().openSettings(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], "reset") : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; public class CmdShow implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("show", "info"); } @Override public String getPermission() { return "superior.island.show"; } @Override public String getUsage(java.util.Locale locale) { return "show [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_SHOW.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Island island = args.length == 1 ? CommandArguments.getIslandWhereStanding(plugin, sender).getIsland() : CommandArguments.getIsland(plugin, sender, args[1]).getIsland(); if (island == null) return; java.util.Locale locale = PlayerLocales.getLocale(sender); StringBuilder infoMessage = new StringBuilder(); if (!Message.ISLAND_INFO_HEADER.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_HEADER.getMessage(locale)).append("\n"); if (!Message.ISLAND_INFO_OWNER.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_OWNER.getMessage(locale, island.getOwner().getName())).append("\n"); if (!Message.ISLAND_INFO_NAME.isEmpty(locale) && !island.getName().isEmpty()) infoMessage.append(Message.ISLAND_INFO_NAME.getMessage(locale, island.getName())).append("\n"); if (!Message.ISLAND_INFO_LOCATION.isEmpty(locale)) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); infoMessage.append(Message.ISLAND_INFO_LOCATION.getMessage(locale, Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), worldInfo))).append("\n"); } if (!Message.ISLAND_INFO_CREATION_TIME.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_CREATION_TIME.getMessage(locale, island.getCreationTimeDate())).append("\n"); if (!Message.ISLAND_INFO_RATE.isEmpty(locale)) { double rating = island.getTotalRating(); infoMessage.append(Message.ISLAND_INFO_RATE.getMessage(locale, Formatters.RATING_FORMATTER.format(rating, locale), Formatters.NUMBER_FORMATTER.format(rating), island.getRatingAmount())).append("\n"); } if (BuiltinModules.BANK.isEnabled()) { if (!Message.ISLAND_INFO_BANK.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_BANK.getMessage(locale, island.getIslandBank().getBalance())).append("\n"); } if (!Message.ISLAND_INFO_WORTH.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_WORTH.getMessage(locale, island.getWorth())).append("\n"); if (!Message.ISLAND_INFO_LEVEL.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_LEVEL.getMessage(locale, island.getIslandLevel())).append("\n"); if (!Message.ISLAND_INFO_DISCORD.isEmpty(locale) && !"None".equals(island.getDiscord()) && island.hasPermission(sender, IslandPrivileges.DISCORD_SHOW)) { infoMessage.append(Message.ISLAND_INFO_DISCORD.getMessage(locale, island.getDiscord())).append("\n"); } if (!Message.ISLAND_INFO_PAYPAL.isEmpty(locale) && !"None".equals(island.getPaypal()) && island.hasPermission(sender, IslandPrivileges.PAYPAL_SHOW)) { infoMessage.append(Message.ISLAND_INFO_PAYPAL.getMessage(locale, island.getPaypal())).append("\n"); } if (!Message.ISLAND_INFO_VISITORS_COUNT.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_VISITORS_COUNT.getMessage(locale, island.getIslandVisitors(false).size(), island.getUniqueVisitorsWithTimes().size())).append("\n"); if (!Message.ISLAND_INFO_ROLES.isEmpty(locale)) { Map rolesStrings = new ArrayMap<>(); plugin.getRoles().getRoles().stream().filter(playerRole -> playerRole.isRoleLadder() && !playerRole.isLastRole()) .forEach(playerRole -> rolesStrings.put(playerRole, new StringBuilder())); List members = island.getIslandMembers(false); if (!Message.ISLAND_INFO_PLAYER_LINE.isEmpty(locale)) { members.forEach(superiorPlayer -> { try { rolesStrings.get(superiorPlayer.getPlayerRole()) .append(Message.ISLAND_INFO_PLAYER_LINE.getMessage(locale, superiorPlayer.getName())).append("\n"); } catch (NullPointerException ex) { Log.warn("It seems like ", superiorPlayer.getName(), " isn't part of the island of " , island.getOwner().getName(), "."); } }); } rolesStrings.keySet().stream() .sorted(Collections.reverseOrder(Comparator.comparingInt(PlayerRole::getWeight))) .forEach(playerRole -> { StringBuilder players = rolesStrings.get(playerRole); if (players != null && players.length() > 0) infoMessage.append(Message.ISLAND_INFO_ROLES.getMessage(locale, playerRole, players)); }); } if (!Message.ISLAND_INFO_FOOTER.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_FOOTER.getMessage(locale)); Message.CUSTOM.send(sender, infoMessage.toString(), false); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1], plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeam.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; public class CmdTeam implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("team", "showteam", "online"); } @Override public String getPermission() { return "superior.island.team"; } @Override public String getUsage(java.util.Locale locale) { return "team [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_TEAM.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Island island = (args.length == 1 ? CommandArguments.getSenderIsland(plugin, sender) : CommandArguments.getIsland(plugin, sender, args[1])).getIsland(); if (island == null) return; BukkitExecutor.async(() -> { java.util.Locale locale = PlayerLocales.getLocale(sender); StringBuilder infoMessage = new StringBuilder(); if (!Message.ISLAND_TEAM_STATUS_HEADER.isEmpty(locale)) { infoMessage.append(Message.ISLAND_TEAM_STATUS_HEADER.getMessage(locale, island.getOwner().getName(), island.getIslandMembers(true).size(), island.getTeamLimit())).append("\n"); } List members = island.getIslandMembers(true); if (!Message.ISLAND_TEAM_STATUS_ROLES.isEmpty(locale)) { Map rolesStrings = new ArrayMap<>(); plugin.getRoles().getRoles().stream().filter(PlayerRole::isRoleLadder) .forEach(playerRole -> rolesStrings.put(playerRole, new StringBuilder())); rolesStrings.put(SPlayerRole.lastRole(), new StringBuilder()); String onlineStatus = Message.ISLAND_TEAM_STATUS_ONLINE.getMessage(locale), offlineStatus = Message.ISLAND_TEAM_STATUS_OFFLINE.getMessage(locale); members.forEach(islandMember -> { PlayerRole playerRole = islandMember.getPlayerRole(); long time = islandMember.getLastTimeStatus() == -1 ? -1 : ((System.currentTimeMillis() / 1000) - islandMember.getLastTimeStatus()); boolean onlinePlayer = islandMember.isOnline() && islandMember.isShownAsOnline(); rolesStrings.get(playerRole).append(Message.ISLAND_TEAM_STATUS_ROLES.getMessage(locale, playerRole, islandMember.getName(), onlinePlayer ? onlineStatus : offlineStatus, Formatters.TIME_FORMATTER.format(Duration.ofSeconds(time), locale))).append("\n"); }); rolesStrings.keySet().stream() .sorted(Collections.reverseOrder(Comparator.comparingInt(PlayerRole::getWeight))) .forEach(playerRole -> infoMessage.append(rolesStrings.get(playerRole))); } if (!Message.ISLAND_TEAM_STATUS_FOOTER.isEmpty(locale)) infoMessage.append(Message.ISLAND_TEAM_STATUS_FOOTER.getMessage(locale)); Message.CUSTOM.send(sender, infoMessage.toString(), false); }); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1], plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdTeamChat implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("teamchat", "chat", "tc"); } @Override public String getPermission() { return "superior.island.teamchat"; } @Override public String getUsage(java.util.Locale locale) { return "teamchat [" + Message.COMMAND_ARGUMENT_MESSAGE.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_TEAM_CHAT.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return Integer.MAX_VALUE; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); if (args.length == 1) { if (!PluginEventsFactory.callPlayerToggleTeamChatEvent(superiorPlayer)) return; if (superiorPlayer.hasTeamChatEnabled()) { Message.TOGGLED_TEAM_CHAT_OFF.send(superiorPlayer); } else { Message.TOGGLED_TEAM_CHAT_ON.send(superiorPlayer); } superiorPlayer.toggleTeamChat(); } else { String message = CommandArguments.buildLongString(args, 1, false); IslandUtils.handleIslandChat(island, superiorPlayer, message); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdTeleport implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("teleport", "tp", "go", "home"); } @Override public String getPermission() { return "superior.island.teleport"; } @Override public String getUsage(java.util.Locale locale) { return "teleport"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_TELEPORT.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); if (!PluginEventsFactory.callIslandHomeTeleportEvent(island, superiorPlayer, dimension)) return; EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getHomeWarmup(), unused -> teleportToIsland(superiorPlayer, island)); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } private void teleportToIsland(SuperiorPlayer superiorPlayer, Island island) { superiorPlayer.setTeleportTask(null); superiorPlayer.teleport(island, result -> { if (result) Message.TELEPORTED_SUCCESS.send(superiorPlayer); else Message.TELEPORTED_FAILED.send(superiorPlayer); }); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdToggle implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("toggle"); } @Override public String getPermission() { return "superior.island.toggle"; } @Override public String getUsage(java.util.Locale locale) { return "toggle "; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_TOGGLE.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (args[1].equalsIgnoreCase("border")) { if (!superiorPlayer.hasPermission("superior.island.toggle.border")) { Message.NO_COMMAND_PERMISSION.send(sender, "superior.island.toggle.border"); return; } if (!PluginEventsFactory.callPlayerToggleBorderEvent(superiorPlayer)) return; if (superiorPlayer.hasWorldBorderEnabled()) { Message.TOGGLED_WORLD_BORDER_OFF.send(superiorPlayer); } else { Message.TOGGLED_WORLD_BORDER_ON.send(superiorPlayer); } superiorPlayer.toggleWorldBorder(); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { superiorPlayer.updateWorldBorder(plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle()))); } } else if (args[1].equalsIgnoreCase("blocks")) { if (!superiorPlayer.hasPermission("superior.island.toggle.blocks")) { Message.NO_COMMAND_PERMISSION.send(sender, "superior.island.toggle.blocks"); return; } if (!PluginEventsFactory.callPlayerToggleBlocksStackerEvent(superiorPlayer)) return; if (superiorPlayer.hasBlocksStackerEnabled()) { Message.TOGGLED_STACKED_BLOCKS_OFF.send(superiorPlayer); } else { Message.TOGGLED_STACKED_BLOCKS_ON.send(superiorPlayer); } superiorPlayer.toggleBlocksStacker(); } else { Message.INVALID_TOGGLE_MODE.send(superiorPlayer, args[1]); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], var -> sender.hasPermission("superior.island.toggle." + var), "border", "blocks") : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTop.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdTop implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("top"); } @Override public String getPermission() { return "superior.island.top"; } @Override public String getUsage(java.util.Locale locale) { return "top"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_TOP.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); plugin.getMenus().openTopIslands(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), SortingTypes.getIslandTopSorting()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTransfer.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdTransfer implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("transfer", "leader", "leadership"); } @Override public String getPermission() { return "superior.island.transfer"; } @Override public String getUsage(java.util.Locale locale) { return "transfer <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_TRANSFER.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (!IslandUtils.checkTransferRestrictions(superiorPlayer, island, targetPlayer)) return; if (plugin.getSettings().isTransferConfirm()) { plugin.getMenus().openConfirmTransfer(superiorPlayer, null, island, targetPlayer); } else { IslandUtils.handleTransferIsland(superiorPlayer, island, targetPlayer); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Island island = superiorPlayer.getIsland(); return args.length == 2 && island != null && superiorPlayer.getPlayerRole().isLastRole() ? CommandTabCompletes.getIslandMembers(island, args[1]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdUncoop.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdUncoop implements IPermissibleCommand { @Override public List getAliases() { return Arrays.asList("uncoop", "untrust"); } @Override public String getPermission() { return "superior.island.uncoop"; } @Override public String getUsage(java.util.Locale locale) { return "uncoop <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_UNCOOP.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.UNCOOP_MEMBER; } @Override public Message getPermissionLackMessage() { return Message.NO_UNCOOP_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; if (!island.isCoop(targetPlayer)) { Message.PLAYER_NOT_COOP.send(superiorPlayer); return; } if (!PluginEventsFactory.callIslandUncoopPlayerEvent(island, superiorPlayer, targetPlayer, IslandUncoopPlayerEvent.UncoopReason.PLAYER)) return; island.removeCoop(targetPlayer); IslandUtils.sendMessage(island, Message.UNCOOP_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName(), targetPlayer.getName()); if (island.getName().isEmpty()) Message.LEFT_ISLAND_COOP.send(targetPlayer, superiorPlayer.getName()); else Message.LEFT_ISLAND_COOP_NAME.send(targetPlayer, island.getName()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), island::isCoop) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdValue.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.CustomKey; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class CmdValue implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("value"); } @Override public String getPermission() { return "superior.island.value"; } @Override public String getUsage(java.util.Locale locale) { return "value [" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_VALUE.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Key toCheck; String keyName = ""; if (args.length == 1) { ItemStack inHand = ((Player) sender).getItemInHand(); if (inHand == null) { inHand = new ItemStack(Material.AIR); } toCheck = Keys.of(inHand); if (inHand.getType() == Materials.SPAWNER.toBukkitType()) { String subKey = toCheck.getSubKey(); if (!Text.isBlank(subKey)) keyName = Formatters.CAPITALIZED_FORMATTER.format(subKey + "_Spawner"); } if (keyName.isEmpty() && toCheck instanceof CustomKey) { String subKey = toCheck.getSubKey(); if (Text.isBlank(subKey)) { keyName = Formatters.CAPITALIZED_FORMATTER.format(toCheck.toString()); } else { keyName = Formatters.CAPITALIZED_FORMATTER.format(subKey); } } } else { toCheck = Keys.ofMaterialAndData(args[1]); } if (keyName.isEmpty()) keyName = Formatters.CAPITALIZED_FORMATTER.format(toCheck.getGlobalKey()); java.util.Locale locale = superiorPlayer.getUserLocale(); StringBuilder stringBuilder = new StringBuilder(); BlockValue blockValue = plugin.getBlockValues().getBlockValue(toCheck); { BigDecimal blockWorth = blockValue.getWorth(); if (blockWorth.doubleValue() == 0) { if (!Message.BLOCK_VALUE_WORTHLESS.isEmpty(locale)) stringBuilder.append(Message.BLOCK_VALUE_WORTHLESS.getMessage(locale, keyName)).append("\n"); } else { if (!Message.BLOCK_VALUE.isEmpty(locale)) stringBuilder.append(Message.BLOCK_VALUE.getMessage(locale, keyName, Formatters.NUMBER_FORMATTER.format(blockWorth))).append("\n"); } } { BigDecimal blockLevel = blockValue.getLevel(); if (blockLevel.doubleValue() == 0) { if (!Message.BLOCK_LEVEL_WORTHLESS.isEmpty(locale)) { stringBuilder.append(Message.BLOCK_LEVEL_WORTHLESS.getMessage(locale, keyName)).append("\n"); } } else { if (!Message.BLOCK_LEVEL.isEmpty(locale)) stringBuilder.append(Message.BLOCK_LEVEL.getMessage(locale, keyName, Formatters.NUMBER_FORMATTER.format(blockLevel))).append("\n"); } } Message.CUSTOM.send(superiorPlayer, stringBuilder.toString(), false); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 2 ? CommandTabCompletes.getMaterials(args[1]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdValues.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdValues implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("values"); } @Override public String getPermission() { return "superior.island.values"; } @Override public String getUsage(java.util.Locale locale) { return "values [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_VALUES.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = args.length == 1 ? CommandArguments.getSenderIsland(plugin, sender) : CommandArguments.getIsland(plugin, sender, args[1]); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); plugin.getMenus().openValues(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1], plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.bgsoftware.superiorskyblock.world.WorldBlocks; import org.bukkit.Location; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdVisit implements ISuperiorCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Override public List getAliases() { return Collections.singletonList("visit"); } @Override public String getPermission() { return "superior.island.visit"; } @Override public String getUsage(java.util.Locale locale) { return "visit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_VISIT.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Island targetIsland = CommandArguments.getIsland(plugin, sender, args[1]).getIsland(); if (targetIsland == null) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); if (!PluginEventsFactory.callIslandVisitorHomeTeleportEvent(targetIsland, superiorPlayer, dimension)) return; IslandWorlds.accessIslandWorldAsync(targetIsland, dimension, true, islandWorldResult -> islandWorldResult.ifLeft(world -> teleportPlayerInternal(targetIsland, superiorPlayer))); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) -> onlineIsland != null && ( (!plugin.getSettings().getVisitorsSign().isRequiredForVisit() || onlineIsland.getVisitorsPosition(null /* unused */) != null) || superiorPlayer.hasBypassModeEnabled()) && (!onlineIsland.isLocked() || onlineIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS))) : Collections.emptyList(); } private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer superiorPlayer) { Location visitLocation; boolean isVisitorSign; if (plugin.getSettings().getVisitorsSign().isRequiredForVisit()) { isVisitorSign = true; visitLocation = targetIsland.getVisitorsLocation(null /* unused */); } else { isVisitorSign = false; visitLocation = targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); } if (visitLocation == null) { Message.INVALID_VISIT_LOCATION.send(superiorPlayer); if (!superiorPlayer.hasBypassModeEnabled()) return; visitLocation = targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); Message.INVALID_VISIT_LOCATION_BYPASS.send(superiorPlayer); } if (targetIsland.isLocked() && !targetIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) { Message.NO_CLOSE_BYPASS.send(superiorPlayer); return; } Location finalVisitLocation = visitLocation; EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getVisitWarmup(), afterWarmup -> teleportPlayerNoWarmup(superiorPlayer, targetIsland, finalVisitLocation, isVisitorSign, afterWarmup /*checkIslandLock*/)); } private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, Location visitLocation, boolean isVisitorSign, boolean checkIslandLock) { if (visitLocation.getWorld() == null) { IslandWorlds.accessIslandWorldAsync(island, visitLocation, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { visitLocation.setWorld(world); teleportPlayerNoWarmupWorldLoaded(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock); }); }); } else { teleportPlayerNoWarmupWorldLoaded(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock); } } private static void teleportPlayerNoWarmupWorldLoaded(SuperiorPlayer superiorPlayer, Island island, Location visitLocation, boolean isVisitorSign, boolean checkIslandLock) { superiorPlayer.setTeleportTask(null); if (checkIslandLock && island.isLocked() && !island.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) { Message.NO_CLOSE_BYPASS.send(superiorPlayer); return; } if (isVisitorSign && !WorldBlocks.isSafeBlock(visitLocation.getBlock())) { Message.INVALID_VISIT_LOCATION.send(superiorPlayer); if (!superiorPlayer.hasBypassModeEnabled()) { if (PluginEventsFactory.callIslandRemoveVisitorHomeEvent(island, superiorPlayer)) island.setVisitorsLocation(null); return; } Message.INVALID_VISIT_LOCATION_BYPASS.send(superiorPlayer); } superiorPlayer.teleport(visitLocation); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisitors.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdVisitors implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("visitors"); } @Override public String getPermission() { return "superior.island.visitors"; } @Override public String getUsage(java.util.Locale locale) { return "visitors"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_VISITORS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); plugin.getMenus().openVisitors(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; public class CmdWarp implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("warp"); } @Override public String getPermission() { return "superior.island.warp"; } @Override public String getUsage(java.util.Locale locale) { return "warp [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "] [" + Message.COMMAND_ARGUMENT_WARP_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_WARP.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Island targetIsland = null; String targetWarpName = null; switch (args.length) { case 1: { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); targetIsland = arguments.getIsland(); break; } case 2: { if (superiorPlayer.hasIsland()) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); targetIsland = arguments.getIsland(); targetWarpName = args[1]; } else { IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[1]); targetIsland = arguments.getIsland(); } break; } case 3: { IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[1]); targetIsland = arguments.getIsland(); targetWarpName = args[2]; break; } } if (targetIsland == null) return; IslandWarp islandWarp = targetWarpName == null ? null : targetIsland.getWarp(targetWarpName); if (islandWarp == null) { switch (args.length) { case 1: plugin.getMenus().openWarpCategories(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), targetIsland); break; case 2: IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[1]); targetIsland = arguments.getIsland(); if (targetIsland != null) { plugin.getMenus().openWarpCategories(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), targetIsland); } break; case 3: Message.INVALID_WARP.send(superiorPlayer, targetWarpName); break; } return; } if (!targetIsland.isMember(superiorPlayer) && islandWarp.hasPrivateFlag()) { Message.INVALID_WARP.send(superiorPlayer, targetWarpName); return; } if (PluginEventsFactory.callIslandWarpTeleportEvent(targetIsland, superiorPlayer, islandWarp)) targetIsland.warpPlayer(superiorPlayer, targetWarpName); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Island playerIsland = superiorPlayer.getIsland(); switch (args.length) { case 2: { List tabCompletes = new LinkedList<>(CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1], true, (player, island) -> island.getIslandWarps().values().stream().anyMatch(islandWarp -> island.isMember(superiorPlayer) || !islandWarp.hasPrivateFlag()))); if (playerIsland != null) { for (String warpName : playerIsland.getIslandWarps().keySet()) { if (warpName.startsWith(args[1])) tabCompletes.add(warpName); } } return tabCompletes.isEmpty() ? Collections.emptyList() : tabCompletes; } case 3: { Island targetIsland = plugin.getGrid().getIsland(args[1]); if (targetIsland != null) { return new SequentialListBuilder>() .filter(islandWarpEntry -> targetIsland.isMember(superiorPlayer) || !islandWarpEntry.getValue().hasPrivateFlag()) .map(targetIsland.getIslandWarps().entrySet(), Map.Entry::getKey); } break; } } return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarps.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdWarps implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("warps"); } @Override public String getPermission() { return "superior.island.warps"; } @Override public String getUsage(java.util.Locale locale) { return "warps"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_WARPS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); plugin.getMenus().openGlobalWarps(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java ================================================ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.commands.CommandsMap; public class PlayerCommandsMap extends CommandsMap { public PlayerCommandsMap(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override public void loadDefaultCommands() { clearCommands(); registerCommand(new CmdAccept()); registerCommand(new CmdAdmin()); registerCommand(new CmdBan()); registerCommand(new CmdBans()); registerCommand(new CmdBiome()); registerCommand(new CmdBorder()); registerCommand(new CmdChest()); registerCommand(new CmdClose()); if (plugin.getSettings().isCoopMembers()) { registerCommand(new CmdCoop()); registerCommand(new CmdCoops()); } registerCommand(new CmdCounts()); registerCommand(new CmdCreate()); registerCommand(new CmdDelWarp()); registerCommand(new CmdDemote()); registerCommand(new CmdDisband()); registerCommand(new CmdExpel()); registerCommand(new CmdFly()); registerCommand(new CmdHelp()); registerCommand(new CmdInvite()); registerCommand(new CmdKick()); registerCommand(new CmdLang()); registerCommand(new CmdLeave()); registerCommand(new CmdMembers()); registerCommand(new CmdName()); registerCommand(new CmdOpen()); registerCommand(new CmdPanel()); registerCommand(new CmdPardon()); registerCommand(new CmdPermissions()); registerCommand(new CmdPromote()); registerCommand(new CmdRate()); registerCommand(new CmdRatings()); registerCommand(new CmdRecalc()); registerCommand(new CmdSetDiscord()); registerCommand(new CmdSetPaypal()); registerCommand(new CmdSetRole()); registerCommand(new CmdSetTeleport()); registerCommand(new CmdSettings()); registerCommand(new CmdSetWarp()); registerCommand(new CmdShow()); registerCommand(new CmdTeam()); registerCommand(new CmdTeamChat()); registerCommand(new CmdTeleport()); registerCommand(new CmdToggle()); registerCommand(new CmdTop()); registerCommand(new CmdTransfer()); if (plugin.getSettings().isCoopMembers()) registerCommand(new CmdUncoop()); registerCommand(new CmdValue()); registerCommand(new CmdValues()); registerCommand(new CmdVisit()); registerCommand(new CmdVisitors()); registerCommand(new CmdWarp()); registerCommand(new CmdWarps()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java ================================================ package com.bgsoftware.superiorskyblock.config; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.config.section.EntityCategoriesSection; import com.bgsoftware.superiorskyblock.config.section.InteractablesSection; import com.bgsoftware.superiorskyblock.config.section.WorldsSection; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.DateFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.NumberFormatter; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.io.Resources; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.values.BlockValuesManagerImpl; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.stream.Collectors; public class SettingsContainer { public final String databaseType; public final boolean databaseBackup; public final String databaseMySQLAddress; public final int databaseMySQLPort; public final String databaseMySQLDBName; public final String databaseMySQLUsername; public final String databaseMySQLPassword; public final String databaseMySQLPrefix; public final boolean databaseMySQLSSL; public final boolean databaseMySQLPublicKeyRetrieval; public final long databaseMySQLWaitTimeout; public final long databaseMySQLMaxLifetime; public final int maxIslandSize; public final String islandCommand; public final int defaultIslandSize; public final KeyMap defaultBlockLimits; public final KeyMap defaultEntityLimits; public final EnumerateMap> defaultGenerator; public final int defaultWarpsLimit; public final int defaultTeamLimit; public final int defaultCoopLimit; public final int defaultCropGrowth; public final double defaultSpawnerRates; public final double defaultMobDrops; public final BigDecimal defaultBankLimit; public final Int2IntMapView defaultRoleLimits; public final Map defaultIslandEffects; public final int islandsHeight; public final int seaLevelHeight; public final boolean worldBordersEnabled; public final boolean stackedBlocksEnabled; public final KeySet whitelistedStackedBlocks; public final List stackedBlocksDisabledWorlds; public final String stackedBlocksName; public final KeyMap stackedBlocksLimits; public final boolean stackedBlocksAutoPickup; public final boolean stackedBlocksMenuEnabled; public final String stackedBlocksMenuTitle; public final String blockLevelFormula; public final boolean roundedIslandLevel; public final RoundingMode islandLevelRoundingMode; public final boolean autoBlocksTracking; public final SortingType islandTopOrder; public final SortingType globalWarpsOrder; public boolean coopMembers; public boolean editPlayerPermissions; public final ConfigurationSection islandRolesSection; public final long calcInterval; public final String signWarpLine; public final List signWarp; public final boolean visitorsSignRequiredForVisit; public final String visitorsSignLine; public final String visitorsSignActive; public final String visitorsSignInactive; public final String visitorsSignDescriptionLineFormat; public final Dimension defaultWorldDimension; public final String defaultWorldName; public final String islandWorldName; public final EnumerateMap dimensionConfigs = new EnumerateMap<>(Dimension.values()); public final String worldsDifficulty; public final String spawnLocation; public final boolean spawnProtection; public final List spawnSettings; public final List spawnPermissions; public final boolean spawnWorldBorder; public final int spawnSize; public final boolean spawnDamage; public final Set worldPermissions; public final boolean voidTeleportMembers; public final boolean voidTeleportVisitors; public final SettingsManager.Interactables interactables; public final KeySet safeBlocks; public final boolean visitorsDamage; public final boolean coopDamage; public final boolean islandTopIncludeLeader; public final Map defaultPlaceholders; public final boolean banConfirm; public final boolean disbandConfirm; public final boolean kickConfirm; public final boolean leaveConfirm; public final boolean transferConfirm; public final String spawnersProvider; public final String stackedBlocksProvider; public final boolean islandNamesRequiredForCreation; public final int islandNamesMaxLength; public final int islandNamesMinLength; public final List filteredIslandNames; public final boolean islandNamesColorSupport; public final boolean islandNamesIslandTop; public final boolean islandNamesPreventPlayerNames; public final boolean islandNamesAnnounceChangeToAll; public final boolean teleportOnCreate; public final boolean teleportOnJoin; public final boolean teleportOnKick; public final boolean teleportOnLeave; public final List clearActionsOnDisband; public final List clearActionsOnJoin; public final List clearActionsOnKick; public final List clearActionsOnLeave; public final boolean rateOwnIsland; public final boolean changeIslandRating; public final List defaultSettings; public final boolean disableRedstoneOffline; public final boolean disableRedstoneAFK; public final boolean disableSpawningAFK; public final Map> commandsCooldown; public final long upgradeCooldown; public final String numberFormat; public final String dateFormat; public final boolean skipOneItemMenus; public final boolean teleportOnPVPEnable; public final boolean immuneToPVPWhenTeleport; public final List blockedVisitorsCommands; public final boolean defaultContainersEnabled; public final Map defaultContainersContents; public final List defaultSignLines; public final Map> eventCommands; public final long warpsWarmup; public final long homeWarmup; public final long visitWarmup; public final boolean liquidUpdate; public final boolean lightsUpdate; public final List pvpWorlds; public final boolean stopLeaving; public final boolean valuesMenu; public final List cropsToGrow; public final int cropsInterval; public final boolean onlyBackButton; public final boolean buildOutsideIsland; public final int defaultDisbandCount; public final String defaultLanguage; public final boolean defaultWorldBorder; public final boolean defaultBlocksStacker; public final boolean defaultToggledPanel; public final boolean defaultIslandFly; public final String defaultBorderColor; public final boolean obsidianToLava; public final BlockValuesManagerImpl.SyncWorthStatus syncWorth; public final boolean negativeWorth; public final boolean negativeLevel; public final List disabledEvents; public final List disabledCommands; public final List disabledHooks; public final boolean schematicNameArgument; public final String islandChestTitle; public final int islandChestsDefaultPage; public final int islandChestsDefaultSize; public final Map> commandAliases; public final KeySet valuableBlocks; public final GameMode islandPreviewsGameMode; public final int islandPreviewsMaxDistance; public final List islandPreviewsBlockedCommands; public final Map islandPreviewsLocations; public final boolean tabCompleteHideVanished; public final boolean dropsUpgradePlayersMultiply; public final Map messageDelays; public final boolean warpCategories; public final boolean physicsListener; public final double chargeOnWarp; public final boolean publicWarps; public final boolean lockedIslands; public final long recalcTaskTimeout; public final boolean autoLanguageDetection; public final boolean autoUncoopWhenAlone; public final TopIslandMembersSorting islandTopMembersSorting; public final int bossBarLimit; public final boolean deleteUnsafeWarps; public final List playerRespawnActions; public final BigInteger blockCountsSaveThreshold; public final boolean chatSigningSupport; public final int commandsPerPage; public final boolean helpOnNoPermission; public final boolean helpOnInvalidCommand; public final boolean cacheSchematics; public final SettingsManager.EntityCategories entityCategories; public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config) throws ManagerLoadException { databaseType = config.getString("database.type").toUpperCase(Locale.ENGLISH); databaseBackup = config.getBoolean("database.backup"); databaseMySQLAddress = config.getString("database.address"); databaseMySQLPort = config.getInt("database.port"); databaseMySQLDBName = config.getString("database.db-name"); databaseMySQLUsername = config.getString("database.user-name"); databaseMySQLPassword = config.getString("database.password"); databaseMySQLPrefix = config.getString("database.prefix"); databaseMySQLSSL = config.getBoolean("database.useSSL"); databaseMySQLPublicKeyRetrieval = config.getBoolean("database.allowPublicKeyRetrieval"); databaseMySQLWaitTimeout = config.getLong("database.waitTimeout"); databaseMySQLMaxLifetime = config.getLong("database.maxLifetime"); calcInterval = config.getLong("calc-interval", 6000); islandCommand = config.getString("island-command", "island,is,islands"); maxIslandSize = config.getInt("max-island-size", 200); defaultIslandSize = Math.max(config.getInt("default-values.island-size", 20), 1); KeyMap defaultBlockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, "default-values.block-limits", "block limit", (key, limit) -> { if (limit >= 0) { Key blockKey = Keys.ofMaterialAndData(key); defaultBlockLimits.put(blockKey, limit); plugin.getBlockValues().addCustomBlockKey(blockKey); } }); this.defaultBlockLimits = KeyMaps.unmodifiableKeyMap(defaultBlockLimits); KeyMap defaultEntityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); loadListOrSection(config, "default-values.entity-limits", "entity limit", (entityType, limit) -> { if (limit >= 0) { defaultEntityLimits.put(Keys.ofEntityType(entityType), limit); } }); this.defaultEntityLimits = KeyMaps.unmodifiableKeyMap(defaultEntityLimits); Map defaultIslandEffects = new ArrayMap<>(); loadListOrSection(config, "default-values.island-effects", "island effect", (effectName, effectLevel) -> { if (effectLevel >= 1) { PotionEffectType potionEffectType = PotionEffectType.getByName(effectName); if (potionEffectType == null) { Log.errorFromFile("config.yml", "Invalid potion effect " + effectName + ", skipping..."); } else { defaultIslandEffects.put(potionEffectType, effectLevel - 1); } } }); this.defaultIslandEffects = Collections.unmodifiableMap(defaultIslandEffects); defaultTeamLimit = Math.max(config.getInt("default-values.team-limit", 4), IslandUpgradeConstants.NO_LIMIT_VALUE); defaultWarpsLimit = Math.max(config.getInt("default-values.warps-limit", 3), IslandUpgradeConstants.NO_LIMIT_VALUE); defaultCoopLimit = Math.max(config.getInt("default-values.coop-limit", 8), IslandUpgradeConstants.NO_LIMIT_VALUE); defaultCropGrowth = Math.max(config.getInt("default-values.crop-growth", 1), IslandUpgradeConstants.NO_LIMIT_VALUE); defaultSpawnerRates = Math.max(config.getDouble("default-values.spawner-rates", 1D), IslandUpgradeConstants.NO_LIMIT_VALUE); defaultMobDrops = Math.max(config.getDouble("default-values.mob-drops", 1D), IslandUpgradeConstants.NO_LIMIT_VALUE); defaultBankLimit = new BigDecimal(config.getString("default-values.bank-limit", "-1")).max(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE); defaultRoleLimits = CollectionsFactory.createInt2IntHashMap(); loadListOrSection(config, "default-values.role-limits", "role limit", (role, limit) -> { if (limit >= 0) { try { defaultRoleLimits.put(Integer.parseInt(role), limit); } catch (NumberFormatException error) { Log.warnFromFile("config.yml", "Invalid role id for limit: " + role); } } }); islandsHeight = config.getInt("islands-height", 100); worldBordersEnabled = config.getBoolean("world-borders", true); stackedBlocksEnabled = config.getBoolean("stacked-blocks.enabled", true); stackedBlocksDisabledWorlds = Collections.unmodifiableList(config.getStringList("stacked-blocks.disabled-worlds")); whitelistedStackedBlocks = KeySets.createHashSet(KeyIndicator.MATERIAL, config.getStringList("stacked-blocks.whitelisted")); stackedBlocksName = Formatters.COLOR_FORMATTER.format(config.getString("stacked-blocks.custom-name")); KeyMap stackedBlocksLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, "stacked-blocks.limits", "stacked-block limit", (key, limit) -> { Key blockKey = Keys.ofMaterialAndData(key); stackedBlocksLimits.put(blockKey, limit); }); this.stackedBlocksLimits = KeyMaps.unmodifiableKeyMap(stackedBlocksLimits); stackedBlocksAutoPickup = config.getBoolean("stacked-blocks.auto-collect", false); stackedBlocksMenuEnabled = config.getBoolean("stacked-blocks.deposit-menu.enabled", true); stackedBlocksMenuTitle = Formatters.COLOR_FORMATTER.format(config.getString("stacked-blocks.deposit-menu.title", "&lDeposit Blocks")); blockLevelFormula = config.getString("block-level-formula", "{} / 2"); roundedIslandLevel = config.getBoolean("rounded-island-level", false); islandLevelRoundingMode = Optional.ofNullable(EnumHelper.getEnum(RoundingMode.class, config.getString("island-level-rounding-mode").toUpperCase(Locale.ENGLISH))) .orElse(RoundingMode.HALF_UP); autoBlocksTracking = config.getBoolean("auto-blocks-tracking", true); String rawTop = config.getString("island-top-order", "WORTH"); SortingType parsedTop = SortingType.getByName(rawTop.toUpperCase(Locale.ENGLISH)); if (parsedTop == null) { parsedTop = SortingType.getByName("WORTH"); Log.warnFromFile("config.yml", "Invalid island-top-order '" + rawTop + "', using 'WORTH'."); } this.islandTopOrder = parsedTop; String rawGlobalWarps = config.getString("global-warps-order", "WORTH").toUpperCase(Locale.ENGLISH); SortingType foundGlobalWarpsOrder = SortingType.getByName(rawGlobalWarps); if (foundGlobalWarpsOrder == null) { foundGlobalWarpsOrder = SortingType.getByName("WORTH"); Log.warnFromFile("config.yml", "Invalid global-warps-order '" + rawGlobalWarps + "', using 'WORTH'."); } this.globalWarpsOrder = foundGlobalWarpsOrder; coopMembers = config.getBoolean("coop-members", true); editPlayerPermissions = config.getBoolean("edit-player-permissions", true); islandRolesSection = config.getConfigurationSection("island-roles"); signWarpLine = config.getString("sign-warp-line", "[IslandWarp]"); List signWarp = Formatters.formatList(config.getStringList("sign-warp"), Formatters.COLOR_FORMATTER); while (signWarp.size() < 4) signWarp.add(""); this.signWarp = Collections.unmodifiableList(signWarp); visitorsSignRequiredForVisit = config.getBoolean("visitors-sign.required-for-visit", true); visitorsSignLine = config.getString("visitors-sign.line", "[Welcome]"); visitorsSignActive = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.active", "&a[Welcome]")); visitorsSignInactive = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.inactive", "&c[Welcome]")); visitorsSignDescriptionLineFormat = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.description-line-format", "{0}")); loadDimensions(config.getConfigurationSection("worlds.dimensions")); islandWorldName = config.getString("worlds.world-name", "SuperiorWorld"); worldsDifficulty = config.getString("worlds.difficulty", "EASY").toUpperCase(Locale.ENGLISH); seaLevelHeight = config.getInt("worlds.sea-level-height", 100); this.defaultWorldDimension = Dimension.getByName(config.getString("worlds.default-world")); loadDimensionConfigs(config.getConfigurationSection("worlds.dimensions")); this.defaultWorldName = this.dimensionConfigs.get(this.defaultWorldDimension).getName(); spawnLocation = config.getString("spawn.location", "SuperiorWorld, 0, 100, 0, 0, 0"); spawnProtection = config.getBoolean("spawn.protection", true); spawnSettings = Collections.unmodifiableList(new LinkedList<>(config.getStringList("spawn.settings") .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()))); spawnPermissions = Collections.unmodifiableList(new LinkedList<>(config.getStringList("spawn.permissions") .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()))); spawnWorldBorder = config.getBoolean("spawn.world-border", false); spawnSize = config.getInt("spawn.size", 200); spawnDamage = config.getBoolean("spawn.players-damage", false); worldPermissions = Collections.unmodifiableSet(new LinkedHashSet<>(config.getStringList("world-permissions") .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toSet()))); voidTeleportMembers = config.getBoolean("void-teleport.members", true); voidTeleportVisitors = config.getBoolean("void-teleport.visitors", true); interactables = loadInteractables(plugin); safeBlocks = loadSafeBlocks(plugin); visitorsDamage = config.getBoolean("visitors-damage", false); coopDamage = config.getBoolean("coop-damage", true); islandTopIncludeLeader = config.getBoolean("island-top-include-leader", true); defaultPlaceholders = Collections.unmodifiableMap(config.getStringList("default-placeholders").stream().collect(Collectors.toMap( line -> line.split(":")[0].replace("superior_", "").toLowerCase(Locale.ENGLISH), line -> line.split(":")[1] ))); banConfirm = config.getBoolean("ban-confirm"); disbandConfirm = config.getBoolean("disband-confirm"); kickConfirm = config.getBoolean("kick-confirm"); leaveConfirm = config.getBoolean("leave-confirm"); transferConfirm = config.getBoolean("transfer-confirm"); spawnersProvider = config.getString("spawners-provider", "AUTO"); stackedBlocksProvider = config.getString("stacked-blocks-provider", "AUTO"); islandNamesRequiredForCreation = config.getBoolean("island-names.required-for-creation", true); islandNamesMaxLength = config.getInt("island-names.max-length", 16); islandNamesMinLength = config.getInt("island-names.min-length", 3); filteredIslandNames = Collections.unmodifiableList(config.getStringList("island-names.filtered-names").stream() .map(str -> str.toLowerCase(Locale.ENGLISH)) .collect(Collectors.toList())); islandNamesColorSupport = config.getBoolean("island-names.color-support", true); islandNamesIslandTop = config.getBoolean("island-names.island-top", true); islandNamesPreventPlayerNames = config.getBoolean("island-names.prevent-player-names", true); islandNamesAnnounceChangeToAll = config.getBoolean("island-names.announce-change-to-all", true); teleportOnCreate = config.getBoolean("teleport-on-create", true); teleportOnJoin = config.getBoolean("teleport-on-join", false); teleportOnKick = config.getBoolean("teleport-on-kick", true); teleportOnLeave = config.getBoolean("teleport-on-leave", false); clearActionsOnDisband = loadClearActions(config.getStringList("clear-on-disband")); clearActionsOnJoin = loadClearActions(config.getStringList("clear-on-join")); clearActionsOnKick = loadClearActions(config.getStringList("clear-on-kick")); clearActionsOnLeave = loadClearActions(config.getStringList("clear-on-leave")); rateOwnIsland = config.getBoolean("rate-own-island", false); changeIslandRating = config.getBoolean("change-island-rating", true); defaultSettings = Collections.unmodifiableList(config.getStringList("default-settings") .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList())); defaultGenerator = new EnumerateMap<>(Dimension.values()); if (config.isConfigurationSection("default-values.generator")) { for (String env : config.getConfigurationSection("default-values.generator").getKeys(false)) { try { Dimension dimension = Dimension.getByName(env.toUpperCase(Locale.ENGLISH)); loadGenerator(config, "default-values.generator." + env, dimension); } catch (Exception error) { Log.errorFromFile(error, "config.yml", "An unexpected error occurred while loading default generator values for ", env + ":"); } } } else { loadGenerator(config, "default-values.generator", this.defaultWorldDimension); } disableRedstoneOffline = config.getBoolean("disable-redstone-offline", true); disableRedstoneAFK = config.getBoolean("afk-integrations.disable-redstone", false); disableSpawningAFK = config.getBoolean("afk-integrations.disable-spawning", true); Map> commandsCooldown = new HashMap<>(); for (String subCommand : config.getConfigurationSection("commands-cooldown").getKeys(false)) { int cooldown = config.getInt("commands-cooldown." + subCommand + ".cooldown"); String permission = config.getString("commands-cooldown." + subCommand + ".bypass-permission"); commandsCooldown.put(subCommand, new Pair<>(cooldown, permission)); } this.commandsCooldown = Collections.unmodifiableMap(commandsCooldown); upgradeCooldown = config.getLong("upgrade-cooldown", -1L); numberFormat = config.getString("number-format", "en-US"); NumberFormatter.setNumberFormatter(numberFormat); dateFormat = config.getString("date-format", "dd/MM/yyyy HH:mm:ss"); DateFormatter.setDateFormatter(plugin, dateFormat); skipOneItemMenus = config.getBoolean("skip-one-item-menus", false); teleportOnPVPEnable = config.getBoolean("teleport-on-pvp-enable", true); immuneToPVPWhenTeleport = config.getBoolean("immune-to-pvp-when-teleport", true); blockedVisitorsCommands = Collections.unmodifiableList(config.getStringList("blocked-visitors-commands")); defaultContainersEnabled = config.getBoolean("default-containers.enabled", false); Map defaultContainersContents = new EnumMap<>(InventoryType.class); if (config.isConfigurationSection("default-containers.containers")) { for (String container : config.getConfigurationSection("default-containers.containers").getKeys(false)) { try { InventoryType containerType = InventoryType.valueOf(container.toUpperCase(Locale.ENGLISH)); ListTag items = ListTag.of(CompoundTag.class); defaultContainersContents.put(containerType, items); ConfigurationSection containerSection = config.getConfigurationSection("default-containers.containers." + container); for (String slot : containerSection.getKeys(false)) { try { // Reading the item from the config TemplateItem templateItem = MenuParserImpl.getInstance().getItemStack("config.yml", containerSection.getConfigurationSection(slot)); if (templateItem == null) continue; ItemStack itemStack = templateItem.build(); itemStack.setAmount(containerSection.getInt(slot + ".amount", 1)); // Parsing it into compound tag CompoundTag itemCompound = plugin.getNMSTags().serializeItem(itemStack); itemCompound.setByte("Slot", Byte.parseByte(slot)); items.addTag(itemCompound); } catch (Exception error) { Log.errorFromFile(error, "config.yml", "An unexpected error occurred while loading container item for ", slot + ":"); } } } catch (IllegalArgumentException ex) { Log.warnFromFile("config.yml", "Invalid container type ", container + ", skipping..."); } } } this.defaultContainersContents = Collections.unmodifiableMap(defaultContainersContents); defaultSignLines = Collections.unmodifiableList( Formatters.formatList(config.getStringList("default-signs"), Formatters.COLOR_FORMATTER)); Map> eventCommands = new HashMap<>(); if (config.isConfigurationSection("event-commands")) { for (String eventName : config.getConfigurationSection("event-commands").getKeys(false)) { eventCommands.put(eventName.toLowerCase(Locale.ENGLISH), config.getStringList("event-commands." + eventName)); } } this.eventCommands = Collections.unmodifiableMap(eventCommands); warpsWarmup = config.getLong("warps-warmup", 0); homeWarmup = config.getLong("home-warmup", 0); visitWarmup = config.getLong("visit-warmup", 0); liquidUpdate = config.getBoolean("liquid-update", false); lightsUpdate = config.getBoolean("lights-update", true); pvpWorlds = Collections.unmodifiableList(config.getStringList("pvp-worlds")); stopLeaving = config.getBoolean("stop-leaving", false); valuesMenu = config.getBoolean("values-menu", true); cropsToGrow = Collections.unmodifiableList(config.getStringList("crops-to-grow")); cropsInterval = config.getInt("crops-interval", 5); onlyBackButton = config.getBoolean("only-back-button", false); buildOutsideIsland = config.getBoolean("build-outside-island", false); defaultDisbandCount = config.getInt("default-disband-count", 5); defaultLanguage = config.getString("default-language", "en-US"); defaultWorldBorder = config.getBoolean("default-world-border", true); defaultBlocksStacker = config.getBoolean("default-blocks-stacker", true); defaultToggledPanel = config.getBoolean("default-toggled-panel", false); defaultIslandFly = config.getBoolean("default-island-fly", false); defaultBorderColor = config.getString("default-border-color", "BLUE"); obsidianToLava = config.getBoolean("obsidian-to-lava", false); syncWorth = BlockValuesManagerImpl.SyncWorthStatus.of(config.getString("sync-worth", "NONE")); negativeWorth = config.getBoolean("negative-worth", true); negativeLevel = config.getBoolean("negative-level", true); disabledEvents = Collections.unmodifiableList(config.getStringList("disabled-events") .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList())); disabledCommands = Collections.unmodifiableList(config.getStringList("disabled-commands") .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList())); disabledHooks = Collections.unmodifiableList(config.getStringList("disabled-hooks") .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList())); schematicNameArgument = config.getBoolean("schematic-name-argument", true); islandChestTitle = Formatters.COLOR_FORMATTER.format(config.getString("island-chests.chest-title", "&4Island Chest")); islandChestsDefaultPage = config.getInt("island-chests.default-pages", 0); islandChestsDefaultSize = Math.min(6, Math.max(1, config.getInt("island-chests.default-size", 3))); Map> commandAliases = new HashMap<>(); if (config.isConfigurationSection("command-aliases")) { for (String label : config.getConfigurationSection("command-aliases").getKeys(false)) { commandAliases.put(label.toLowerCase(Locale.ENGLISH), config.getStringList("command-aliases." + label)); } } this.commandAliases = Collections.unmodifiableMap(commandAliases); valuableBlocks = KeySets.unmodifiableKeySet( KeySets.createHashSet(KeyIndicator.MATERIAL, config.getStringList("valuable-blocks"))); GameMode islandPreviewsGameMode; String islandPreviewsGameModeName = config.getString("island-previews.game-mode", "SPECTATOR").toUpperCase(Locale.ENGLISH); try { islandPreviewsGameMode = GameMode.valueOf(islandPreviewsGameModeName); } catch (IllegalArgumentException error) { islandPreviewsGameMode = GameMode.SPECTATOR; Log.warnFromFile("config.yml", "Invalid game mode ", islandPreviewsGameModeName + ", using SPECTATOR instead."); } this.islandPreviewsGameMode = islandPreviewsGameMode; islandPreviewsMaxDistance = config.getInt("island-previews.max-distance", 100); islandPreviewsBlockedCommands = Collections.unmodifiableList(config.getStringList("island-previews.blocked-commands")); Map islandPreviewsLocations = new HashMap<>(); if (config.isConfigurationSection("island-previews.locations")) { for (String schematic : config.getConfigurationSection("island-previews.locations").getKeys(false)) { try { islandPreviewsLocations.put(schematic.toLowerCase(Locale.ENGLISH), Serializers.LOCATION_SPACED_CENTERED_SERIALIZER .deserialize(config.getString("island-previews.locations." + schematic))); } catch (Exception error) { Log.warnFromFile("config.yml", "Cannot deserialize island preview for ", schematic, ", skipping..."); } } } this.islandPreviewsLocations = Collections.unmodifiableMap(islandPreviewsLocations); tabCompleteHideVanished = config.getBoolean("tab-complete-hide-vanished", true); dropsUpgradePlayersMultiply = config.getBoolean("drops-upgrade-players-multiply", false); Map messageDelays = new HashMap<>(); if (config.isConfigurationSection("message-delays")) { for (String message : config.getConfigurationSection("message-delays").getKeys(false)) { messageDelays.put(message.toUpperCase(Locale.ENGLISH), config.getLong("message-delays." + message)); } } this.messageDelays = Collections.unmodifiableMap(messageDelays); warpCategories = config.getBoolean("warp-categories", true); physicsListener = config.getBoolean("physics-listener", true); chargeOnWarp = config.getDouble("charge-on-warp", 0D); publicWarps = config.getBoolean("public-warps"); lockedIslands = config.getBoolean("locked-islands", false); recalcTaskTimeout = config.getLong("recalc-task-timeout"); autoLanguageDetection = config.getBoolean("auto-language-detection", true); autoUncoopWhenAlone = config.getBoolean("auto-uncoop-when-alone", false); islandTopMembersSorting = Optional.ofNullable(EnumHelper.getEnum(TopIslandMembersSorting.class, config.getString("island-top-members-sorting").toUpperCase(Locale.ENGLISH))) .orElse(TopIslandMembersSorting.NAMES); bossBarLimit = config.getInt("bossbar-limit", 1); deleteUnsafeWarps = config.getBoolean("delete-unsafe-warps", true); List playerRespawnActions = new LinkedList<>(); config.getStringList("player-respawn").forEach(respawnAction -> { try { playerRespawnActions.add(RespawnAction.getByName(respawnAction)); } catch (NullPointerException error) { Log.warnFromFile("config.yml", "Invalid respawn action ", respawnAction + ", skipping..."); } }); this.playerRespawnActions = Collections.unmodifiableList(playerRespawnActions); blockCountsSaveThreshold = BigInteger.valueOf(config.getInt("block-counts-save-threshold", 100)); chatSigningSupport = config.getBoolean("chat-signing-support", true); commandsPerPage = config.getInt("commands-per-page", 7); helpOnInvalidCommand = config.getBoolean("help-on-invalid-command", true); helpOnNoPermission = config.getBoolean("help-on-no-permission", false); cacheSchematics = config.getBoolean("cache-schematics", true); entityCategories = loadEntityCategories(plugin); } private void loadDimensions(ConfigurationSection dimensionsSection) { // First register all dimensions for (String dimensionName : dimensionsSection.getKeys(false)) { String environmentName = dimensionsSection.getString(dimensionName + ".environment"); World.Environment environment; try { environment = World.Environment.valueOf(environmentName.toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException error) { Log.warnFromFile("config.yml", "Cannot load dimension due to invalid environment: ", environmentName, " - skipping..."); continue; } try { Dimension.register(dimensionName, environment); } catch (IllegalStateException ignored) { } } } private void loadDimensionConfigs(ConfigurationSection dimensionsSection) throws ManagerLoadException { for (String dimensionName : dimensionsSection.getKeys(false)) { ConfigurationSection dimensionSection = dimensionsSection.getConfigurationSection(dimensionName); if (dimensionSection == null) { Log.warnFromFile("config.yml", "Invalid dimension config section for ", dimensionName, " - skipping..."); continue; } Dimension dimension = Dimension.getByName(dimensionName); String worldName = defaultWorldDimension == dimension ? islandWorldName : islandWorldName + "_" + dimensionName.toLowerCase(Locale.ENGLISH); switch (dimension.getEnvironment()) { case NORMAL: dimensionConfigs.put(dimension, new WorldsSection.NormalDimensionConfig(dimensionSection, dimension, worldName)); break; case NETHER: dimensionConfigs.put(dimension, new WorldsSection.NetherDimensionConfig(dimensionSection, dimension, worldName)); break; case THE_END: dimensionConfigs.put(dimension, new WorldsSection.EndDimensionConfig(dimensionSection, dimension, worldName)); break; } } // Check the default dimension is valid SettingsManager.Worlds.DimensionConfig dimensionConfig = this.dimensionConfigs.get(this.defaultWorldDimension); if (dimensionConfig == null || !dimensionConfig.isEnabled()) { throw new ManagerLoadException("Cannot find a default islands world.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } } private List loadClearActions(List clearActionsNames) { List clearActions = new LinkedList<>(); clearActionsNames.forEach(clearAction -> { try { clearActions.add(ClearAction.getByName(clearAction)); } catch (NullPointerException error) { Log.warnFromFile("config.yml", "Invalid clear action ", clearAction + ", skipping..."); } }); return Collections.unmodifiableList(clearActions); } private SettingsManager.Interactables loadInteractables(SuperiorSkyblockPlugin plugin) { File file = new File(plugin.getDataFolder(), "interactables.yml"); if (!file.exists()) plugin.saveResource("interactables.yml", false); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); InteractablesSection interactables = new InteractablesSection(plugin, cfg); // Warn about interactables that the default file contains but the current // file does not. Set localInteractables = new HashSet<>(); for (Key key : interactables.getInteractables()) { localInteractables.add(key.toString()); } YamlConfiguration defaultInteractablesConfig = CommentedConfiguration.loadConfiguration(plugin.getResource("interactables.yml")); for (String block : defaultInteractablesConfig.getStringList("interactables")) { if (!localInteractables.contains(block)) { Log.warn("Potentially missing interactable block ", block); } } if (interactables.isLegacy()) { try { interactables.saveToFile(file); } catch (IOException error) { Log.errorFromFile(error, "interactables.yml", "Failed to save interactables:"); } } return interactables; } private SettingsManager.EntityCategories loadEntityCategories(SuperiorSkyblockPlugin plugin) { File file = new File(plugin.getDataFolder(), "entity-categories.yml"); boolean removeInvalidEntityKeys = false; if (!file.exists()) { plugin.saveResource("entity-categories.yml", false); removeInvalidEntityKeys = true; } YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); if (removeInvalidEntityKeys) { EntityCategoriesSection.removeInvalidEntityKeys(cfg, file); } return new EntityCategoriesSection(cfg); } private KeySet loadSafeBlocks(SuperiorSkyblockPlugin plugin) { File file = new File(plugin.getDataFolder(), "safe_blocks.yml"); if (!file.exists()) Resources.saveResource("safe_blocks.yml"); CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file); List safeBlocks = cfg.getStringList("safe-blocks"); if (safeBlocks.isEmpty()) { Log.warnFromFile(file.getName(), "There are no valid safe blocks! Generating default ones..."); safeBlocks.addAll(Arrays.stream(Material.values()) .filter(Material::isSolid) .map(Material::name) .sorted() .collect(Collectors.toList())); try { cfg.set("safe-blocks", safeBlocks); cfg.save(file); } catch (IOException error) { Log.errorFromFile(error, "config.yml", "An unexpected error occurred while saving safe blocks into file:"); } } return KeySets.unmodifiableKeySet(KeySets.createHashSet(KeyIndicator.MATERIAL, safeBlocks)); } private void loadGenerator(YamlConfiguration config, String path, Dimension dimension) { KeyMap defaultGenerator = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, path, "generator-rates", (key, percentage) -> { if (percentage >= 0) { Key blockKey = Keys.ofMaterialAndData(key); defaultGenerator.put(blockKey, percentage); } }); this.defaultGenerator.put(dimension, KeyMaps.unmodifiableKeyMap(defaultGenerator)); } private static void loadListOrSection(YamlConfiguration config, String path, String parseName, BiConsumer consumer) { Object value = config.get(path); if (value == null) return; if (value instanceof List) { ((List) value).forEach(line -> { String[] sections = line.split(":"); if (sections.length == 2) { consumer.accept(sections[0], Integer.parseInt(sections[1])); } else if (sections.length == 3) { consumer.accept(sections[0] + ":" + sections[1], Integer.parseInt(sections[2])); } else { Log.warnFromFile("config.yml", "Cannot parse " + parseName + " '", line, "', skipping..."); } }); } else if (value instanceof ConfigurationSection) { for (String key : ((ConfigurationSection) value).getKeys(false)) { consumer.accept(key, ((ConfigurationSection) value).getInt(key)); } } else { throw new IllegalArgumentException("Value of path '" + path + "' is not a list or a section, but " + value.getClass()); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainerHolder.java ================================================ package com.bgsoftware.superiorskyblock.config; public abstract class SettingsContainerHolder { private SettingsContainer container; protected SettingsContainerHolder() { } public void setContainer(SettingsContainer container) { this.container = container; } protected SettingsContainer getContainer() { if (this.container == null) throw new IllegalStateException("Cannot access SettingsManager before initialization"); return this.container; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.config; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.config.section.AFKIntegrationsSection; import com.bgsoftware.superiorskyblock.config.section.DatabaseSection; import com.bgsoftware.superiorskyblock.config.section.DefaultContainersSection; import com.bgsoftware.superiorskyblock.config.section.DefaultValuesSection; import com.bgsoftware.superiorskyblock.config.section.GlobalSection; import com.bgsoftware.superiorskyblock.config.section.IslandChestsSection; import com.bgsoftware.superiorskyblock.config.section.IslandNamesSection; import com.bgsoftware.superiorskyblock.config.section.IslandPreviewsSection; import com.bgsoftware.superiorskyblock.config.section.IslandRolesSection; import com.bgsoftware.superiorskyblock.config.section.SpawnSection; import com.bgsoftware.superiorskyblock.config.section.StackedBlocksSection; import com.bgsoftware.superiorskyblock.config.section.VisitorsSignSection; import com.bgsoftware.superiorskyblock.config.section.VoidTeleportSection; import com.bgsoftware.superiorskyblock.config.section.WorldsSection; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.IOException; import java.math.BigInteger; import java.math.RoundingMode; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @SuppressWarnings("WeakerAccess") public class SettingsManagerImpl extends Manager implements SettingsManager { private static final String[] IGNORED_SECTIONS = new String[]{ "config.yml", "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", "worlds.dimensions", "island-previews.locations", "default-values.block-limits", "default-values.entity-limits", "default-values.role-limits", "stacked-blocks.limits", "default-values.generator", "message-delays" }; private final GlobalSection global = new GlobalSection(); private final DatabaseSection database = new DatabaseSection(); private final DefaultValuesSection defaultValues = new DefaultValuesSection(); private final StackedBlocksSection stackedBlocks = new StackedBlocksSection(); private final IslandRolesSection islandRoles = new IslandRolesSection(); private final VisitorsSignSection visitorsSign = new VisitorsSignSection(); private final WorldsSection worlds = new WorldsSection(); private final SpawnSection spawn = new SpawnSection(); private final VoidTeleportSection voidTeleport = new VoidTeleportSection(); private final IslandNamesSection islandNames = new IslandNamesSection(); private final AFKIntegrationsSection afkIntegrations = new AFKIntegrationsSection(); private final DefaultContainersSection defaultContainers = new DefaultContainersSection(); private final IslandChestsSection islandChests = new IslandChestsSection(); private final IslandPreviewsSection islandPreviews = new IslandPreviewsSection(); public SettingsManagerImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override public void loadData() throws ManagerLoadException { File file = new File(plugin.getDataFolder(), "config.yml"); if (!file.exists()) plugin.saveResource("config.yml", false); CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file); convertData(cfg); convertInteractables(plugin, cfg); convertEntityCategories(plugin, cfg); try { cfg.syncWithConfig(file, plugin.getResource("config.yml"), IGNORED_SECTIONS); } catch (Exception error) { Log.error(error, file, "An unexpected error occurred while loading config file:"); } loadContainerFromConfig(cfg); PluginEventsFactory.callSettingsUpdateEvent(); } @Override public long getCalcInterval() { return this.global.getCalcInterval(); } @Override public Database getDatabase() { return this.database; } @Override public String getIslandCommand() { return this.global.getIslandCommand(); } @Override public int getMaxIslandSize() { return this.global.getMaxIslandSize(); } @Override public DefaultValuesSection getDefaultValues() { return this.defaultValues; } @Override public int getIslandHeight() { return this.global.getIslandHeight(); } @Override public boolean isWorldBorders() { return this.global.isWorldBorders(); } @Override public StackedBlocks getStackedBlocks() { return this.stackedBlocks; } @Override public String getIslandLevelFormula() { return this.global.getBlockLevelFormula(); } @Override public boolean isRoundedIslandLevels() { return this.global.isRoundedIslandLevels(); } @Override public RoundingMode getIslandLevelRoundingMode() { return this.global.getIslandLevelRoundingMode(); } @Override public boolean isAutoBlocksTracking() { return this.global.isAutoBlocksTracking(); } @Override public String getIslandTopOrder() { return this.global.getIslandTopOrder().getName(); } @Override public String getGlobalWarpsOrder() { return this.global.getGlobalWarpsOrder().getName(); } @Override public boolean isCoopMembers() { return this.global.isCoopMembers(); } @Override public boolean isEditPlayerPermissions() { return this.global.isEditPlayerPermissions(); } @Override public IslandRoles getIslandRoles() { return this.islandRoles; } @Override public String getSignWarpLine() { return this.global.getSignWarpLine(); } @Override public List getSignWarp() { return this.global.getSignWarp(); } @Override public VisitorsSign getVisitorsSign() { return this.visitorsSign; } @Override public Worlds getWorlds() { return this.worlds; } @Override public Spawn getSpawn() { return this.spawn; } @Override public Collection getWorldPermissions() { return this.global.getWorldPermissions(); } @Override public VoidTeleport getVoidTeleport() { return this.voidTeleport; } @Override public List getInteractables() { List interactables = new LinkedList<>(); for (Key key : getInteractablesMap().getInteractables()) { interactables.add(key.toString()); } return interactables.isEmpty() ? Collections.emptyList() : interactables; } @Override public Interactables getInteractablesMap() { return this.global.getInteractablesMap(); } @Override public Collection getSafeBlocks() { return this.global.getSafeBlocks(); } @Override public boolean isVisitorsDamage() { return this.global.isVisitorsDamage(); } @Override public boolean isCoopDamage() { return this.global.isCoopDamage(); } @Override public int getDisbandCount() { return this.global.getDisbandCount(); } @Override public boolean isIslandTopIncludeLeader() { return this.global.isIslandTopIncludeLeader(); } @Override public Map getDefaultPlaceholders() { return this.global.getDefaultPlaceholders(); } @Override public boolean isBanConfirm() { return this.global.isBanConfirm(); } @Override public boolean isDisbandConfirm() { return this.global.isDisbandConfirm(); } @Override public boolean isKickConfirm() { return this.global.isKickConfirm(); } @Override public boolean isLeaveConfirm() { return this.global.isLeaveConfirm(); } @Override public boolean isTransferConfirm() { return this.global.isTransferConfirm(); } @Override public String getSpawnersProvider() { return this.global.getSpawnersProvider(); } @Override public String getStackedBlocksProvider() { return this.global.getStackedBlocksProvider(); } @Override public boolean isDisbandInventoryClear() { List clearActions = this.global.getClearActionsOnDisband(); return clearActions.contains(ClearActions.ENDER_CHEST) && clearActions.contains(ClearActions.INVENTORY); } @Override public IslandNames getIslandNames() { return this.islandNames; } @Override public boolean isTeleportOnCreate() { return this.global.isTeleportOnCreate(); } @Override public boolean isTeleportOnJoin() { return this.global.isTeleportOnJoin(); } @Override public boolean isTeleportOnKick() { return this.global.isTeleportOnKick(); } @Override public boolean isTeleportOnLeave() { return this.global.isTeleportOnLeave(); } @Override public boolean isClearOnJoin() { List clearActions = this.global.getClearActionsOnJoin(); return clearActions.contains(ClearActions.ENDER_CHEST) && clearActions.contains(ClearActions.INVENTORY); } @Override public List getClearActionsOnDisband() { return this.global.getClearActionsOnDisband(); } @Override public List getClearActionsOnJoin() { return this.global.getClearActionsOnJoin(); } @Override public List getClearActionsOnKick() { return this.global.getClearActionsOnKick(); } @Override public List getClearActionsOnLeave() { return this.global.getClearActionsOnLeave(); } @Override public boolean isRateOwnIsland() { return this.global.isRateOwnIsland(); } @Override public boolean isChangeIslandRating() { return this.global.isChangeIslandRating(); } @Override public List getDefaultSettings() { return this.global.getDefaultSettings(); } @Override public boolean isDisableRedstoneOffline() { return this.global.isDisableRedstoneOffline(); } @Override public AFKIntegrations getAFKIntegrations() { return this.afkIntegrations; } @Override public Map> getCommandsCooldown() { return this.global.getCommandsCooldown(); } @Override public long getUpgradeCooldown() { return this.global.getUpgradeCooldown(); } @Override public String getNumbersFormat() { return this.global.getNumbersFormat(); } @Override public String getDateFormat() { return this.global.getDateFormat(); } @Override public boolean isSkipOneItemMenus() { return this.global.isSkipOneItemMenus(); } @Override public boolean isTeleportOnPvPEnable() { return this.global.isTeleportOnPvPEnable(); } @Override public boolean isImmuneToPvPWhenTeleport() { return this.global.isImmuneToPvPWhenTeleport(); } @Override public List getBlockedVisitorsCommands() { return this.global.getBlockedVisitorsCommands(); } @Override public DefaultContainersSection getDefaultContainers() { return this.defaultContainers; } @Override public List getDefaultSign() { return this.global.getDefaultSign(); } @Override public Map> getEventCommands() { return this.global.getEventCommands(); } @Override public long getWarpsWarmup() { return this.global.getWarpsWarmup(); } @Override public long getHomeWarmup() { return this.global.getHomeWarmup(); } @Override public long getVisitWarmup() { return this.global.getVisitWarmup(); } @Override public boolean isLiquidUpdate() { return this.global.isLiquidUpdate(); } @Override public boolean isLightsUpdate() { return this.global.isLightsUpdate(); } @Override public List getPvPWorlds() { return this.global.getPvPWorlds(); } @Override public boolean isStopLeaving() { return this.global.isStopLeaving(); } @Override public boolean isValuesMenu() { return this.global.isValuesMenu(); } @Override public List getCropsToGrow() { return this.global.getCropsToGrow(); } @Override public int getCropsInterval() { return this.global.getCropsInterval(); } @Override public boolean isOnlyBackButton() { return this.global.isOnlyBackButton(); } @Override public boolean isBuildOutsideIsland() { return this.global.isBuildOutsideIsland(); } @Override public String getDefaultLanguage() { return this.global.getDefaultLanguage(); } @Override public boolean isDefaultWorldBorder() { return this.global.isDefaultWorldBorder(); } @Override public boolean isDefaultStackedBlocks() { return this.global.isDefaultStackedBlocks(); } @Override public boolean isDefaultToggledPanel() { return this.global.isDefaultToggledPanel(); } @Override public boolean isDefaultIslandFly() { return this.global.isDefaultIslandFly(); } @Override public String getDefaultBorderColor() { return this.global.getDefaultBorderColor(); } @Override public boolean isObsidianToLava() { return this.global.isObsidianToLava(); } @Override public BlockValuesManager.SyncWorthStatus getSyncWorth() { return this.global.getSyncWorth(); } @Override public boolean isNegativeWorth() { return this.global.isNegativeWorth(); } @Override public boolean isNegativeLevel() { return this.global.isNegativeLevel(); } @Override public List getDisabledEvents() { return this.global.getDisabledEvents(); } @Override public List getDisabledCommands() { return this.global.getDisabledCommands(); } @Override public List getDisabledHooks() { return this.global.getDisabledHooks(); } @Override public boolean isSchematicNameArgument() { return this.global.isSchematicNameArgument(); } @Override public IslandChests getIslandChests() { return this.islandChests; } @Override public Map> getCommandAliases() { return this.global.getCommandAliases(); } @Override public Set getValuableBlocks() { return this.global.getValuableBlocks(); } @Override @Deprecated public Map getPreviewIslands() { return this.islandPreviews.getLocations(); } @Override public IslandPreviewsSection getIslandPreviews() { return this.islandPreviews; } @Override public boolean isTabCompleteHideVanished() { return this.global.isTabCompleteHideVanished(); } @Override public boolean isDropsUpgradePlayersMultiply() { return this.global.isDropsUpgradePlayersMultiply(); } @Override @Deprecated public long getProtectedMessageDelay() { return this.global.getMessageDelays().getOrDefault("ISLAND_PROTECTED", 0L); } @Override public Map getMessageDelays() { return this.global.getMessageDelays(); } @Override public boolean isWarpCategories() { return this.global.isWarpCategories(); } @Override public boolean isPhysicsListener() { return this.global.isPhysicsListener(); } @Override public double getChargeOnWarp() { return this.global.getChargeOnWarp(); } @Override public boolean isPublicWarps() { return this.global.isPublicWarps(); } @Override public boolean isLockedIslands() { return this.global.isLockedIslands(); } @Override public long getRecalcTaskTimeout() { return this.global.getRecalcTaskTimeout(); } @Override public boolean isAutoLanguageDetection() { return this.global.isAutoLanguageDetection(); } @Override public boolean isAutoUncoopWhenAlone() { return this.global.isAutoUncoopWhenAlone(); } @Override public TopIslandMembersSorting getTopIslandMembersSorting() { return this.global.getTopIslandMembersSorting(); } @Override public int getBossbarLimit() { return this.global.getBossbarLimit(); } @Override public boolean getDeleteUnsafeWarps() { return this.global.getDeleteUnsafeWarps(); } @Override public List getPlayerRespawn() { return this.global.getPlayerRespawn(); } @Override public BigInteger getBlockCountsSaveThreshold() { return this.global.getBlockCountsSaveThreshold(); } @Override public boolean getChatSigningSupport() { return this.global.getChatSigningSupport(); } @Override public int getCommandsPerPage() { return this.global.getCommandsPerPage(); } @Override public boolean isHelpOnInvalidCommand() { return this.global.isHelpOnInvalidCommand(); } @Override public boolean isHelpOnNoPermission() { return this.global.isHelpOnNoPermission(); } @Override public boolean isCacheSchematics() { return this.global.isCacheSchematics(); } @Override public Map getEntityCategories() { Map categories = new HashMap<>(); for (EntityCategory entityCategory : getEntityCategoriesMap().getCategories()) { categories.put(entityCategory.getName(), entityCategory.getEntities()); } return categories.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(categories); } @Override public EntityCategories getEntityCategoriesMap() { return this.global.getEntityCategoriesMap(); } public void updateValue(String path, Object value) throws IOException { File file = new File(plugin.getDataFolder(), "config.yml"); if (!file.exists()) plugin.saveResource("config.yml", false); CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file); cfg.syncWithConfig(file, plugin.getResource("config.yml"), "config.yml", "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", "island-previews.locations", "worlds.dimensions"); cfg.set(path, value); cfg.save(file); try { loadContainerFromConfig(cfg); } catch (ManagerLoadException ex) { ManagerLoadException.handle(ex); } } private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadException { SettingsContainer container = new SettingsContainer(plugin, cfg); this.global.setContainer(container); this.database.setContainer(container); this.defaultValues.setContainer(container); this.stackedBlocks.setContainer(container); this.islandRoles.setContainer(container); this.visitorsSign.setContainer(container); this.worlds.setContainer(container); this.spawn.setContainer(container); this.voidTeleport.setContainer(container); this.islandNames.setContainer(container); this.afkIntegrations.setContainer(container); this.defaultContainers.setContainer(container); this.islandChests.setContainer(container); this.islandPreviews.setContainer(container); } private void convertData(YamlConfiguration cfg) { if (cfg.getConfigurationSection("worlds.dimensions") == null) { cfg.set("worlds.dimensions.normal", cfg.getConfigurationSection("worlds.normal")); cfg.set("worlds.dimensions.normal.environment", "NORMAL"); cfg.set("worlds.dimensions.normal.portals.NETHER", "nether"); cfg.set("worlds.dimensions.normal.portals.ENDER", "the_end"); cfg.set("worlds.normal", null); cfg.set("worlds.dimensions.nether", cfg.getConfigurationSection("worlds.nether")); cfg.set("worlds.dimensions.nether.environment", "NETHER"); cfg.set("worlds.dimensions.nether.portals.NETHER", "normal"); cfg.set("worlds.dimensions.nether.portals.ENDER", "the_end"); cfg.set("worlds.nether", null); cfg.set("worlds.dimensions.the_end", cfg.getConfigurationSection("worlds.end")); cfg.set("worlds.dimensions.the_end.environment", "THE_END"); cfg.set("worlds.dimensions.the_end.portals.NETHER", "nether"); cfg.set("worlds.dimensions.the_end.portals.ENDER", "normal"); cfg.set("worlds.end", null); } if (cfg.get("island-level-formula") != null) { cfg.set("block-level-formula", cfg.getString("island-level-formula")); cfg.set("island-level-formula", null); } if (cfg.get("protected-message-delay") instanceof Number) { long delay = cfg.getLong("protected-message-delay") * 50; cfg.set("message-delays.ISLAND_PROTECTED", delay); cfg.set("message-delays.ISLAND_PROTECTED_OPPED", delay); cfg.set("message-delays.SPAWN_PROTECTED", delay); cfg.set("message-delays.SPAWN_PROTECTED_OPPED", delay); cfg.set("protected-message-delay", null); } if (cfg.isConfigurationSection("preview-islands")) { cfg.set("island-previews.locations", cfg.getConfigurationSection("preview-islands")); cfg.set("preview-islands", null); } if (cfg.isBoolean("disband-inventory-clear")) { if (cfg.getBoolean("disband-inventory-clear")) { cfg.set("clear-on-disband", Arrays.asList("ENDER_CHEST", "INVENTORY")); } else { cfg.set("clear-on-disband", Collections.emptyList()); } cfg.set("disband-inventory-clear", null); } if (cfg.isBoolean("clear-on-join")) { if (cfg.getBoolean("disband-inventory-clear")) { cfg.set("clear-on-join", Arrays.asList("ENDER_CHEST", "INVENTORY")); } else { cfg.set("clear-on-join", Collections.emptyList()); } } if (cfg.isInt("disband-count")) { cfg.set("default-disband-count", cfg.getInt("disband-count") == 0 ? -1 : cfg.getInt("disband-count")); cfg.set("disband-count", null); } if (cfg.isInt("default-hoppers-limit")) { cfg.set("default-limits", Collections.singletonList("HOPPER:" + cfg.getInt("default-hoppers-limit"))); cfg.set("default-hoppers-limit", null); } if (cfg.isConfigurationSection("default-permissions")) { cfg.set("island-roles.guest.name", "Guest"); cfg.set("island-roles.guest.permissions", cfg.getStringList("default-permissions.guest")); cfg.set("island-roles.ladder.member.name", "Member"); cfg.set("island-roles.ladder.member.weight", 0); cfg.set("island-roles.ladder.member.permissions", cfg.getStringList("default-permissions.member")); cfg.set("island-roles.ladder.mod.name", "Moderator"); cfg.set("island-roles.ladder.mod.weight", 1); cfg.set("island-roles.ladder.mod.permissions", cfg.getStringList("default-permissions.mod")); cfg.set("island-roles.ladder.admin.name", "Admin"); cfg.set("island-roles.ladder.admin.weight", 2); cfg.set("island-roles.ladder.admin.permissions", cfg.getStringList("default-permissions.admin")); cfg.set("island-roles.ladder.leader.name", "Leader"); cfg.set("island-roles.ladder.leader.weight", 3); cfg.set("island-roles.ladder.leader.permissions", cfg.getStringList("default-permissions.leader")); } if (cfg.isString("spawn-location")) cfg.set("spawn.location", cfg.getString("spawn-location")); if (cfg.isBoolean("spawn-protection")) cfg.set("spawn.protection", cfg.getBoolean("spawn-protection")); if (cfg.getBoolean("spawn-pvp", false)) cfg.set("spawn.settings", Collections.singletonList("PVP")); if (cfg.isString("island-world")) cfg.set("worlds.normal-world", cfg.getString("island-world")); if (cfg.isString("welcome-sign-line")) cfg.set("visitors-sign.line", cfg.getString("welcome-sign-line")); if (cfg.isConfigurationSection("island-roles.ladder")) { for (String name : cfg.getConfigurationSection("island-roles.ladder").getKeys(false)) { if (!cfg.isInt("island-roles.ladder." + name + ".id")) cfg.set("island-roles.ladder." + name + ".id", cfg.getInt("island-roles.ladder." + name + ".weight")); } } if (cfg.isInt("default-island-size")) cfg.set("default-values.island-size", cfg.getInt("default-island-size")); if (cfg.isList("default-limits")) cfg.set("default-values.block-limits", cfg.getStringList("default-limits")); if (cfg.isList("default-entity-limits")) cfg.set("default-values.entity-limits", cfg.getStringList("default-entity-limits")); if (cfg.isInt("default-warps-limit")) cfg.set("default-values.warps-limit", cfg.getInt("default-warps-limit")); if (cfg.isInt("default-team-limit")) cfg.set("default-values.team-limit", cfg.getInt("default-team-limit")); if (cfg.isInt("default-crop-growth")) cfg.set("default-values.crop-growth", cfg.getInt("default-crop-growth")); if (cfg.isInt("default-spawner-rates")) cfg.set("default-values.spawner-rates", cfg.getInt("default-spawner-rates")); if (cfg.isInt("default-mob-drops")) cfg.set("default-values.mob-drops", cfg.getInt("default-mob-drops")); if (cfg.isInt("default-island-height")) cfg.set("islands-height", cfg.getInt("default-island-height")); if (cfg.isConfigurationSection("starter-chest")) { cfg.set("default-containers.enabled", cfg.getBoolean("starter-chest.enabled")); cfg.set("default-containers.containers.chest", cfg.getConfigurationSection("starter-chest.contents")); } if (cfg.isList("default-generator")) cfg.set("default-values.generator", cfg.getStringList("default-generator")); if (cfg.isBoolean("void-teleport")) { boolean voidTeleport = cfg.getBoolean("void-teleport"); cfg.set("void-teleport.members", voidTeleport); cfg.set("void-teleport.visitors", voidTeleport); } if (cfg.isBoolean("sync-worth")) cfg.set("sync-worth", cfg.getBoolean("sync-worth") ? "BUY" : "NONE"); if (!cfg.isConfigurationSection("worlds.nether")) { cfg.set("worlds.nether.enabled", cfg.getBoolean("worlds.nether-world")); cfg.set("worlds.nether.unlock", cfg.getBoolean("worlds.nether-unlock")); } if (!cfg.isConfigurationSection("worlds.end")) { cfg.set("worlds.end.enabled", cfg.getBoolean("worlds.end-world")); cfg.set("worlds.end.unlock", cfg.getBoolean("worlds.end-unlock")); } if (cfg.isString("worlds.normal-world")) { cfg.set("worlds.world-name", cfg.getString("worlds.normal-world")); cfg.set("worlds.normal-world", null); } if (cfg.isBoolean("worlds.end.dragon-fight")) { cfg.set("worlds.end.dragon-fight.enabled", cfg.getBoolean("worlds.end.dragon-fight")); } if (!cfg.isConfigurationSection("default-values.island-effects")) cfg.createSection("default-values.island-effects"); } private void convertInteractables(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) { if (!cfg.isList("interactables")) return; File file = new File(plugin.getDataFolder(), "interactables.yml"); if (!file.exists()) plugin.saveResource("interactables.yml", false); CommentedConfiguration commentedConfig = CommentedConfiguration.loadConfiguration(file); commentedConfig.set("interactables", cfg.getStringList("interactables")); try { commentedConfig.save(file); cfg.set("interactables", null); } catch (Exception error) { Log.errorFromFile(error, file.getName(), "An unexpected error occurred while saving file:"); } } private void convertEntityCategories(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) { if (!cfg.isConfigurationSection("entity-categories")) return; File file = new File(plugin.getDataFolder(), "entity-categories.yml"); if (!file.exists()) plugin.saveResource("entity-categories.yml", false); CommentedConfiguration commentedConfig = CommentedConfiguration.loadConfiguration(file); for (String categoryName : cfg.getConfigurationSection("entity-categories").getKeys(false)) { List entities = cfg.getStringList("entity-categories." + categoryName); if (!entities.isEmpty()) { categoryName = categoryName.toUpperCase(Locale.ENGLISH); commentedConfig.set(categoryName + ".entities", entities); commentedConfig.set(categoryName + ".actions.SPAWN", categoryName + "_SPAWN"); commentedConfig.set(categoryName + ".actions.DAMAGE", categoryName + "_DAMAGE"); commentedConfig.set(categoryName + ".actions.SPAWNER_SPAWN", "SPAWNER_" + categoryName + "_SPAWN"); commentedConfig.set(categoryName + ".actions.NATURAL_SPAWN", "NATURAL_" + categoryName + "_SPAWN"); } } try { commentedConfig.save(file); cfg.set("entity-categories", null); } catch (Exception error) { Log.errorFromFile(error, file.getName(), "An unexpected error occurred while saving file:"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/AFKIntegrationsSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; public class AFKIntegrationsSection extends SettingsContainerHolder implements SettingsManager.AFKIntegrations { @Override public boolean isDisableRedstone() { return getContainer().disableRedstoneAFK; } @Override public boolean isDisableSpawning() { return getContainer().disableSpawningAFK; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/DatabaseSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; public class DatabaseSection extends SettingsContainerHolder implements SettingsManager.Database { @Override public String getType() { return getContainer().databaseType; } @Override public boolean isBackup() { return getContainer().databaseBackup; } @Override public String getAddress() { return getContainer().databaseMySQLAddress; } @Override public int getPort() { return getContainer().databaseMySQLPort; } @Override public String getDBName() { return getContainer().databaseMySQLDBName; } @Override public String getUsername() { return getContainer().databaseMySQLUsername; } @Override public String getPassword() { return getContainer().databaseMySQLPassword; } @Override public String getPrefix() { return getContainer().databaseMySQLPrefix; } @Override public boolean hasSSL() { return getContainer().databaseMySQLSSL; } @Override public boolean hasPublicKeyRetrieval() { return getContainer().databaseMySQLPublicKeyRetrieval; } @Override public long getWaitTimeout() { return getContainer().databaseMySQLWaitTimeout; } @Override public long getMaxLifetime() { return getContainer().databaseMySQLMaxLifetime; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultContainersSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import com.bgsoftware.superiorskyblock.tag.ListTag; import org.bukkit.event.inventory.InventoryType; public class DefaultContainersSection extends SettingsContainerHolder implements SettingsManager.DefaultContainers { @Override public boolean isEnabled() { return getContainer().defaultContainersEnabled; } public ListTag getContents(InventoryType inventoryType) { return getContainer().defaultContainersContents.get(inventoryType); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.util.Collections; import java.util.Map; public class DefaultValuesSection extends SettingsContainerHolder implements SettingsManager.DefaultValues { @Override public int getIslandSize() { return getContainer().defaultIslandSize; } @Override public Map getBlockLimits() { return getContainer().defaultBlockLimits; } @Override public Map getEntityLimits() { return getContainer().defaultEntityLimits; } @Override public int getWarpsLimit() { return getContainer().defaultWarpsLimit; } @Override public int getTeamLimit() { return getContainer().defaultTeamLimit; } @Override public int getCoopLimit() { return getContainer().defaultCoopLimit; } @Override public double getCropGrowth() { return getContainer().defaultCropGrowth; } @Override public double getSpawnerRates() { return getContainer().defaultSpawnerRates; } @Override public double getMobDrops() { return getContainer().defaultMobDrops; } @Override public BigDecimal getBankLimit() { return getContainer().defaultBankLimit; } @Override public Map[] getGenerators() { Map[] generators = new Map[Dimension.values().size()]; if (!getContainer().defaultGenerator.isEmpty()) { for (Dimension dimension : Dimension.values()) { Map dimensionGeneratorRates = getContainer().defaultGenerator.get(dimension); if (dimensionGeneratorRates != null) generators[dimension.ordinal()] = dimensionGeneratorRates; } } return generators; } @Override public Map> getGeneratorsMap() { return getContainer().defaultGenerator.collect(Dimension.values()); } public EnumerateMap> getRealGeneratorsMap() { return getContainer().defaultGenerator; } @Override public Map getRoleLimits() { return Collections.unmodifiableMap(getContainer().defaultRoleLimits.asMap()); } public Int2IntMapView getRoleLimitsAsView() { return getContainer().defaultRoleLimits; } @Override public Map getIslandEffects() { return getContainer().defaultIslandEffects; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import com.bgsoftware.superiorskyblock.world.entity.EntityCategoryImpl; import com.google.common.base.Preconditions; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.EntityType; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; public class EntityCategoriesSection implements SettingsManager.EntityCategories { private final Map nameToCategory; private final KeyMap> entityToCategory; private final LazyReference> entityCategories = new LazyReference>() { @Override protected List create() { return nameToCategory.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new LinkedList<>(nameToCategory.values())); } }; public EntityCategoriesSection(YamlConfiguration cfg) { this.nameToCategory = loadInternal(cfg); this.entityToCategory = convertEntityToCategoryInternal(this.nameToCategory.values()); } public static void removeInvalidEntityKeys(YamlConfiguration cfg, File file) { boolean removed = false; for (String categoryName : cfg.getKeys(false)) { if (EnumHelper.getEnum(BuiltinEntityCategory.class, categoryName) == null) { List entities = cfg.getStringList(categoryName + ".entities"); Iterator iterator = entities.iterator(); while (iterator.hasNext()) { EntityType entityType = EnumHelper.getEnum(EntityType.class, iterator.next()); if (entityType == null) { iterator.remove(); removed = true; } } if (entities.isEmpty()) { cfg.set(categoryName, null); } else { cfg.set(categoryName + ".entities", entities); } } } if (removed) { try { cfg.save(file); } catch (IOException ignored) { } } } private static Map loadInternal(YamlConfiguration cfg) { Map entityCategories = new HashMap<>(); for (String categoryName : cfg.getKeys(false)) { String key = categoryName.toLowerCase(Locale.ENGLISH); if (entityCategories.containsKey(categoryName)) { Log.warnFromFile("entity-categories.yml", "Duplicate entity category ", categoryName, " - skipping..."); continue; } ConfigurationSection section = cfg.getConfigurationSection(categoryName); BuiltinEntityCategory builtinEntityCategory = EnumHelper.getEnum(BuiltinEntityCategory.class, categoryName.toUpperCase(Locale.ENGLISH)); KeySet entities = builtinEntityCategory != null ? builtinEntityCategory.getEntities() : KeySets.createHashSet(KeyIndicator.ENTITY_TYPE, section.getStringList("entities")); IslandPrivilege spawnPrivilege = getOrRegisterPrivilege(section.getString("actions.SPAWN")); IslandPrivilege damagePrivilege = getOrRegisterPrivilege(section.getString("actions.DAMAGE")); IslandPrivilege interactPrivilege = getOrRegisterPrivilege(section.getString("actions.INTERACT")); IslandFlag spawnerSpawnFlag = getOrRegisterFlag(section.getString("actions.SPAWNER_SPAWN")); IslandFlag naturalSpawnFlag = getOrRegisterFlag(section.getString("actions.NATURAL_SPAWN")); entityCategories.put(key, new EntityCategoryImpl(categoryName, entities, spawnPrivilege, damagePrivilege, interactPrivilege, spawnerSpawnFlag, naturalSpawnFlag)); } // Add rest of built-in entity categories for (BuiltinEntityCategory builtinEntityCategory : BuiltinEntityCategory.values()) { if (!entityCategories.containsKey(builtinEntityCategory.name())) { entityCategories.put(builtinEntityCategory.name(), new EntityCategoryImpl(builtinEntityCategory.name(), builtinEntityCategory.getEntities(), null, null, null, null, null)); } } return Collections.unmodifiableMap(entityCategories); } private static KeyMap> convertEntityToCategoryInternal(Collection entityCategories) { KeyMap> categories = KeyMaps.createHashMap(KeyIndicator.ENTITY_TYPE); for (EntityCategory entityCategory : entityCategories) { for (Key key : entityCategory.getEntities()) { categories.computeIfAbsent(key, k -> new LinkedList<>()).add(entityCategory); } } if (categories.isEmpty()) return KeyMaps.createEmptyMap(); // Convert keyMap to unmodifiable. KeyMap> categoriesUnmodifiable = KeyMaps.createHashMap(KeyIndicator.ENTITY_TYPE); categories.forEach((key, value) -> categoriesUnmodifiable.put(key, Collections.unmodifiableList(value))); return KeyMaps.unmodifiableKeyMap(categoriesUnmodifiable); } @Override public List getCategories() { return this.entityCategories.get(); } @Override public List getCategories(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null"); return this.entityToCategory.getOrDefault(key, Collections.emptyList()); } @Override public EntityCategory getCategoryByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null"); return this.nameToCategory.get(name.toLowerCase(Locale.ENGLISH)); } @Nullable private static IslandPrivilege getOrRegisterPrivilege(@Nullable String name) { if (name == null) return null; try { return IslandPrivilege.getByName(name); } catch (NullPointerException error) { IslandPrivilege.register(name); return IslandPrivilege.getByName(name); } } @Nullable private static IslandFlag getOrRegisterFlag(@Nullable String name) { if (name == null) return null; try { return IslandFlag.getByName(name); } catch (NullPointerException error) { IslandFlag.register(name); return IslandFlag.getByName(name); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import java.math.BigInteger; import java.math.RoundingMode; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; public class GlobalSection extends SettingsContainerHolder { public long getCalcInterval() { return getContainer().calcInterval; } public String getIslandCommand() { return getContainer().islandCommand; } public int getMaxIslandSize() { return getContainer().maxIslandSize; } public int getIslandHeight() { return getContainer().islandsHeight; } public int getSeaLevelHeight() { return getContainer().seaLevelHeight; } public boolean isWorldBorders() { return getContainer().worldBordersEnabled; } public String getBlockLevelFormula() { return getContainer().blockLevelFormula; } public boolean isRoundedIslandLevels() { return getContainer().roundedIslandLevel; } public RoundingMode getIslandLevelRoundingMode() { return getContainer().islandLevelRoundingMode; } public boolean isAutoBlocksTracking() { return getContainer().autoBlocksTracking; } public SortingType getIslandTopOrder() { return getContainer().islandTopOrder; } public SortingType getGlobalWarpsOrder() { return getContainer().globalWarpsOrder; } public boolean isCoopMembers() { return getContainer().coopMembers; } public boolean isEditPlayerPermissions() { return getContainer().editPlayerPermissions; } public String getSignWarpLine() { return getContainer().signWarpLine; } public List getSignWarp() { return getContainer().signWarp; } public SettingsManager.Interactables getInteractablesMap() { return getContainer().interactables; } public Collection getSafeBlocks() { return getContainer().safeBlocks; } public Collection getWorldPermissions() { return getContainer().worldPermissions; } public boolean isVisitorsDamage() { return getContainer().visitorsDamage; } public boolean isCoopDamage() { return getContainer().coopDamage; } public int getDisbandCount() { return getContainer().defaultDisbandCount; } public boolean isIslandTopIncludeLeader() { return getContainer().islandTopIncludeLeader; } public Map getDefaultPlaceholders() { return getContainer().defaultPlaceholders; } public boolean isBanConfirm() { return getContainer().banConfirm; } public boolean isDisbandConfirm() { return getContainer().disbandConfirm; } public boolean isKickConfirm() { return getContainer().kickConfirm; } public boolean isLeaveConfirm() { return getContainer().leaveConfirm; } public boolean isTransferConfirm() { return getContainer().transferConfirm; } public String getSpawnersProvider() { return getContainer().spawnersProvider; } public String getStackedBlocksProvider() { return getContainer().stackedBlocksProvider; } public boolean isTeleportOnCreate() { return getContainer().teleportOnCreate; } public boolean isTeleportOnJoin() { return getContainer().teleportOnJoin; } public boolean isTeleportOnKick() { return getContainer().teleportOnKick; } public boolean isTeleportOnLeave() { return getContainer().teleportOnLeave; } public List getClearActionsOnDisband() { return getContainer().clearActionsOnDisband; } public List getClearActionsOnJoin() { return getContainer().clearActionsOnJoin; } public List getClearActionsOnKick() { return getContainer().clearActionsOnKick; } public List getClearActionsOnLeave() { return getContainer().clearActionsOnLeave; } public boolean isRateOwnIsland() { return getContainer().rateOwnIsland; } public boolean isChangeIslandRating() { return getContainer().changeIslandRating; } public List getDefaultSettings() { return getContainer().defaultSettings; } public boolean isDisableRedstoneOffline() { return getContainer().disableRedstoneOffline; } public Map> getCommandsCooldown() { return getContainer().commandsCooldown; } public long getUpgradeCooldown() { return getContainer().upgradeCooldown; } public String getNumbersFormat() { return getContainer().numberFormat; } public String getDateFormat() { return getContainer().dateFormat; } public boolean isSkipOneItemMenus() { return getContainer().skipOneItemMenus; } public boolean isTeleportOnPvPEnable() { return getContainer().teleportOnPVPEnable; } public boolean isImmuneToPvPWhenTeleport() { return getContainer().immuneToPVPWhenTeleport; } public List getBlockedVisitorsCommands() { return getContainer().blockedVisitorsCommands; } public List getDefaultSign() { return getContainer().defaultSignLines; } public Map> getEventCommands() { return getContainer().eventCommands; } public long getWarpsWarmup() { return getContainer().warpsWarmup; } public long getHomeWarmup() { return getContainer().homeWarmup; } public long getVisitWarmup() { return getContainer().visitWarmup; } public boolean isLiquidUpdate() { return getContainer().liquidUpdate; } public boolean isLightsUpdate() { return getContainer().lightsUpdate; } public List getPvPWorlds() { return getContainer().pvpWorlds; } public boolean isStopLeaving() { return getContainer().stopLeaving; } public boolean isValuesMenu() { return getContainer().valuesMenu; } public List getCropsToGrow() { return getContainer().cropsToGrow; } public int getCropsInterval() { return getContainer().cropsInterval; } public boolean isOnlyBackButton() { return getContainer().onlyBackButton; } public boolean isBuildOutsideIsland() { return getContainer().buildOutsideIsland; } public String getDefaultLanguage() { return getContainer().defaultLanguage; } public boolean isDefaultWorldBorder() { return getContainer().defaultWorldBorder; } public boolean isDefaultStackedBlocks() { return getContainer().defaultBlocksStacker; } public boolean isDefaultToggledPanel() { return getContainer().defaultToggledPanel; } public boolean isDefaultIslandFly() { return getContainer().defaultIslandFly; } public String getDefaultBorderColor() { return getContainer().defaultBorderColor; } public boolean isObsidianToLava() { return getContainer().obsidianToLava; } public BlockValuesManager.SyncWorthStatus getSyncWorth() { return getContainer().syncWorth; } public boolean isNegativeWorth() { return getContainer().negativeWorth; } public boolean isNegativeLevel() { return getContainer().negativeLevel; } public List getDisabledEvents() { return getContainer().disabledEvents; } public List getDisabledCommands() { return getContainer().disabledCommands; } public List getDisabledHooks() { return getContainer().disabledHooks; } public boolean isSchematicNameArgument() { return getContainer().schematicNameArgument; } public Map> getCommandAliases() { return getContainer().commandAliases; } public Set getValuableBlocks() { return getContainer().valuableBlocks; } public boolean isTabCompleteHideVanished() { return getContainer().tabCompleteHideVanished; } public boolean isDropsUpgradePlayersMultiply() { return getContainer().dropsUpgradePlayersMultiply; } public Map getMessageDelays() { return getContainer().messageDelays; } public boolean isWarpCategories() { return getContainer().warpCategories; } public boolean isPhysicsListener() { return getContainer().physicsListener; } public double getChargeOnWarp() { return getContainer().chargeOnWarp; } public boolean isPublicWarps() { return getContainer().publicWarps; } public boolean isLockedIslands() { return getContainer().lockedIslands; } public long getRecalcTaskTimeout() { return getContainer().recalcTaskTimeout; } public boolean isAutoLanguageDetection() { return getContainer().autoLanguageDetection; } public boolean isAutoUncoopWhenAlone() { return getContainer().autoUncoopWhenAlone; } public TopIslandMembersSorting getTopIslandMembersSorting() { return getContainer().islandTopMembersSorting; } public int getBossbarLimit() { return getContainer().bossBarLimit; } public boolean getDeleteUnsafeWarps() { return getContainer().deleteUnsafeWarps; } public List getPlayerRespawn() { return getContainer().playerRespawnActions; } public BigInteger getBlockCountsSaveThreshold() { return getContainer().blockCountsSaveThreshold; } public boolean getChatSigningSupport() { return getContainer().chatSigningSupport; } public int getCommandsPerPage() { return getContainer().commandsPerPage; } public boolean isHelpOnInvalidCommand() { return getContainer().helpOnInvalidCommand; } public boolean isHelpOnNoPermission() { return getContainer().helpOnNoPermission; } public boolean isCacheSchematics() { return getContainer().cacheSchematics; } public SettingsManager.EntityCategories getEntityCategoriesMap() { return getContainer().entityCategories; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Material; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.Comparator; import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; public class InteractablesSection implements SettingsManager.Interactables { private static final LazyReference PRIVILEGE_CHEST_ACCESS = lazyIslandPrivilege("CHEST_ACCESS"); private static final LazyReference PRIVILEGE_FARM_TRAMPING = lazyIslandPrivilege("FARM_TRAMPING"); private static final LazyReference PRIVILEGE_INTERACT = lazyIslandPrivilege("INTERACT"); private static final LazyReference PRIVILEGE_PICKUP_LECTERN_BOOK = lazyIslandPrivilege("PICKUP_LECTERN_BOOK"); private static final LazyReference PRIVILEGE_SIGN_INTERACT = lazyIslandPrivilege("SIGN_INTERACT"); private static final LazyReference PRIVILEGE_SPAWNER_BREAK = lazyIslandPrivilege("SPAWNER_BREAK"); private static final LazyReference PRIVILEGE_TURTLE_EGG_TRAMPING = lazyIslandPrivilege("TURTLE_EGG_TRAMPING"); private static final LazyReference PRIVILEGE_USE = lazyIslandPrivilege("USE"); private static final Material FARMLAND = EnumHelper.getEnum(Material.class, "FARMLAND", "SOIL"); @Nullable private static final Material ROOTED_DIRT = EnumHelper.getEnum(Material.class, "ROOTED_DIRT"); @Nullable private static final Material TURTLE_EGG = EnumHelper.getEnum(Material.class, "TURTLE_EGG"); @Nullable private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, "SWEET_BERRY_BUSH"); @Nullable private static final Material CAVE_VINES = EnumHelper.getEnum(Material.class, "CAVE_VINES"); @Nullable private static final Material CAVE_VINES_PLANT = EnumHelper.getEnum(Material.class, "CAVE_VINES_PLANT"); @Nullable private static final Material LECTERN = EnumHelper.getEnum(Material.class, "LECTERN"); @Nullable private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); @Nullable private static final Material BLAST_FURNACE = EnumHelper.getEnum(Material.class, "BLAST_FURNACE"); @Nullable private static final Material BURNING_FURNACE = EnumHelper.getEnum(Material.class, "BURNING_FURNACE"); @Nullable private static final Material CHISELED_BOOKSHELF = EnumHelper.getEnum(Material.class, "CHISELED_BOOKSHELF"); @Nullable private static final Material CRAFTER = EnumHelper.getEnum(Material.class, "CRAFTER"); @Nullable private static final Material DECORATED_POT = EnumHelper.getEnum(Material.class, "DECORATED_POT"); @Nullable private static final Material SMOKER = EnumHelper.getEnum(Material.class, "SMOKER"); private final Map privilegeToInteractables; private final KeyMap interactableToPrivilege; private final SuperiorSkyblockPlugin plugin; private final boolean legacy; public InteractablesSection(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) { this.plugin = plugin; this.legacy = cfg.getKeys(false).size() == 1 && cfg.isList("interactables"); Map privilegeToInteractables = new IdentityHashMap<>(); if (this.legacy) { loadLegacyInternal(cfg, privilegeToInteractables); } else { loadInternal(cfg, privilegeToInteractables); } this.privilegeToInteractables = privilegeToInteractables.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(privilegeToInteractables); this.interactableToPrivilege = convertView(privilegeToInteractables); } private static KeyMap convertView(Map base) { KeyMap converted = KeyMaps.createHashMap(KeyIndicator.MATERIAL); base.forEach((islandPrivilege, keySet) -> { for (Key key : keySet) { IslandPrivilege oldPrivilege = converted.put(key, islandPrivilege); if (oldPrivilege != null) { Log.warnFromFile("interactables.yml", "The interactable block ", key, " had two privileges: ", oldPrivilege, ", ", islandPrivilege); } } }); return KeyMaps.unmodifiableKeyMap(converted); } public boolean isLegacy() { return legacy; } @Override public Set getInteractables() { return Collections.unmodifiableSet(this.interactableToPrivilege.keySet()); } @Override @Nullable public Set getInteractables(IslandPrivilege islandPrivilege) { Set interactables = this.privilegeToInteractables.get(islandPrivilege); return interactables == null || interactables.isEmpty() ? null : Collections.unmodifiableSet(interactables); } @Override @Nullable public IslandPrivilege getRequiredPrivilege(Key key) { return this.interactableToPrivilege.get(key); } public void saveToFile(File file) throws IOException { CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(plugin.getResource("interactables.yml")); Set islandPrivileges = new TreeSet<>(Comparator.comparing(IslandPrivilege::getName)); islandPrivileges.addAll(this.privilegeToInteractables.keySet()); boolean copyHeaderComment = true; for(IslandPrivilege islandPrivilege : islandPrivileges) { Set keys = new TreeSet<>(String::compareTo); this.privilegeToInteractables.get(islandPrivilege).forEach(key -> keys.add(key.toString())); cfg.set(islandPrivilege.getName(), new LinkedList<>(keys)); if (copyHeaderComment) { copyHeaderComment = false; cfg.setComment(islandPrivilege.getName(), cfg.getComment("interactables")); } else { cfg.setComment(islandPrivilege.getName(), ""); } } // Remove the default interactables cfg.set("interactables", null); cfg.save(file); } private static void loadLegacyInternal(YamlConfiguration cfg, Map interactablesMap) { List interactables = cfg.getStringList("interactables"); for (String blockType : interactables) { Key blockKey = Key.ofMaterialAndData(blockType); IslandPrivilege islandPrivilege; try { Material material = ((MaterialKey) blockKey).getMaterial(); if (Materials.isChest(material)) { islandPrivilege = PRIVILEGE_CHEST_ACCESS.get(); } else if (material == LECTERN) { islandPrivilege = PRIVILEGE_PICKUP_LECTERN_BOOK.get(); } else if (isInventoryHolder(material)) { islandPrivilege = PRIVILEGE_USE.get(); } else if (Materials.isSign(material)) { islandPrivilege = PRIVILEGE_SIGN_INTERACT.get(); } else if (material == Materials.SPAWNER.toBukkitType()) { islandPrivilege = PRIVILEGE_SPAWNER_BREAK.get(); } else if (material == FARMLAND || material == ROOTED_DIRT || material == SWEET_BERRY_BUSH || material == CAVE_VINES || material == CAVE_VINES_PLANT) { islandPrivilege = PRIVILEGE_FARM_TRAMPING.get(); } else if (material == TURTLE_EGG) { islandPrivilege = PRIVILEGE_TURTLE_EGG_TRAMPING.get(); } else { islandPrivilege = PRIVILEGE_INTERACT.get(); } } catch (Throwable ignored) { // In the case this is a custom block or something, default to INTERACT privilege. islandPrivilege = PRIVILEGE_INTERACT.get(); } interactablesMap.computeIfAbsent(islandPrivilege, p -> KeySets.createHashSet(KeyIndicator.MATERIAL)) .add(blockKey); } } private static boolean isInventoryHolder(Material material) { return Materials.isShelf(material) || material == BLAST_FURNACE || material == Material.BREWING_STAND || material == BURNING_FURNACE || material == CHISELED_BOOKSHELF || material == CRAFTER || material == DECORATED_POT || material == Material.DISPENSER || material == Material.DROPPER || material == Material.FURNACE || material == Material.HOPPER || material == Material.JUKEBOX || material == SMOKER || material == VAULT; } private static void loadInternal(YamlConfiguration cfg, Map interactablesMap) { for (String islandPrivilegeName : cfg.getKeys(false)) { try { IslandPrivilege.register(islandPrivilegeName); } catch (IllegalStateException ignored) { } IslandPrivilege islandPrivilege = IslandPrivilege.getByName(islandPrivilegeName); KeySet keys = KeySets.createHashSet(KeyIndicator.MATERIAL, cfg.getStringList(islandPrivilegeName)); interactablesMap.put(islandPrivilege, keys); } } private static LazyReference lazyIslandPrivilege(String name) { return new LazyReference() { @Override protected IslandPrivilege create() { try { IslandPrivilege.register(name); } catch (IllegalStateException ignored) { } return IslandPrivilege.getByName(name); } }; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandChestsSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; public class IslandChestsSection extends SettingsContainerHolder implements SettingsManager.IslandChests { @Override public String getChestTitle() { return getContainer().islandChestTitle; } @Override public int getDefaultPages() { return getContainer().islandChestsDefaultPage; } @Override public int getDefaultSize() { return getContainer().islandChestsDefaultSize; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandNamesSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import java.util.List; public class IslandNamesSection extends SettingsContainerHolder implements SettingsManager.IslandNames { @Override public boolean isRequiredForCreation() { return getContainer().islandNamesRequiredForCreation; } @Override public int getMaxLength() { return getContainer().islandNamesMaxLength; } @Override public int getMinLength() { return getContainer().islandNamesMinLength; } @Override public List getFilteredNames() { return getContainer().filteredIslandNames; } @Override public boolean isColorSupport() { return getContainer().islandNamesColorSupport; } @Override public boolean isIslandTop() { return getContainer().islandNamesIslandTop; } @Override public boolean isPreventPlayerNames() { return getContainer().islandNamesPreventPlayerNames; } @Override public boolean isAnnounceChangeToAll() { return getContainer().islandNamesAnnounceChangeToAll; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandPreviewsSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import org.bukkit.GameMode; import org.bukkit.Location; import java.util.List; import java.util.Map; public class IslandPreviewsSection extends SettingsContainerHolder implements SettingsManager.IslandPreviews { @Override public GameMode getGameMode() { return getContainer().islandPreviewsGameMode; } @Override public int getMaxDistance() { return getContainer().islandPreviewsMaxDistance; } @Override public List getBlockedCommands() { return getContainer().islandPreviewsBlockedCommands; } @Override public Map getLocations() { return getContainer().islandPreviewsLocations; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandRolesSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import org.bukkit.configuration.ConfigurationSection; public class IslandRolesSection extends SettingsContainerHolder implements SettingsManager.IslandRoles { @Override public ConfigurationSection getSection() { return getContainer().islandRolesSection; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/SpawnSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import java.util.List; public class SpawnSection extends SettingsContainerHolder implements SettingsManager.Spawn { @Override public String getLocation() { return getContainer().spawnLocation; } @Override public boolean isProtected() { return getContainer().spawnProtection; } @Override public List getSettings() { return getContainer().spawnSettings; } @Override public List getPermissions() { return getContainer().spawnPermissions; } @Override public boolean isWorldBorder() { return getContainer().spawnWorldBorder; } @Override public int getSize() { return getContainer().spawnSize; } @Override public boolean isPlayersDamage() { return getContainer().spawnDamage; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/StackedBlocksSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import java.util.List; import java.util.Map; import java.util.Set; public class StackedBlocksSection extends SettingsContainerHolder implements SettingsManager.StackedBlocks { private final DepositMenu depositMenu = new DepositMenuSection(); @Override public boolean isEnabled() { return getContainer().stackedBlocksEnabled; } @Override public String getCustomName() { return getContainer().stackedBlocksName; } @Override public List getDisabledWorlds() { return getContainer().stackedBlocksDisabledWorlds; } @Override public Set getWhitelisted() { return getContainer().whitelistedStackedBlocks; } @Override public Map getLimits() { return getContainer().stackedBlocksLimits; } @Override public boolean isAutoCollect() { return getContainer().stackedBlocksAutoPickup; } @Override public DepositMenu getDepositMenu() { return this.depositMenu; } private class DepositMenuSection implements DepositMenu { @Override public boolean isEnabled() { return getContainer().stackedBlocksMenuEnabled; } @Override public String getTitle() { return getContainer().stackedBlocksMenuTitle; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/VisitorsSignSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; public class VisitorsSignSection extends SettingsContainerHolder implements SettingsManager.VisitorsSign { @Override public boolean isRequiredForVisit() { return getContainer().visitorsSignRequiredForVisit; } @Override public String getLine() { return getContainer().visitorsSignLine; } @Override public String getActive() { return getContainer().visitorsSignActive; } @Override public String getInactive() { return getContainer().visitorsSignInactive; } @Override public String getDescriptionLineFormat() { return getContainer().visitorsSignDescriptionLineFormat; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/VoidTeleportSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; public class VoidTeleportSection extends SettingsContainerHolder implements SettingsManager.VoidTeleport { @Override public boolean isMembers() { return getContainer().voidTeleportMembers; } @Override public boolean isVisitors() { return getContainer().voidTeleportVisitors; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java ================================================ package com.bgsoftware.superiorskyblock.config.section; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import java.util.Collections; import java.util.EnumMap; import java.util.Map; public class WorldsSection extends SettingsContainerHolder implements SettingsManager.Worlds { @Override public Dimension getDefaultWorldDimension() { return getContainer().defaultWorldDimension; } @Override @Deprecated public World.Environment getDefaultWorld() { return getDefaultWorldDimension().getEnvironment(); } @Override public String getWorldName() { return getContainer().islandWorldName; } @Override public String getDefaultWorldName() { return getContainer().defaultWorldName; } @Override public Normal getNormal() { return (Normal) getDimensionConfig(Dimension.getByName("NORMAL")); } @Override public Nether getNether() { return (Nether) getDimensionConfig(Dimension.getByName("NETHER")); } @Override public End getEnd() { return (End) getDimensionConfig(Dimension.getByName("THE_END")); } @Override public String getDifficulty() { return getContainer().worldsDifficulty; } @Override public int getSeaLevelHeight() { return getContainer().seaLevelHeight; } @Override public DimensionConfig getDimensionConfig(Dimension dimension) { return getContainer().dimensionConfigs.get(dimension); } public static abstract class BaseDimensionConfig implements DimensionConfig { private final boolean isEnabled; private final boolean isUnlocked; private final boolean isSchematicOffset; private final String biome; private final String name; private final Map portalAgents; protected BaseDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) { this.isEnabled = section.getBoolean("enabled"); this.isUnlocked = section.getBoolean("unlock"); this.isSchematicOffset = section.getBoolean("schematic-offset"); this.biome = section.getString("biome"); String name = section.getString("name"); this.name = Text.isBlank(name) ? defaultName : name; this.portalAgents = loadPortalAgents(section.getConfigurationSection("portals"), dimension); } private static Map loadPortalAgents(@Nullable ConfigurationSection portals, Dimension dimension) { EnumMap portalAgents = new EnumMap<>(PortalType.class); if (portals == null) { // Map environment to dimension Dimension normalDimension; Dimension netherDimension; Dimension endDimension; { EnumMap environmentToDimension = new EnumMap<>(World.Environment.class); for (Dimension dim : Dimension.values()) { Dimension currentDimension = environmentToDimension.get(dim.getEnvironment()); if (currentDimension == null || dim.ordinal() < currentDimension.ordinal()) environmentToDimension.put(dim.getEnvironment(), dim); } normalDimension = environmentToDimension.get(World.Environment.NORMAL); netherDimension = environmentToDimension.get(World.Environment.NETHER); endDimension = environmentToDimension.get(World.Environment.THE_END); } // Set portal agent switch (dimension.getEnvironment()) { case NORMAL: if (netherDimension != null) portalAgents.put(PortalType.NETHER, netherDimension); if (endDimension != null) portalAgents.put(PortalType.ENDER, endDimension); break; case NETHER: if (normalDimension != null) portalAgents.put(PortalType.NETHER, normalDimension); if (endDimension != null) portalAgents.put(PortalType.ENDER, endDimension); break; case THE_END: if (netherDimension != null) portalAgents.put(PortalType.NETHER, netherDimension); if (normalDimension != null) portalAgents.put(PortalType.ENDER, normalDimension); break; } } else { for (PortalType portalType : PortalType.values()) { String destination = portals.getString(portalType.name()); if (destination != null) { try { portalAgents.put(portalType, Dimension.getByName(destination)); } catch (NullPointerException error) { Log.warnFromFile("config.yml", "Cannot find valid dimension ", destination, " - skipping..."); } } } } return portalAgents.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(portalAgents); } @Override public boolean isEnabled() { return this.isEnabled; } @Override public boolean isUnlocked() { return this.isUnlocked; } @Override public boolean isSchematicOffset() { return this.isSchematicOffset; } @Override public String getBiome() { return this.biome; } @Override public String getName() { return this.name; } @Override public Dimension getPortalDestination(PortalType portalType) { return this.portalAgents.get(portalType); } } public static class NormalDimensionConfig extends BaseDimensionConfig implements Normal { public NormalDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) { super(section, dimension, defaultName); } } public static class NetherDimensionConfig extends BaseDimensionConfig implements Nether { public NetherDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) { super(section, dimension, defaultName); } } public static class EndDimensionConfig extends BaseDimensionConfig implements End { private final boolean isDragonFlight; private final BlockOffset portalOffset; public EndDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) { super(section, dimension, defaultName); this.isDragonFlight = section.getBoolean("dragon-fight.enabled") && ServerVersion.isAtLeast(ServerVersion.v1_9); String portalOffset = section.getString("dragon-fight.portal-offset"); BlockOffset endDragonFightPortalOffset = Serializers.OFFSET_SPACED_SERIALIZER.deserialize(portalOffset); if (endDragonFightPortalOffset == null) { Log.warnFromFile("config.yml", "Cannot parse portal-offset '", portalOffset, "' to a valid offset, skipping..."); this.portalOffset = SBlockOffset.ZERO; } else { this.portalOffset = endDragonFightPortalOffset; } } @Override public boolean isDragonFight() { return this.isDragonFlight; } @Override public BlockOffset getPortalOffset() { return this.portalOffset; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/BaseCacheImpl.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.google.common.base.Preconditions; import java.util.Collection; import java.util.function.Function; @SuppressWarnings("unchecked") public class BaseCacheImpl { private final Synchronized> cache; public BaseCacheImpl(Collection keys) { this.cache = Synchronized.of(new EnumerateMap<>(keys)); } public final T store(K key, T value) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(value, "value parameter cannot be null"); Object oldValue = this.cache.writeAndGet(cache -> cache.put(key, value)); return oldValue == null ? null : (T) oldValue; } public T remove(K key) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Object oldValue = this.cache.writeAndGet(cache -> cache.remove(key)); return oldValue == null ? null : (T) oldValue; } public T get(K key) { return getOrDefault(key, null); } public T getOrDefault(K key, T def) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Object oldValue = this.cache.readAndGet(cache -> cache.get(key)); return oldValue == null ? def : (T) oldValue; } public T computeIfAbsent(K key, Function mappingFunction) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(mappingFunction, "mappingFunction parameter cannot be null"); return (T) this.cache.writeAndGet(cache -> { Object value = cache.get(key); if (value == null) { value = mappingFunction.apply(key); cache.put(key, value); } return value; }); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/BigBitSet.java ================================================ package com.bgsoftware.superiorskyblock.core; import java.util.BitSet; public class BigBitSet { private static final int DEFAULT_CAPACITY = 4096 * 64; private final BitSet[] backend; private int size; public BigBitSet(int nbits) { this.backend = new BitSet[(int) Math.ceil((double) nbits / DEFAULT_CAPACITY)]; this.size = 0; } public int size() { return this.size; } public void set(int pos) { try { int backendIdx = pos / DEFAULT_CAPACITY; int bitSetIdx = pos % DEFAULT_CAPACITY; BitSet bitSet = this.backend[backendIdx]; if (bitSet == null) bitSet = this.backend[backendIdx] = new BitSet(DEFAULT_CAPACITY); bitSet.set(bitSetIdx); ++this.size; } catch (IndexOutOfBoundsException error) { throw new IndexOutOfBoundsException("Out of bounds for pos " + pos); } } public int nextSetBit(int fromIndex) { int backendIdx = fromIndex / DEFAULT_CAPACITY; int bitSetIdx = fromIndex % DEFAULT_CAPACITY; return nextSetBitInternal(backendIdx, bitSetIdx); } private int nextSetBitInternal(int backendIdx, int bitSetIdx) { if (backendIdx < 0 || backendIdx >= this.backend.length) return -1; BitSet bitSet = this.backend[backendIdx]; if (bitSet != null) { int next = bitSet.nextSetBit(bitSetIdx); if (next != -1) { return backendIdx * DEFAULT_CAPACITY + next; } } return nextSetBitInternal(backendIdx + 1, 0); } public int cardinality() { int cardinality = 0; for (BitSet bitSet : backend) { if (bitSet != null) cardinality += bitSet.cardinality(); } return cardinality; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/ByteBigArray.java ================================================ package com.bgsoftware.superiorskyblock.core; import java.util.Arrays; public class ByteBigArray { private static final short DEFAULT_CAPACITY = 4096; private static final byte[][] EMPTY_BIG_ARRAY = {}; private byte[][] backend; private final short capacity; private int backendIdx = 0; private short innerSize = 0; private int size = 0; private boolean readOnly = false; public ByteBigArray() { this(DEFAULT_CAPACITY); } public ByteBigArray(short capacity) { this.capacity = capacity; this.backend = EMPTY_BIG_ARRAY; } public int size() { return this.size; } public void add(byte val) { if (this.readOnly) throw new IllegalStateException("Cannot alter big arrays that are finalized"); getNextInnerArray()[this.innerSize++] = val; ++this.size; } public byte get() { return getNextInnerArray()[this.innerSize]; } public byte get(int pos) { int backendIdx = pos / this.capacity; int innerIdx = pos % this.capacity; return this.backend[backendIdx][innerIdx]; } public ByteBigArray readOnly() { int backendIdx = this.size / this.capacity; int innerSize = this.size % this.capacity; this.backend = Arrays.copyOf(this.backend, backendIdx + 1); this.backend[this.backend.length - 1] = Arrays.copyOf(this.backend[this.backend.length - 1], innerSize); this.readOnly = true; return this; } private byte[] getNextInnerArray() { if (this.innerSize >= this.capacity) { ++this.backendIdx; this.innerSize = 0; } if (this.backendIdx >= this.backend.length) { this.backend = Arrays.copyOf(this.backend, this.backend.length + 1); this.backend[this.backendIdx] = new byte[this.capacity]; this.innerSize = 0; } return this.backend[this.backendIdx]; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/CalculatedChunk.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import org.bukkit.Location; import java.util.List; public class CalculatedChunk { private final ChunkPosition chunkPosition; protected CalculatedChunk(ChunkPosition chunkPosition) { this.chunkPosition = chunkPosition; } public ChunkPosition getPosition() { return chunkPosition; } public static class Blocks extends CalculatedChunk { private final KeyMap blockCounts; private final List spawners; public Blocks(ChunkPosition chunkPosition, KeyMap blockCounts, List spawners) { super(chunkPosition); this.blockCounts = blockCounts; this.spawners = spawners; } public KeyMap getBlockCounts() { return blockCounts; } public List getSpawners() { return spawners; } } public static class Entities extends CalculatedChunk { private final KeyMap entityCounts; public Entities(ChunkPosition chunkPosition, KeyMap entityCounts) { super(chunkPosition); this.entityCounts = entityCounts; } public KeyMap getEntityCounts() { return entityCounts; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import java.lang.ref.WeakReference; import java.util.Objects; import java.util.Optional; public class ChunkPosition implements ObjectsPool.Releasable, AutoCloseable { private static final ObjectsPool POOL = new ObjectsPool<>(ChunkPosition::new); protected WorldInfo worldInfo; protected int x; protected int z; protected long pairedXZ = -1; @Nullable protected WeakReference cachedBukkitWorld = new WeakReference<>(null); private final boolean isPool; public static ChunkPosition of(Location location) { World world = location.getWorld(); return of(WorldInfo.of(world), location.getBlockX() >> 4, location.getBlockZ() >> 4).withBukkitWorld(world); } public static ChunkPosition of(WorldInfo worldInfo, WorldPosition worldPosition) { BlockPosition blockPosition = worldPosition.toBlockPosition(); return of(worldInfo, blockPosition.getX() >> 4, blockPosition.getZ() >> 4); } public static ChunkPosition of(Chunk chunk) { return of(chunk, true); } public static ChunkPosition of(Chunk chunk, boolean fromPool) { World world = chunk.getWorld(); return of(WorldInfo.of(world), chunk.getX(), chunk.getZ(), fromPool).withBukkitWorld(world); } public static ChunkPosition of(World world, int x, int z) { return of(world, x, z, true); } public static ChunkPosition of(World world, int x, int z, boolean fromPool) { return of(WorldInfo.of(world), x, z, fromPool).withBukkitWorld(world); } public static ChunkPosition of(WorldInfo worldInfo, int x, int z) { return of(worldInfo, x, z, true); } public static ChunkPosition of(WorldInfo worldInfo, int x, int z, boolean fromPool) { ChunkPosition chunkPosition = fromPool ? POOL.obtain() : new ChunkPosition(false); return chunkPosition.initialize(worldInfo, x, z); } public static ChunkPosition of(IslandWarp islandWarp) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return of(islandWarp.getLocation(wrapper.getHandle())); } } protected ChunkPosition() { this(true); } protected ChunkPosition(boolean isPool) { this.isPool = isPool; } private ChunkPosition initialize(WorldInfo worldInfo, int x, int z) { this.worldInfo = worldInfo; this.x = x; this.z = z; return this; } public World getWorld() { World cachedBukkitWorld = this.cachedBukkitWorld.get(); if (cachedBukkitWorld == null) { cachedBukkitWorld = Bukkit.getWorld(getWorldName()); this.cachedBukkitWorld = new WeakReference<>(cachedBukkitWorld); } return cachedBukkitWorld; } public WorldInfo getWorldsInfo() { return this.worldInfo; } public String getWorldName() { return this.worldInfo.getName(); } public int getX() { return x; } public int getZ() { return z; } public long asPair() { if (this.pairedXZ < 0) pairedXZ = (long) this.x & 4294967295L | ((long) this.z & 4294967295L) << 32; return pairedXZ; } public boolean isInsideChunk(Location location) { return location.getWorld().getName().equals(worldInfo.getName()) && location.getBlockX() >> 4 == x && location.getBlockZ() >> 4 == z; } public int distanceSquared(ChunkPosition other) { int deltaX = this.x - other.x; int deltaZ = this.z - other.z; return (deltaX * deltaX) + (deltaZ * deltaZ); } @Override public void release() { if (!isPool) return; this.worldInfo = null; this.pairedXZ = -1; this.cachedBukkitWorld.clear(); POOL.release(this); } public ChunkPosition copy() { return new ChunkPosition(false).initialize(this.worldInfo, this.x, this.z); } @Override public void close() { release(); } @Override public int hashCode() { return Objects.hash(worldInfo.getName(), x, z); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ChunkPosition that = (ChunkPosition) o; return x == that.x && z == that.z && worldInfo.getName().equals(that.worldInfo.getName()); } @Override public String toString() { return worldInfo.getName() + ", " + x + ", " + z; } private ChunkPosition withBukkitWorld(World world) { this.cachedBukkitWorld = new WeakReference<>(world); return this; } public static Optional getLoadedChunk(ChunkPosition chunkPosition) { boolean isChunkLoaded = chunkPosition.getWorld().isChunkLoaded(chunkPosition.getX(), chunkPosition.getZ()); if (!isChunkLoaded) return Optional.empty(); return Optional.of(chunkPosition.getWorld().getChunkAt(chunkPosition.getX(), chunkPosition.getZ())); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/Counter.java ================================================ package com.bgsoftware.superiorskyblock.core; public class Counter { private int value; public Counter(int initialValue) { this.value = initialValue; } public int inc(int delta) { int original = this.value; this.value += delta; return original; } public int set(int value) { int original = this.value; this.value = value; return original; } public int get() { return this.value; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/DirtyChunk.java ================================================ package com.bgsoftware.superiorskyblock.core; import java.util.Objects; public class DirtyChunk { private final String worldName; private final int x; private final int z; public DirtyChunk(String worldName, int x, int z) { this.worldName = worldName; this.x = x; this.z = z; } public String getWorldName() { return worldName; } public int getX() { return x; } public int getZ() { return z; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DirtyChunk that = (DirtyChunk) o; return x == that.x && z == that.z && worldName.equals(that.worldName); } @Override public int hashCode() { return Objects.hash(worldName, x, z); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/DynamicArray.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import java.util.Arrays; import java.util.List; public class DynamicArray { private Object[] elements; public DynamicArray() { this(0); } public DynamicArray(int capacity) { this.elements = new Object[capacity]; } @Nullable public E get(int index) { rangeCheck(index); return (E) elements[index]; } @Nullable public E set(int index, E element) { ensureCapacity(index + 1); E current = (E) elements[index]; elements[index] = element; return current; } public int length() { return this.elements.length; } public List toList() { return Arrays.asList((E[]) this.elements); } private void rangeCheck(int index) { if (index < 0 || index > elements.length) throw new ArrayIndexOutOfBoundsException("Index: " + index + ", Size: " + elements.length); } private void ensureCapacity(int capacity) { if (capacity > elements.length) { this.elements = Arrays.copyOf(this.elements, capacity); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/Either.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import java.util.function.Consumer; public abstract class Either { public static Either right(R value) { return new Right<>(value); } public static Either left(L value) { return new Left<>(value); } public abstract Either ifRight(Consumer consumer); public abstract Either ifLeft(Consumer consumer); @Nullable public abstract R getRight(); @Nullable public abstract L getLeft(); private static class Right extends Either { private final R value; Right(R value) { this.value = value; } @Override public Either ifRight(Consumer consumer) { consumer.accept(this.value); return this; } @Override public Either ifLeft(Consumer consumer) { // Do nothing return this; } @Override public R getRight() { return this.value; } @Override public L getLeft() { return null; } } private static class Left extends Either { private final L value; Left(L value) { this.value = value; } @Override public Either ifRight(Consumer consumer) { // Do nothing return this; } @Override public Either ifLeft(Consumer consumer) { consumer.accept(this.value); return this; } @Override public R getRight() { return null; } @Override public L getLeft() { return this.value; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/EnumHelper.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import java.lang.reflect.Field; public class EnumHelper { private EnumHelper() { } @Nullable public static T getEnum(Class enumClass, String name) { return enumClass.isInterface() ? getInterfaceEnumValue(enumClass, name) : getEnumValue(enumClass, name); } public static T getEnum(Class enumClass, String... names) { if(enumClass.isInterface()) { for (String name : names) { T enumValue = getInterfaceEnumValue(enumClass, name); if (enumValue != null) return enumValue; } } else { for (String name : names) { T enumValue = getEnumValue(enumClass, name); if (enumValue != null) return enumValue; } } return null; } @Nullable private static T getInterfaceEnumValue(Class enumClass, String name) { try { Field field = enumClass.getDeclaredField(name); return (T) field.get(null); } catch (Throwable error) { return null; } } @Nullable private static T getEnumValue(Class enumClass, String name) { try { return (T) Enum.valueOf(enumClass, name); } catch (IllegalArgumentException error) { return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/GameSoundImpl.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.world.GameSound; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; public class GameSoundImpl implements GameSound { private final Sound sound; private final float volume; private final float pitch; public GameSoundImpl(Sound sound, float volume, float pitch) { this.sound = sound; this.volume = volume; this.pitch = pitch; } public Sound getSound() { return sound; } public float getVolume() { return volume; } public float getPitch() { return pitch; } public static boolean isEmpty(@Nullable GameSound gameSound) { return gameSound == null || gameSound.getSound() == null || gameSound.getVolume() <= 0 || gameSound.getPitch() <= 0; } public static void playSound(HumanEntity humanEntity, @Nullable GameSound gameSound) { if (!isEmpty(gameSound)) playSound((Player) humanEntity, gameSound); } public static void playSound(Player player, @Nullable GameSound gameSound) { if (!isEmpty(gameSound)) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { player.playSound(player.getLocation(wrapper.getHandle()), gameSound.getSound(), gameSound.getVolume(), gameSound.getPitch()); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; public class IslandArea { private double minX; private double minZ; private double maxX; private double maxZ; public void update(BlockPosition center, double size) { update(center.getX() - size, center.getZ() - size, center.getX() + size, center.getZ() + size); } public void update(double minX, double minZ, double maxX, double maxZ) { this.minX = minX; this.minZ = minZ; this.maxX = maxX; this.maxZ = maxZ; } public boolean intercepts(double x, double z) { return x >= this.minX && x <= this.maxX && z >= this.minZ && z <= this.maxZ; } public boolean expandAndIntercepts(double x, double z, double expandFactor) { if (expandFactor == 0) return intercepts(x, z); double minX = this.minX - expandFactor; double minZ = this.minZ - expandFactor; double maxX = this.maxX + expandFactor; double maxZ = this.maxZ + expandFactor; return x >= minX && x <= maxX && z >= minZ && z <= maxZ; } public boolean expandRshiftAndIntercepts(double x, double z, double expandFactor, int shiftFactor) { if (shiftFactor == 0) return intercepts(x, z); int minX = (int) (this.minX - expandFactor) >> shiftFactor; int minZ = (int) (this.minZ - expandFactor) >> shiftFactor; int maxX = (int) (this.maxX + expandFactor) >> shiftFactor; int maxZ = (int) (this.maxZ + expandFactor) >> shiftFactor; return x >= minX && x <= maxX && z >= minZ && z <= maxZ; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; public class IslandPosition { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private IslandPosition() { } public static long calculatePackedPosFromLocation(int locX, int locZ) { int radius = plugin.getSettings().getMaxIslandSize() * 3; int x = (Math.abs(locX) + (radius / 2)) / radius; int z = (Math.abs(locZ) + (radius / 2)) / radius; return calculatePackedPos(locX < 0 ? -x : x, locZ < 0 ? -z : z); } public static long calculatePackedPos(int posX, int posZ) { long posXLong = (long) posX & 0xFFFFFFFFL; long posZLong = (long) posZ & 0xFFFFFFFFL; return (posXLong) | (posZLong << 32); } public static int getXFromPacked(long packedPos) { return (int) (packedPos & 0xFFFFFFFFL); } public static int getZFromPacked(long packedPos) { return (int) ((packedPos >>> 32) & 0xFFFFFFFFL); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import java.util.function.Consumer; public class IslandWorlds { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public static void accessIslandWorldsAsync(Island island, boolean loadWorld, Consumer> consumer) { for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) { accessIslandWorldAsync(island, dimension, loadWorld, consumer); } } } public static void accessIslandWorldAsync(Island island, Location location, boolean loadWorld, Consumer> consumer) { World world = location.getWorld(); if (world != null) { consumer.accept(Either.left(world)); return; } String worldName = LazyWorldLocation.getWorldName(location); if (!loadWorld) { consumer.accept(Either.right(new NullPointerException("World " + worldName + " is not loaded when requested"))); return; } WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, worldName); Dimension dimension = worldInfo.getDimension(); WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); if (worldsProvider instanceof LazyWorldsProvider) { ((LazyWorldsProvider) worldsProvider).prepareWorld(island, dimension, () -> loadedWorldCallback(worldInfo, consumer)); } else { loadedWorldCallback(worldInfo, consumer); } } public static void accessIslandWorldAsync(Island island, Dimension dimension, boolean loadWorld, Consumer> consumer) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); if (worldInfo == null) { consumer.accept(Either.right(new NullPointerException("Cannot find world for dimension " + dimension.getName()))); return; } World world = Bukkit.getWorld(worldInfo.getName()); if (world != null) { consumer.accept(Either.left(world)); return; } if (!loadWorld) { consumer.accept(Either.right(new NullPointerException("World is not loaded for dimension " + dimension.getName()))); return; } WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); if (worldsProvider instanceof LazyWorldsProvider) { ((LazyWorldsProvider) worldsProvider).prepareWorld(island, dimension, () -> loadedWorldCallback(worldInfo, consumer)); } else { loadedWorldCallback(worldInfo, consumer); } } public static Location setWorldToLocation(Island island, Dimension dimension, WorldPosition worldPosition) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); return setWorldToLocation(worldInfo, worldPosition); } public static Location setWorldToLocation(WorldInfo worldInfo, WorldPosition worldPosition) { World world = Bukkit.getWorld(worldInfo.getName()); Location location; if (world != null) { location = worldPosition.toLocation(world); } else { throw new IllegalStateException("You cannot call this method while the world is unloaded. Use Island#accessIslandWorld"); } return location; } public static void ensureWorldLoaded(Island island, Dimension dimension) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); ensureWorldLoaded(worldInfo); } public static void ensureWorldLoaded(WorldInfo worldInfo) { World world = Bukkit.getWorld(worldInfo.getName()); if (world == null) throw new IllegalStateException("You cannot call this method while the world is unloaded. Use Island#accessIslandWorld"); } private static void loadedWorldCallback(WorldInfo worldInfo, Consumer> consumer) { World world = Bukkit.getWorld(worldInfo.getName()); if (world != null) { consumer.accept(Either.left(world)); } else { consumer.accept(Either.right(new NullPointerException("World does not exist"))); } } private IslandWorlds() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorldsPlayersStrategy.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import java.util.List; public abstract class IslandWorldsPlayersStrategy implements ObjectsPool.Releasable, AutoCloseable { private static final LazyReference> POOL = new LazyReference>() { @Override protected ObjectsPool create() { return plugin.getProviders().hasCustomWorldsSupport() ? new ObjectsPool<>(IslandWorldsPlayersStrategyMultiWorld::new) : new ObjectsPool<>(IslandWorldsPlayersStrategySingleWorld::new); } }; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public static IslandWorldsPlayersStrategy create(Island island) { return POOL.get().obtain().initialize(island); } private IslandWorldsPlayersStrategy() { } protected abstract IslandWorldsPlayersStrategy initialize(Island island); @Override public void close() { release(); } public abstract List getPlayers(WorldInfo worldInfo); public abstract List getSuperiorPlayers(WorldInfo worldInfo); private static class IslandWorldsPlayersStrategySingleWorld extends IslandWorldsPlayersStrategy { private List playersInIsland = null; private IslandWorldsPlayersStrategySingleWorld() { } protected IslandWorldsPlayersStrategySingleWorld initialize(Island island) { this.playersInIsland = island.getAllPlayersInside(); return this; } @Override public void release() { this.playersInIsland = null; } @Override public List getPlayers(WorldInfo worldInfo) { return new SequentialListBuilder() .filter(player -> player.getWorld().getName().equals(worldInfo.getName())) .build(this.playersInIsland, SuperiorPlayer::asPlayer); } @Override public List getSuperiorPlayers(WorldInfo worldInfo) { return new SequentialListBuilder() .filter(player -> player.getWorld().getName().equals(worldInfo.getName())) .build(this.playersInIsland); } } private static class IslandWorldsPlayersStrategyMultiWorld extends IslandWorldsPlayersStrategy { private Island island = null; private IslandWorldsPlayersStrategyMultiWorld() { } protected IslandWorldsPlayersStrategyMultiWorld initialize(Island island) { this.island = island; return this; } @Override public void release() { this.island = null; } @Override public List getPlayers(WorldInfo worldInfo) { World bukkitWorld = Bukkit.getWorld(worldInfo.getName()); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return new SequentialListBuilder() .filter(player -> island.isInside(player.getLocation(wrapper.getHandle()))) .build(bukkitWorld.getPlayers()); } } @Override public List getSuperiorPlayers(WorldInfo worldInfo) { World bukkitWorld = Bukkit.getWorld(worldInfo.getName()); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return new SequentialListBuilder() .filter(player -> island.isInside(player.getLocation(wrapper.getHandle()))) .build(bukkitWorld.getPlayers(), plugin.getPlayers()::getSuperiorPlayer); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/JavaVersion.java ================================================ package com.bgsoftware.superiorskyblock.core; public class JavaVersion { private static final int currentJavaVersion = detectJavaVersion(); private static int detectJavaVersion() { String[] javaVersionSections = System.getProperty("java.version").split("\\."); if(javaVersionSections[0].equals("1")) return Integer.parseInt(javaVersionSections[1]); return Integer.parseInt(javaVersionSections[0]); } public static boolean isAtLeast(int version) { return currentJavaVersion >= version; } private JavaVersion() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/LazyReference.java ================================================ package com.bgsoftware.superiorskyblock.core; import java.util.Optional; public abstract class LazyReference { private E instance; public E get() { return instance == null ? (instance = create()) : instance; } protected abstract E create(); public Optional getIfPresent() { return Optional.ofNullable(this.instance); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; /** * LazyWorldLocation will update the world again if it's null on initialize. */ public class LazyWorldLocation extends Location { @Nullable private String worldName; private boolean updatedWorld = false; public static LazyWorldLocation of(Location location) { if (location instanceof LazyWorldLocation) return (LazyWorldLocation) ((LazyWorldLocation) location).clone(true); return new LazyWorldLocation(location.getWorld().getName(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } public static LazyWorldLocation of(WorldInfo worldInfo, BlockPosition blockPosition) { return new LazyWorldLocation(worldInfo.getName(), blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), 0f, 0f); } public static LazyWorldLocation of(WorldInfo worldInfo, WorldPosition worldPosition) { return new LazyWorldLocation(worldInfo.getName(), worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), worldPosition.getYaw(), worldPosition.getPitch()); } public LazyWorldLocation(World world, double x, double y, double z) { super(world, x, y, z); this.worldName = null; this.updatedWorld = false; } public LazyWorldLocation(String worldName, double x, double y, double z, float yaw, float pitch) { super(Bukkit.getWorld(worldName), x, y, z, yaw, pitch); this.worldName = worldName; this.updatedWorld = false; } public String getWorldName() { return this.worldName; } public void setWorldName(String worldName) { this.worldName = worldName; this.updatedWorld = false; } @Override public World getWorld() { if (!this.updatedWorld) { updateWorldInternal(worldName == null ? null : Bukkit.getWorld(worldName)); } return super.getWorld(); } @Override public void setWorld(World world) { updateWorldInternal(world); this.worldName = world == null ? null : world.getName(); } private void updateWorldInternal(@Nullable World world) { super.setWorld(world); this.updatedWorld = true; } @Override public Location clone() { return clone(false); } public Location clone(boolean keepLazy) { return keepLazy || getWorld() == null ? new LazyWorldLocation(this.worldName, getX(), getY(), getZ(), getYaw(), getPitch()) : super.clone(); } public static String getWorldName(Location location) { if (location instanceof LazyWorldLocation) return ((LazyWorldLocation) location).getWorldName(); World world = location.getWorld(); return world == null ? "null" : world.getName(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/Manager.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; public abstract class Manager { protected final SuperiorSkyblockPlugin plugin; protected Manager(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } public abstract void loadData() throws ManagerLoadException; } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.function.Predicate; public enum Materials { CLOCK("WATCH"), PLAYER_HEAD("SKULL_ITEM", 3), GOLDEN_AXE("GOLD_AXE"), SPAWNER("MOB_SPAWNER"), SUNFLOWER("DOUBLE_PLANT"), BLACK_STAINED_GLASS_PANE("STAINED_GLASS_PANE", 15), BONE_MEAL("INK_SACK", 15), NETHER_PORTAL("PORTAL"), END_PORTAL_FRAME("ENDER_PORTAL_FRAME"); private static final EnumMap> MATERIAL_TAGS = setupMaterialTags(); private static final EnumSet BLOCK_NON_LEGACY_MATERIALS = allOf(material -> material.isBlock() && !isLegacy(material)); private static final EnumSet SOLID_MATERIALS = allOf(Material::isSolid); private static final Map PATCHED_MATERIAL_NAMES = setupPatchedMaterialNames(); private final String bukkitType; private final short bukkitData; Materials(String bukkitType) { this(bukkitType, 0); } Materials(String bukkitType, int bukkitData) { this.bukkitType = bukkitType; this.bukkitData = (short) bukkitData; } public Material toBukkitType() { try { return Material.valueOf(ServerVersion.isLegacy() ? bukkitType : name()); } catch (Exception ex) { throw new IllegalArgumentException("Couldn't cast " + name() + " into a bukkit enum. Contact Ome_R!"); } } public ItemStack toBukkitItem() { return toBukkitItem(1); } public ItemStack toBukkitItem(int amount) { return ServerVersion.isLegacy() ? new ItemStack(toBukkitType(), amount, bukkitData) : new ItemStack(toBukkitType(), amount); } public static boolean hasTag(Material material, Tag tag) { EnumSet materialsTag = MATERIAL_TAGS.get(material); return materialsTag != null && materialsTag.contains(tag); } public static boolean isSlab(Material material) { return hasTag(material, Tag.SLAB); } public static boolean isWater(Material material) { return hasTag(material, Tag.WATER); } public static boolean isLegacy(Material material) { return hasTag(material, Tag.LEGACY); } public static boolean isRail(Material material) { return hasTag(material, Tag.RAIL); } public static boolean isMinecart(Material material) { return hasTag(material, Tag.MINECART); } public static boolean isChest(Material material) { return hasTag(material, Tag.CHEST); } public static boolean isBoat(Material material) { return hasTag(material, Tag.BOAT); } public static boolean isLava(Material material) { return hasTag(material, Tag.LAVA); } public static boolean isSign(Material material) { return hasTag(material, Tag.SIGN); } public static boolean isDye(Material material) { return hasTag(material, Tag.DYE); } public static boolean isSpawnEgg(Material material) { return hasTag(material, Tag.SPAWN_EGG); } public static boolean isCarpet(Material material) { return hasTag(material, Tag.CARPET); } public static boolean isHarness(Material material) { return hasTag(material, Tag.HARNESS); } public static boolean isBed(Material material) { return hasTag(material, Tag.BED); } public static boolean isHoe(Material material) { return hasTag(material, Tag.HOE); } public static boolean isShelf(Material material) { return hasTag(material, Tag.SHELF); } public static Set getBlocksNonLegacy() { return Collections.unmodifiableSet(BLOCK_NON_LEGACY_MATERIALS); } public static Set getSolids() { return Collections.unmodifiableSet(SOLID_MATERIALS); } public static String patchOldMaterialName(String type) { return PATCHED_MATERIAL_NAMES.getOrDefault(type, type); } public static void init() { } private static EnumSet allOf(Predicate predicate) { EnumSet enumSet = EnumSet.noneOf(Material.class); Arrays.stream(Material.values()).filter(predicate).forEach(enumSet::add); return enumSet; } private static EnumMap> setupMaterialTags() { EnumMap> enumMap = new EnumMap<>(Material.class); for (Material material : Material.values()) { EnumSet materialTags = EnumSet.noneOf(Tag.class); String materialName = material.name(); if (materialName.startsWith("LEGACY_")) materialTags.add(Tag.LEGACY); if (materialName.contains("SLAB")) materialTags.add(Tag.SLAB); if (materialName.contains("WATER")) materialTags.add(Tag.WATER); if (materialName.contains("RAIL")) materialTags.add(Tag.RAIL); if (materialName.contains("MINECART")) materialTags.add(Tag.MINECART); if (material == Material.CHEST || materialName.endsWith("_CHEST") || materialName.contains("SHULKER_BOX") || materialName.equals("BARREL")) materialTags.add(Tag.CHEST); if (materialName.contains("BOAT") || materialName.contains("_RAFT")) materialTags.add(Tag.BOAT); if (materialName.contains("LAVA")) materialTags.add(Tag.LAVA); if (materialName.contains("SIGN")) materialTags.add(Tag.SIGN); if (ServerVersion.isLegacy() ? material == Material.INK_SACK : materialName.contains("_DYE")) materialTags.add(Tag.DYE); if (ServerVersion.isLegacy() ? material == Material.MONSTER_EGG : materialName.contains("_SPAWN_EGG")) materialTags.add(Tag.SPAWN_EGG); if (materialName.contains("CARPET")) materialTags.add(Tag.CARPET); if (materialName.contains("HARNESS")) materialTags.add(Tag.HARNESS); if (materialName.contains("BED")) materialTags.add(Tag.BED); if (materialName.contains("_HOE")) materialTags.add(Tag.HOE); if (materialName.contains("_SHELF")) materialTags.add(Tag.SHELF); if (!materialTags.isEmpty()) enumMap.put(material, materialTags); } return enumMap; } private static Map setupPatchedMaterialNames() { Map map = new HashMap<>(); try { Material.valueOf("GRASS"); } catch (IllegalArgumentException error) { map.put("GRASS", "GRASS_BLOCK"); } return map.isEmpty() ? Collections.emptyMap() : map; } public enum Tag { SLAB, WATER, LEGACY, RAIL, MINECART, CHEST, BOAT, LAVA, SIGN, DYE, SPAWN_EGG, CARPET, BED, HARNESS, HOE, SHELF } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/MutableChunkPosition.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; public class MutableChunkPosition extends ChunkPosition { public MutableChunkPosition() { super(false); } public MutableChunkPosition reset(WorldInfo worldInfo, int x, int z) { this.worldInfo = worldInfo; this.x = x; this.z = z; this.pairedXZ = -1; this.cachedBukkitWorld.clear(); return this; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPool.java ================================================ package com.bgsoftware.superiorskyblock.core; import java.util.LinkedList; import java.util.Queue; public class ObjectsPool { private final Queue backend = new LinkedList<>(); private final Creator creator; public ObjectsPool(Creator creator) { this(creator, 0); } public ObjectsPool(Creator creator, int initialCapacity) { this.creator = creator; for (int i = 0; i < initialCapacity; ++i) this.backend.offer(creator.create()); } public T obtain() { T obj; synchronized (this) { obj = this.backend.poll(); } return obj == null ? this.creator.create() : obj; } public void release(T obj) { synchronized (this) { this.backend.offer(obj); } } public interface Creator { T create(); } public interface Releasable { void release(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import org.bukkit.Location; import javax.annotation.Nullable; import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; public class ObjectsPools { public static final ObjectsPool> LOCATION = createNewPool(() -> new Location(null, 0D, 0D, 0D)); public static final ObjectsPool> LAZY_LOCATION = createNewPool(() -> new LazyWorldLocation(null, 0D, 0D, 0D)); public static final ObjectsPool> DB_COLUMN = createNewPool(() -> new DBColumn("", null)); public static final ObjectsPool> DB_COLUMN_BATCH = new ObjectsPool<>(() -> new Batch<>(DB_COLUMN)); private ObjectsPools() { } public static ObjectsPool> createNewPool(ObjectsPool.Creator creator) { MutableObject>> wrapperReference = new MutableObject<>(null); ObjectsPool> pool = new ObjectsPool<>( () -> new Wrapper<>(creator.create(), obj -> onWrapperRelease(obj, wrapperReference.getValue()))); wrapperReference.setValue(pool); return pool; } private static void onWrapperRelease(T obj, @Nullable ObjectsPool pool) { if (pool != null) pool.release(obj); } public static class Wrapper implements ObjectsPool.Releasable, AutoCloseable { private final T handle; private final Consumer> releaseMethod; Wrapper(T handle, Consumer> releaseMethod) { this.handle = handle; this.releaseMethod = releaseMethod; } public T getHandle() { return handle; } @Override public void release() { this.releaseMethod.accept(this); } @Override public void close() { release(); } } public static class Batch implements ObjectsPool.Releasable, AutoCloseable { private final ObjectsPool> pool; private final List> obtainedObjects = new LinkedList<>(); public Batch(ObjectsPool> pool) { this.pool = pool; } public T obtain() { Wrapper obj = this.pool.obtain(); this.obtainedObjects.add(obj); return obj.getHandle(); } @Override public void release() { obtainedObjects.forEach(Wrapper::release); obtainedObjects.clear(); } @Override public void close() { release(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/PlayerHand.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import org.bukkit.inventory.EquipmentSlot; import java.util.function.Supplier; public enum PlayerHand { MAIN_HAND { @Override public EquipmentSlot getEquipmentSlot() { return EquipmentSlot.HAND; } }, OFF_HAND { @Override public EquipmentSlot getEquipmentSlot() { return EQUIPMENT_SLOT_OFF_HAND; } }; @Nullable private static final EquipmentSlot EQUIPMENT_SLOT_OFF_HAND = ((Supplier) () -> { try { return EquipmentSlot.valueOf("OFF_HAND"); } catch (IllegalArgumentException error) { return null; } }).get(); public static PlayerHand of(EquipmentSlot equipmentSlot) { if (equipmentSlot == EquipmentSlot.HAND) { return PlayerHand.MAIN_HAND; } else if (equipmentSlot == EQUIPMENT_SLOT_OFF_HAND) { return PlayerHand.OFF_HAND; } throw new IllegalArgumentException("Cannot get PlayerHand from: " + equipmentSlot); } public abstract EquipmentSlot getEquipmentSlot(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/PluginLoadingStage.java ================================================ package com.bgsoftware.superiorskyblock.core; public enum PluginLoadingStage { START, API_INITIALIZED, SUPPORTED_SERVER_SOFTWARE, NMS_INITIALIZED, LOADED, START_ENABLE, SETTINGS_INITIALIZED, MODULES_INITIALIZED, COMMANDS_INITIALIZED, WORLDS_PREPARED, MANAGERS_INITIALIZED, CHUNKS_PROVIDER_INITIALIZED, ENABLED; public boolean isAtLeast(PluginLoadingStage other) { return this.ordinal() >= other.ordinal(); } public PluginLoadingStage next() { try { return PluginLoadingStage.values()[this.ordinal() + 1]; } catch (ArrayIndexOutOfBoundsException error) { return this; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/PluginReloadReason.java ================================================ package com.bgsoftware.superiorskyblock.core; public enum PluginReloadReason { STARTUP, COMMAND } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/Precision.java ================================================ package com.bgsoftware.superiorskyblock.core; import java.math.BigDecimal; import java.math.RoundingMode; public class Precision { private Precision() { } public static double round(double value, int places) { if (places < 0) throw new IllegalArgumentException(); BigDecimal bd = new BigDecimal(Double.toString(value)); bd = bd.setScale(places, RoundingMode.FLOOR); return bd.doubleValue(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/SBlockOffset.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.google.common.base.Preconditions; import org.bukkit.Location; import java.util.Objects; public class SBlockOffset implements BlockOffset { public static final SBlockOffset ZERO = new SBlockOffset(0, 0, 0); private final double offsetX; private final double offsetY; private final double offsetZ; public static BlockOffset fromOffsets(int offsetX, int offsetY, int offsetZ) { return offsetX == 0 && offsetY == 0 && offsetZ == 0 ? ZERO : new SBlockOffset(offsetX, offsetY, offsetZ); } public static BlockOffset fromOffsets(double offsetX, double offsetY, double offsetZ) { return offsetX == 0 && offsetY == 0 && offsetZ == 0 ? ZERO : new SBlockOffset(offsetX, offsetY, offsetZ); } private SBlockOffset(double offsetX, double offsetY, double offsetZ) { this.offsetX = offsetX; this.offsetY = offsetY; this.offsetZ = offsetZ; } @Override public int getOffsetX() { return (int) this.offsetX; } @Override public int getOffsetY() { return (int) this.offsetY; } @Override public int getOffsetZ() { return (int) this.offsetZ; } @Override public BlockOffset negate() { return SBlockOffset.fromOffsets(-offsetX, -offsetY, -offsetZ); } @Override public Location applyToLocation(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); return location.clone().add(this.offsetX, this.offsetY, this.offsetZ); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SBlockOffset that = (SBlockOffset) o; return offsetX == that.offsetX && offsetY == that.offsetY && offsetZ == that.offsetZ; } @Override public int hashCode() { return Objects.hash(offsetX, offsetY, offsetZ); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import java.util.Objects; public class SBlockPosition implements BlockPosition { private final int x; private final int y; private final int z; @Nullable private WorldPosition cachedWorldPosition; public static SBlockPosition of(Location location) { return of(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } public static SBlockPosition of(Block block) { return of(block.getX(), block.getY(), block.getZ()); } public static SBlockPosition of(WorldPosition worldPosition) { return new SBlockPosition(Location.locToBlock(worldPosition.getX()), Location.locToBlock(worldPosition.getY()), Location.locToBlock(worldPosition.getZ())); } public static SBlockPosition of(int x, int y, int z) { return new SBlockPosition(x, y, z); } private SBlockPosition(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } @Override public int getX() { return x; } @Override public int getY() { return y; } @Override public int getZ() { return z; } @Override public BlockPosition offset(int x, int y, int z) { return new SBlockPosition(this.x + x, this.y + y, this.z + z); } @Override public Location toLocation(@Nullable World world) { return new Location(world, x, y, z); } @Override public Location toLocation(@Nullable World world, @Nullable Location location) { if (location != null) { location.setWorld(world); location.setX(this.x); location.setY(this.y); location.setZ(this.z); location.setYaw(0f); location.setPitch(0f); } return location; } @Override public Location toLocation(WorldInfo worldInfo) { return LazyWorldLocation.of(worldInfo, this); } @Override public Location toLocation(WorldInfo worldInfo, @Nullable Location location) { if (location != null) { location.setX(this.x); location.setY(this.y); location.setZ(this.z); location.setYaw(0f); location.setPitch(0f); if (location instanceof LazyWorldLocation) { ((LazyWorldLocation) location).setWorldName(worldInfo.getName()); } else { World world = Bukkit.getWorld(worldInfo.getName()); location.setWorld(world); } } return location; } @Override public WorldPosition toWorldPosition() { if (this.cachedWorldPosition == null) this.cachedWorldPosition = SWorldPosition.of(this); return this.cachedWorldPosition; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SBlockPosition that = (SBlockPosition) o; return x == that.x && y == that.y && z == that.z; } @Override public int hashCode() { return Objects.hash(x, y, z); } @Override public String toString() { return x + ", " + y + ", " + z; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/SWorldPosition.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import java.util.Objects; public class SWorldPosition implements WorldPosition { private final double x; private final double y; private final double z; private final float yaw; private final float pitch; @Nullable private BlockPosition cachedBlockPosition; public static SWorldPosition of(Location location) { return of(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } public static SWorldPosition of(Block block) { return of(block.getX(), block.getY(), block.getZ()); } public static SWorldPosition of(double x, double y, double z) { return of(x, y, z, 0f, 0f); } public static SWorldPosition of(BlockPosition blockPosition) { return of(blockPosition.getX() + 0.5, blockPosition.getY(), blockPosition.getZ() + 0.5); } public static SWorldPosition of(double x, double y, double z, float yaw, float pitch) { return new SWorldPosition(x, y, z, yaw, pitch); } private SWorldPosition(double x, double y, double z, float yaw, float pitch) { this.x = x; this.y = y; this.z = z; this.yaw = yaw; this.pitch = pitch; } @Override public double getX() { return this.x; } @Override public double getY() { return this.y; } @Override public double getZ() { return this.z; } @Override public float getYaw() { return this.yaw; } @Override public float getPitch() { return this.pitch; } @Override public WorldPosition offset(double x, double y, double z) { return of(this.x + x, this.y + y, this.z + z, this.yaw, this.pitch); } @Override public WorldPosition rotate(float yaw, float pitch) { return of(this.x, this.y, this.z, this.yaw + yaw, this.pitch + pitch); } @Override public WorldPosition offset(double x, double y, double z, float yaw, float pitch) { return of(this.x + x, this.y + y, this.z + z, this.yaw + yaw, this.pitch + pitch); } @Override public Location toLocation(@Nullable World world) { return new Location(world, this.x, this.y, this.z, this.yaw, this.pitch); } @Override public Location toLocation(@Nullable World world, @Nullable Location location) { if (location != null) { location.setWorld(world); location.setX(this.x); location.setY(this.y); location.setZ(this.z); location.setYaw(this.yaw); location.setPitch(this.pitch); } return location; } @Override public Location toLocation(WorldInfo worldInfo) { return LazyWorldLocation.of(worldInfo, this); } @Override public Location toLocation(WorldInfo worldInfo, @Nullable Location location) { if (location != null) { location.setX(this.x); location.setY(this.y); location.setZ(this.z); location.setYaw(this.yaw); location.setPitch(this.pitch); if (location instanceof LazyWorldLocation) { ((LazyWorldLocation) location).setWorldName(worldInfo.getName()); } else { World world = Bukkit.getWorld(worldInfo.getName()); location.setWorld(world); } } return location; } @Override public BlockPosition toBlockPosition() { if (this.cachedBlockPosition == null) this.cachedBlockPosition = SBlockPosition.of(this); return this.cachedBlockPosition; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SWorldPosition that = (SWorldPosition) o; return x == that.x && y == that.y && z == that.z && yaw == that.yaw && pitch == that.pitch; } @Override public int hashCode() { return Objects.hash(x, y, z, yaw, pitch); } @Override public String toString() { return x + ", " + y + ", " + z + ", " + yaw + ", " + pitch; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; public class SequentialListBuilder { @Nullable private Comparator comparator; @Nullable private Predicate predicate; private boolean mutable = false; public SequentialListBuilder sorted(@Nullable Comparator comparator) { this.comparator = comparator; return this; } public SequentialListBuilder filter(@Nullable Predicate predicate) { this.predicate = predicate; return this; } public SequentialListBuilder mutable() { this.mutable = true; return this; } public List build(Collection collection, Function mapper) { LinkedList sequentialList = new LinkedList<>(); collection.forEach(element -> { E mappedElement = mapper.apply(element); if (predicate == null || predicate.test(mappedElement)) sequentialList.add(mappedElement); }); return completeBuild(sequentialList); } public List build(O[] collection, Function mapper) { LinkedList sequentialList = new LinkedList<>(); for (O element : collection) { E mappedElement = mapper.apply(element); if (predicate == null || predicate.test(mappedElement)) sequentialList.add(mappedElement); } return completeBuild(sequentialList); } public List map(Collection collection, Function mapper) { LinkedList sequentialList = new LinkedList<>(); collection.forEach(element -> { if (predicate == null || predicate.test(element)) sequentialList.add(mapper.apply(element)); }); return completeBuild(sequentialList, null, this.mutable); } public List map(E[] collection, Function mapper) { LinkedList sequentialList = new LinkedList<>(); for (E element : collection) { if (predicate == null || predicate.test(element)) sequentialList.add(mapper.apply(element)); } return completeBuild(sequentialList, null, this.mutable); } public List map(Iterator iterator, Function mapper) { LinkedList sequentialList = new LinkedList<>(); while (iterator.hasNext()) { E next = iterator.next(); if (predicate == null || predicate.test(next)) sequentialList.add(mapper.apply(next)); } return completeBuild(sequentialList, null, this.mutable); } public List build(Stream stream) { LinkedList sequentialList = new LinkedList<>(); stream.forEach(element -> { if (predicate == null || predicate.test(element)) sequentialList.add(element); }); return completeBuild(sequentialList); } public List build(Collection collection) { LinkedList sequentialList; if (predicate == null) { sequentialList = new LinkedList<>(collection); } else { sequentialList = new LinkedList<>(); collection.forEach(element -> { if (predicate.test(element)) sequentialList.add(element); }); } return completeBuild(sequentialList); } public List build(Iterator iterator) { LinkedList sequentialList = new LinkedList<>(); if (predicate == null) { while (iterator.hasNext()) sequentialList.add(iterator.next()); } else { while (iterator.hasNext()) { E next = iterator.next(); if (predicate.test(next)) sequentialList.add(next); } } return completeBuild(sequentialList); } private List completeBuild(List sequentialList) { return completeBuild(sequentialList, this.comparator, this.mutable); } private static List completeBuild(List sequentialList, @Nullable Comparator comparator, boolean mutable) { if (sequentialList.isEmpty()) return mutable ? sequentialList : Collections.emptyList(); if (comparator != null) sequentialList.sort(comparator); return mutable ? sequentialList : Collections.unmodifiableList(sequentialList); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java ================================================ package com.bgsoftware.superiorskyblock.core; import org.bukkit.Bukkit; import java.util.Arrays; import java.util.Optional; public enum ServerVersion { v1_8(18), v1_9(19), v1_10(110), v1_11(111), v1_12(112), v1_13(113), v1_14(114), v1_15(115), v1_16(116), v1_17(117), v1_18(118), v1_19(119), v1_20(120), v1_21(121), v26_1(261), UNKONWN(-1); private static final ServerVersion currentVersion; private static final String bukkitVersion; private static final boolean legacy; static { bukkitVersion = Bukkit.getBukkitVersion().split("-")[0]; String[] sections = bukkitVersion.split("\\."); currentVersion = Optional.ofNullable(EnumHelper.getEnum(ServerVersion.class, "v" + sections[0] + "_" + sections[1])).orElse(UNKONWN); legacy = isLessThan(ServerVersion.v1_13); } private final int code; ServerVersion(int code) { this.code = code; } public static boolean isAtLeast(ServerVersion serverVersion) { return isValidVersion(serverVersion) && currentVersion.code >= serverVersion.code; } public static boolean isLessThan(ServerVersion serverVersion) { return isValidVersion(serverVersion) && currentVersion.code < serverVersion.code; } public static boolean isEquals(ServerVersion serverVersion) { return isValidVersion(serverVersion) && currentVersion.code == serverVersion.code; } public static boolean isLegacy() { return legacy; } public static String getBukkitVersion() { return bukkitVersion; } public static ServerVersion[] getByOrder() { ServerVersion[] versions = Arrays.copyOfRange(values(), 0, currentVersion.ordinal() + 1); for (int i = 0; i < versions.length / 2; i++) { ServerVersion temp = versions[i]; versions[i] = versions[versions.length - i - 1]; versions[versions.length - i - 1] = temp; } return versions; } private static boolean isValidVersion(ServerVersion compareVersion) { return currentVersion != UNKONWN && compareVersion != UNKONWN; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/Text.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; public class Text { private Text() { } public static boolean isBlank(@Nullable String string) { return string == null || string.isEmpty(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.google.common.base.Preconditions; import java.util.Arrays; import java.util.NoSuchElementException; public class VarintArray { private static final ThreadLocal VARINT_BUF = ThreadLocal.withInitial(() -> new byte[10]); private static final byte[] ZERO_BYTE = new byte[]{0}; private final ByteBigArray backend; private int size; public VarintArray() { this.backend = new ByteBigArray(); this.size = 0; } public VarintArray(ByteBigArray data) { Preconditions.checkState(data.size() == 0 || (data.get(data.size() - 1) & 0x80) == 0, "Last byte in data-stream cannot have its MSB on"); this.backend = data; this.size = data.size(); } public void add(long value) { byte[] varint = serializeVarint(value); for (byte b : varint) this.backend.add(b); this.size += varint.length; } public ByteBigArray toArray() { return this.backend.readOnly(); } public Itr iterator() { return new Itr(); } private static byte[] serializeVarint(long value) { if (value == 0) return ZERO_BYTE; byte[] varintBuf = VARINT_BUF.get(); int varintBytesCount = 0; while (value != 0) { byte nextByte = (byte) (value & 0x7f); value >>= 7; varintBuf[varintBytesCount++] = value == 0 ? nextByte : (byte) (nextByte | 0x80); } return Arrays.copyOf(varintBuf, varintBytesCount); } public class Itr { private int index = 0; public boolean hasNext() { return index < size; } public long next() { if (!hasNext()) throw new NoSuchElementException(); int i = 0; long value = 0; while (index < size) { byte b = backend.get(index++); value |= (long) (b & 0x7f) << i; i += 7; if ((b & 0x80) == 0) break; } return value; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/WorldInfoImpl.java ================================================ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import org.bukkit.World; import java.util.Objects; public class WorldInfoImpl implements WorldInfo { private final String worldName; private final Dimension dimension; public WorldInfoImpl(String worldName, Dimension dimension) { this.worldName = worldName; this.dimension = dimension; } @Override public String getName() { return this.worldName; } @Override @Deprecated public World.Environment getEnvironment() { return this.dimension.getEnvironment(); } @Override public Dimension getDimension() { return this.dimension; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; WorldInfoImpl worldInfo = (WorldInfoImpl) o; return dimension.equals(worldInfo.dimension) && worldName.equals(worldInfo.worldName); } @Override public int hashCode() { return Objects.hash(worldName, dimension); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/ArrayMap.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import org.jetbrains.annotations.NotNull; import java.util.AbstractCollection; import java.util.AbstractSet; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; public class ArrayMap implements Map { private static final Object[] EMPTY_ARRAY = new Object[0]; private static final int DEFAULT_CAPACITY = 4; private KeySet keySet; private Values valuesCollection; private EntrySet entrySet; private Object[] keys = EMPTY_ARRAY; private Object[] values = EMPTY_ARRAY; private int size = 0; private int capacity = 0; private int findKeyPos(Object key) { for (int i = 0; i < this.size; ++i) { if (Objects.equals(keys[i], key)) return i; } return -1; } private void ensureCapacity() { if (this.capacity == 0) { this.capacity = DEFAULT_CAPACITY; this.keys = new Object[DEFAULT_CAPACITY]; this.values = new Object[DEFAULT_CAPACITY]; } else if (this.size >= this.capacity) { this.capacity *= 2; this.keys = Arrays.copyOf(this.keys, this.capacity); this.values = Arrays.copyOf(this.values, this.capacity); } } @Override public V get(Object key) { int pos = findKeyPos(key); return pos < 0 ? null : (V) this.values[pos]; } @Override public int size() { return this.size; } @Override public void clear() { this.values = EMPTY_ARRAY; this.keys = EMPTY_ARRAY; this.size = 0; this.capacity = 0; } @Override public boolean containsKey(Object key) { return findKeyPos(key) >= 0; } @Override public boolean containsValue(Object value) { for (Object curr : this.values) { if (Objects.equals(value, curr)) return true; } return false; } @Override public boolean isEmpty() { return this.size == 0; } @Override public V put(Object key, Object value) { int pos = findKeyPos(key); if (pos >= 0) { Object old = this.values[pos]; this.values[pos] = value; return (V) old; } ensureCapacity(); this.keys[this.size] = key; this.values[this.size] = value; ++this.size; return null; } @Override public V remove(Object key) { int pos = findKeyPos(key); if (pos < 0) { return null; } return remove(pos); } private V remove(int pos) { Object oldValue = this.values[pos]; int tail = this.size - pos - 1; System.arraycopy(this.keys, pos + 1, this.keys, pos, tail); System.arraycopy(this.values, pos + 1, this.values, pos, tail); --this.size; this.values[this.size] = null; return (V) oldValue; } @Override public void putAll(@NotNull Map map) { for (Entry curr : map.entrySet()) { put(curr.getKey(), curr.getValue()); } } @NotNull @Override public Set keySet() { return this.keySet == null ? (this.keySet = new KeySet()) : this.keySet; } @NotNull @Override public Collection values() { return this.valuesCollection == null ? (this.valuesCollection = new Values()) : this.valuesCollection; } @NotNull @Override public Set> entrySet() { return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet; } private class KeySet extends AbstractSet { @Override public int size() { return ArrayMap.this.size(); } @Override public boolean isEmpty() { return ArrayMap.this.isEmpty(); } @Override public boolean contains(Object o) { return ArrayMap.this.containsKey(o); } @NotNull @Override public Iterator iterator() { return new KeySetItr(); } @NotNull @Override public Object[] toArray() { return Arrays.copyOf(ArrayMap.this.keys, size()); } @NotNull @Override public T[] toArray(@NotNull T[] ts) { Object[] arr = ts.length >= size() ? ts : Arrays.copyOf(ts, size()); System.arraycopy(ArrayMap.this.keys, 0, arr, 0, size()); return (T[]) arr; } @Override public void clear() { ArrayMap.this.clear(); } } private class KeySetItr extends Itr { @Override protected K getNext() { return (K) ArrayMap.this.keys[this.lastRet]; } } private class Values extends AbstractCollection { @Override public int size() { return ArrayMap.this.size(); } @Override public boolean isEmpty() { return ArrayMap.this.isEmpty(); } @Override public boolean contains(Object o) { return ArrayMap.this.containsValue(o); } @NotNull @Override public Iterator iterator() { return new ValuesItr(); } @NotNull @Override public Object[] toArray() { return Arrays.copyOf(ArrayMap.this.values, size()); } @NotNull @Override public T[] toArray(@NotNull T[] ts) { Object[] arr = ts.length >= size() ? ts : Arrays.copyOf(ts, size()); System.arraycopy(ArrayMap.this.values, 0, arr, 0, size()); return (T[]) arr; } @Override public void clear() { ArrayMap.this.clear(); } } private class ValuesItr extends Itr { @Override protected V getNext() { return (V) ArrayMap.this.values[this.lastRet]; } } private class EntrySet extends AbstractSet> { @Override public int size() { return ArrayMap.this.size(); } @Override public boolean isEmpty() { return ArrayMap.this.isEmpty(); } @Override public boolean contains(Object o) { return ArrayMap.this.containsKey(o); } @NotNull @Override public Iterator> iterator() { return new EntrySetItr(); } @Override public void clear() { ArrayMap.this.clear(); } } private class EntrySetItr extends Itr> { @Override protected Entry getNext() { return new EntryImpl(this.lastRet); } } private class EntryImpl implements Entry { private final int pos; EntryImpl(int pos) { this.pos = pos; } @Override public K getKey() { return (K) ArrayMap.this.keys[this.pos]; } @Override public V getValue() { return (V) ArrayMap.this.values[this.pos]; } @Override public V setValue(V v) { Object old = ArrayMap.this.values[this.pos]; ArrayMap.this.values[this.pos] = v; return (V) old; } } private abstract class Itr implements Iterator { protected int pos = 0; protected int lastRet = -1; @Override public final boolean hasNext() { return this.pos < size(); } @Override public final T next() { if (!hasNext()) throw new NoSuchElementException(); this.lastRet = this.pos++; return getNext(); } protected abstract T getNext(); @Override public final void remove() { if (this.lastRet < 0) throw new IllegalStateException(); ArrayMap.this.remove(this.lastRet); this.pos = this.lastRet; this.lastRet = -1; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/AutoRemovalCollection.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.common.annotations.NotNull; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @SuppressWarnings("UnstableApiUsage") public class AutoRemovalCollection implements Collection { private static final Object DUMMY = new Object(); private final Collection elements; private final Cache elementsLifeTime; public static AutoRemovalCollection newHashSet(long removalDelay, TimeUnit timeUnit) { return new AutoRemovalCollection<>(removalDelay, timeUnit, HashSet::new); } public static AutoRemovalCollection newArrayList(long removalDelay, TimeUnit timeUnit) { return new AutoRemovalCollection<>(removalDelay, timeUnit, ArrayList::new); } private AutoRemovalCollection(long removalDelay, TimeUnit timeUnit, Supplier> collectionSupplier) { this.elements = collectionSupplier.get(); this.elementsLifeTime = CacheBuilder.newBuilder() .expireAfterWrite(removalDelay, timeUnit) .removalListener(removalNotification -> { elements.remove(removalNotification.getKey()); }) .build(); } @Override public int size() { refreshLifeTime(); return elements.size(); } @Override public boolean isEmpty() { return size() <= 0; } @Override public boolean contains(Object o) { refreshLifeTime(o); return elements.contains(o); } @NotNull @Override public Iterator iterator() { refreshLifeTime(); return elements.iterator(); } @NotNull @Override public Object[] toArray() { refreshLifeTime(); return elements.toArray(); } @NotNull @Override public T[] toArray(@NotNull T[] a) { refreshLifeTime(); return elements.toArray(a); } @Override public boolean add(E e) { refreshLifeTime(e); boolean result = elements.add(e); if (result) this.elementsLifeTime.put(e, DUMMY); return result; } @Override public boolean remove(Object o) { this.elementsLifeTime.invalidate(o); return elements.remove(o); } @Override public boolean containsAll(@NotNull Collection c) { c.forEach(this::refreshLifeTime); return elements.containsAll(c); } @Override public boolean addAll(@NotNull Collection c) { boolean result = false; for (E element : c) result |= add(element); return result; } @Override public boolean retainAll(@NotNull Collection c) { return elements.retainAll(c); } @Override public boolean removeAll(@NotNull Collection c) { this.elementsLifeTime.invalidateAll((Iterable) c.iterator()); return elements.removeAll(c); } @Override public void clear() { elements.clear(); this.elementsLifeTime.invalidateAll(); } private void refreshLifeTime(Object o) { try { this.elementsLifeTime.get((E) o, () -> null); } catch (Throwable ignored) { } } private void refreshLifeTime() { this.elementsLifeTime.size(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/AutoRemovalMap.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @SuppressWarnings("UnstableApiUsage") public class AutoRemovalMap implements Map { private static final Object DUMMY = new Object(); private final Map elements; private final Cache elementsLifeTime; public static AutoRemovalMap newHashMap(long removalDelay, TimeUnit timeUnit) { return newMap(removalDelay, timeUnit, HashMap::new); } public static AutoRemovalMap newMap(long removalDelay, TimeUnit timeUnit, Supplier> mapSupplier) { return new AutoRemovalMap<>(removalDelay, timeUnit, mapSupplier); } private AutoRemovalMap(long removalDelay, TimeUnit timeUnit, Supplier> mapSupplier) { this.elements = mapSupplier.get(); this.elementsLifeTime = CacheBuilder.newBuilder() .expireAfterWrite(removalDelay, timeUnit) .removalListener(removalNotification -> { elements.remove(removalNotification.getKey()); }) .build(); } @Override public int size() { refreshLifeTime(); return elements.size(); } @Override public boolean isEmpty() { refreshLifeTime(); return elements.isEmpty(); } @Override public boolean containsKey(Object key) { refreshLifeTime(key); return elements.containsKey(key); } @Override public boolean containsValue(Object value) { refreshLifeTime(); return elements.containsValue(value); } @Override public V get(Object key) { refreshLifeTime(key); return elements.get(key); } @Nullable @Override public V put(K key, V value) { refreshLifeTime(key); V old = elements.put(key, value); if (old != value) this.elementsLifeTime.put(key, DUMMY); return value; } @Override public V remove(Object key) { V value = elements.remove(key); this.elementsLifeTime.invalidate(key); return value; } @Override public void putAll(@NotNull Map m) { m.forEach(this::put); } @Override public void clear() { this.elementsLifeTime.invalidateAll(); elements.clear(); } @NotNull @Override public Set keySet() { refreshLifeTime(); return elements.keySet(); } @NotNull @Override public Collection values() { refreshLifeTime(); return elements.values(); } @NotNull @Override public Set> entrySet() { refreshLifeTime(); return elements.entrySet(); } private void refreshLifeTime(Object o) { try { this.elementsLifeTime.get((K) o, () -> null); } catch (Throwable ignored) { } } private void refreshLifeTime() { this.elementsLifeTime.size(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.MutableChunkPosition; import com.bgsoftware.superiorskyblock.core.WorldInfoImpl; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.function.Supplier; public class Chunk2ObjectMap extends AbstractMap { @Nullable private KeySet keySet; @Nullable private Values values; @Nullable private EntrySet entrySet; private final Map> backendMap = new LinkedHashMap<>(); private int size = 0; @Override public int size() { return this.size; } @Override public boolean isEmpty() { return this.size == 0; } @Override public boolean containsKey(Object key) { return get(key) != null; } @Override public boolean containsValue(Object value) { return value != null && super.containsValue(value); } @Override public V get(Object key) { return key instanceof ChunkPosition ? get((ChunkPosition) key) : null; } @Nullable public V get(ChunkPosition chunkPosition) { return get(chunkPosition.getWorldName(), chunkPosition.asPair()); } @Nullable public V get(String worldName, long chunkPair) { Long2ObjectMapView worldBackendData = this.backendMap.get(worldName); if (worldBackendData == null) return null; return worldBackendData.get(chunkPair); } public V computeIfAbsent(String worldName, long chunkPair, Supplier newValue) { Long2ObjectMapView worldBackendData = this.backendMap.computeIfAbsent(worldName, n -> CollectionsFactory.createLong2ObjectLinkedHashMap()); return worldBackendData.computeIfAbsent(chunkPair, p -> { ++Chunk2ObjectMap.this.size; return newValue.get(); }); } @Nullable @Override public V put(ChunkPosition chunkPosition, V value) { return put(chunkPosition.getWorldName(), chunkPosition.asPair(), value); } @Nullable public V put(String worldName, long chunkPair, V value) { Long2ObjectMapView worldBackendData = this.backendMap.computeIfAbsent(worldName, n -> CollectionsFactory.createLong2ObjectLinkedHashMap()); V oldValue = worldBackendData.put(chunkPair, value); if (oldValue == null) ++this.size; return oldValue; } @Override public V remove(Object key) { return key instanceof ChunkPosition ? remove((ChunkPosition) key) : null; } @Nullable public V remove(ChunkPosition chunkPosition) { return remove(chunkPosition.getWorldName(), chunkPosition.asPair()); } @Nullable public V remove(String worldName, long chunkPair) { Long2ObjectMapView worldBackendData = this.backendMap.get(worldName); if (worldBackendData == null) return null; V oldValue = onRemove(worldBackendData.remove(chunkPair)); if (oldValue == null) return null; if (worldBackendData.isEmpty()) Chunk2ObjectMap.this.backendMap.remove(worldName); return oldValue; } @Nullable private V onRemove(@Nullable V removedValue) { if (removedValue != null) --this.size; return removedValue; } @Override public void clear() { this.backendMap.clear(); this.size = 0; } @NotNull @Override public Set keySet() { return this.keySet == null ? (this.keySet = new KeySet()) : this.keySet; } @NotNull @Override public Collection values() { return this.values == null ? (this.values = new Values()) : this.values; } @NotNull @Override public Set> entrySet() { return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet; } static int getChunkXFromPair(long chunkPair) { return (int) (chunkPair & 0xFFFFFFFFL); } static int getChunkZFromPair(long chunkPair) { return (int) (chunkPair >> 32); } private class KeySet extends AbstractSet { @Override public int size() { return Chunk2ObjectMap.this.size(); } @Override public boolean isEmpty() { return Chunk2ObjectMap.this.isEmpty(); } @Override public boolean contains(Object o) { return Chunk2ObjectMap.this.containsKey(o); } @NotNull @Override public Iterator iterator() { return new KeySetItr(); } @Override public void clear() { Chunk2ObjectMap.this.clear(); } private class KeySetItr extends Itr { private final MutableChunkPosition mutableChunkPosition = new MutableChunkPosition(); private WorldInfoImpl cachedWorldInfo = null; @Override protected ChunkPosition getNext() { return this.mutableChunkPosition.reset(this.cachedWorldInfo, getChunkXFromPair(this.currChunk), getChunkZFromPair(this.currChunk)); } @Override protected void onWorldChange() { this.cachedWorldInfo = new WorldInfoImpl(this.currWorld, null); } } } private class Values extends AbstractCollection { @Override public int size() { return Chunk2ObjectMap.this.size(); } @Override public boolean isEmpty() { return Chunk2ObjectMap.this.isEmpty(); } @Override public boolean contains(Object o) { return Chunk2ObjectMap.this.containsValue(o); } @NotNull @Override public Iterator iterator() { return new ValuesItr(); } @Override public void clear() { Chunk2ObjectMap.this.clear(); } private class ValuesItr extends Itr { @Override protected V getNext() { return this.currValue; } } } private class EntrySet extends AbstractSet> { @Override public int size() { return Chunk2ObjectMap.this.size(); } @Override public boolean isEmpty() { return Chunk2ObjectMap.this.isEmpty(); } @Override public boolean contains(Object o) { ChunkPosition key = null; if (o instanceof Entry) { o = ((Entry) o).getKey(); } if (o instanceof ChunkPosition) key = (ChunkPosition) o; return key != null && Chunk2ObjectMap.this.containsKey(o); } @NotNull @Override public Iterator> iterator() { return new EntrySetItr(); } @Override public void clear() { Chunk2ObjectMap.this.clear(); } private class EntrySetItr extends Itr> { private final MutableChunkPosition mutableChunkPosition = new MutableChunkPosition(); private final EntryImpl mutableEntry = new EntryImpl(); private WorldInfoImpl cachedWorldInfo = null; @Override protected Entry getNext() { return mutableEntry.reset( this.mutableChunkPosition.reset(this.cachedWorldInfo, getChunkXFromPair(this.currChunk), getChunkZFromPair(this.currChunk)), this.currValue); } @Override protected void onWorldChange() { this.cachedWorldInfo = new WorldInfoImpl(this.currWorld, null); } private class EntryImpl implements Entry { private ChunkPosition chunkPosition; private V cachedValue; EntryImpl() { } EntryImpl reset(ChunkPosition chunkPosition, V value) { this.chunkPosition = chunkPosition; this.cachedValue = value; return this; } @Override public ChunkPosition getKey() { return this.chunkPosition; } @Override public V getValue() { return this.cachedValue; } @Override public V setValue(V v) { V oldValue = this.cachedValue; this.cachedValue = v; Long2ObjectMapView worldBackendData = Chunk2ObjectMap.this.backendMap .get(this.chunkPosition.getWorldName()); worldBackendData.put(this.chunkPosition.asPair(), this.cachedValue); return oldValue; } } } } private abstract class Itr implements Iterator { protected final Iterator>> worldsIterator; protected Iterator> currWorldIterator = Collections.emptyIterator(); protected String currWorld; protected long currChunk; protected V currValue; protected Itr() { this.worldsIterator = Chunk2ObjectMap.this.backendMap.entrySet().iterator(); } @Override public final boolean hasNext() { return this.currWorldIterator.hasNext() || this.worldsIterator.hasNext(); } @Override public final T next() { if (!this.currWorldIterator.hasNext()) { if (!this.worldsIterator.hasNext()) { throw new NoSuchElementException(); } Entry> nextWorld = this.worldsIterator.next(); this.currWorldIterator = nextWorld.getValue().entryIterator(); this.currWorld = nextWorld.getKey(); onWorldChange(); } Long2ObjectMapView.Entry nextChunk = this.currWorldIterator.next(); this.currChunk = nextChunk.getKey(); this.currValue = nextChunk.getValue(); return getNext(); } protected void onWorldChange() { } protected abstract T getNext(); @Override public final void remove() { Long2ObjectMapView worldBackendData = Chunk2ObjectMap.this.backendMap.get(this.currWorld); this.currWorldIterator.remove(); Chunk2ObjectMap.this.onRemove(this.currValue); if (worldBackendData.isEmpty()) this.worldsIterator.remove(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/CollectionsFactory.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.superiorskyblock.core.collections.creator.CollectionsCreator; import com.bgsoftware.superiorskyblock.core.collections.creator.FastUtilCollectionsCreator; import com.bgsoftware.superiorskyblock.core.collections.creator.JavaCollectionsCreator; import com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; public class CollectionsFactory { private static final CollectionsCreator creator = findSuitableCollectionsCreator(); private CollectionsFactory() { } public static Int2ObjectMapView createInt2ObjectLinkedHashMap() { return creator.createInt2ObjectLinkedHashMap(); } public static Int2ObjectMapView createInt2ObjectArrayMap() { return creator.createInt2ObjectArrayMap(); } public static Int2IntMapView createInt2IntArrayMap() { return creator.createInt2IntArrayMap(); } public static Int2IntMapView createInt2IntHashMap() { return creator.createInt2IntHashMap(); } public static Long2ObjectMapView createLong2ObjectHashMap() { return creator.createLong2ObjectHashMap(); } public static Long2ObjectMapView createLong2ObjectLinkedHashMap() { return creator.createLong2ObjectLinkedHashMap(); } public static Long2ObjectMapView createLong2ObjectArrayMap() { return creator.createLong2ObjectArrayMap(); } public static Char2ObjectMapView createChar2ObjectArrayMap() { return creator.createChar2ObjectArrayMap(); } private static CollectionsCreator findSuitableCollectionsCreator() { try { Class.forName("it.unimi.dsi.fastutil.ints.Int2IntArrayMap"); return FastUtilCollectionsCreator.INSTANCE; } catch (ClassNotFoundException ignored) { } return JavaCollectionsCreator.INSTANCE; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/CompletableFutureList.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.superiorskyblock.core.logging.Log; import java.util.ArrayList; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; public class CompletableFutureList extends ArrayList> { private final long timeout; public CompletableFutureList(long timeout) { this.timeout = timeout; } public void forEachCompleted(Consumer consumer, Consumer onFailure) { CompletableFuture allTasks = CompletableFuture.allOf(toArray(new CompletableFuture[0])).thenRun(() -> { for (CompletableFuture completableFuture : this) { E result = completableFuture.getNow(null); assert result != null; // Result cannot be null as all CompletableFutures must be completed by now. consumer.accept(result); } }).exceptionally(error -> { onFailure.accept(error); return null; }); if (timeout <= 0L) { allTasks.join(); } else try { allTasks.get(timeout, TimeUnit.SECONDS); } catch (Throwable error) { Log.error(error, "An unexpected error occurred while waiting for tasks to complete:"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/EnumerateMap.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.google.common.base.Preconditions; import java.util.AbstractCollection; import java.util.Arrays; import java.util.Collection; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; public class EnumerateMap { private Object[] values; private int size = 0; private Values valuesView; public EnumerateMap(Collection enumerables) { this.values = new Object[enumerables.size()]; } public EnumerateMap(V[] values) { this.values = values.clone(); for (V value : values) if (value != null) ++size; } public EnumerateMap(EnumerateMap other) { this.values = other.values.clone(); this.size = other.size; } public int size() { return this.size; } public boolean isEmpty() { return size() <= 0; } public boolean containsKey(K key) { return get(key) != null; } @Nullable public V get(K key) { return isValidKey(key) ? (V) this.values[key.ordinal()] : null; } public V getOrDefault(K key, V def) { V value = get(key); return value == null ? def : value; } @Nullable public V put(K key, @NotNull V value) { Preconditions.checkNotNull(value, "Cannot set values as nulls."); this.ensureCapacity(key.ordinal() + 1); V oldValue = (V) this.values[key.ordinal()]; this.values[key.ordinal()] = value; if (oldValue == null) ++this.size; return oldValue; } public void putAll(EnumerateMap other) { for (int i = 0; i < other.values.length; ++i) { Object val = other.values[i]; if (val != null) values[i] = val; } } @Nullable public V remove(K key) { if (!isValidKey(key)) return null; V oldValue = (V) this.values[key.ordinal()]; this.values[key.ordinal()] = null; --this.size; return oldValue; } public void clear() { this.values = new Object[this.values.length]; this.size = 0; } public V computeIfAbsent(K key, Function mappingFunction) { V value = get(key); if (value == null) { value = mappingFunction.apply(key); put(key, value); } return value; } public Map collect(Collection enumerables, Function valuesMapper) { Map map = new IdentityHashMap<>(); for (K key : enumerables) { V value = get(key); if (value != null) map.put(key, valuesMapper.apply(value)); } return map; } public Map collect(Collection enumerables, BiFunction valuesMapper) { Map map = new IdentityHashMap<>(); for (K key : enumerables) { V value = get(key); if (value != null) map.put(key, valuesMapper.apply(key, value)); } return map; } public Map collect(Collection enumerables) { Map map = new IdentityHashMap<>(); for (K key : enumerables) { V value = get(key); if (value != null) map.put(key, value); } return map; } public Collection values() { if (valuesView == null) valuesView = new Values(); return valuesView; } private boolean isValidKey(K key) { return key.ordinal() >= 0 && key.ordinal() < this.values.length; } private void ensureCapacity(int capacity) { if (capacity <= this.values.length) return; this.values = Arrays.copyOf(this.values, capacity); } private class Values extends AbstractCollection { public Iterator iterator() { return new ValueIterator(); } public int size() { return size; } public boolean contains(Object o) { for (Object val : values) { if (Objects.equals(o, val)) return true; } return false; } public boolean remove(Object o) { for (int i = 0; i < values.length; i++) { if (Objects.equals(o, values[i])) { values[i] = null; size--; return true; } } return false; } public void clear() { EnumerateMap.this.clear(); } } private class ValueIterator implements Iterator { private int index = 0; private int lastReturnedIndex = -1; @Override public boolean hasNext() { while (index < values.length && values[index] == null) index++; return index != values.length; } @Override public V next() { if (!hasNext()) throw new NoSuchElementException(); lastReturnedIndex = index++; return (V) values[lastReturnedIndex]; } @Override public void remove() { checkLastReturnedIndex(); if (values[lastReturnedIndex] != null) { values[lastReturnedIndex] = null; size--; } lastReturnedIndex = -1; } private void checkLastReturnedIndex() { if (lastReturnedIndex < 0) throw new IllegalStateException(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/EnumerateSet.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; import com.bgsoftware.superiorskyblock.api.world.Dimension; import java.util.Arrays; import java.util.Collection; import java.util.IdentityHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; public class EnumerateSet { private boolean[] values; private int size = 0; public EnumerateSet(Collection enumerables) { this.values = new boolean[enumerables.size()]; } public EnumerateSet(EnumerateSet other) { this.values = other.values.clone(); this.size = other.size; } public int size() { return this.size; } public boolean isEmpty() { return size() <= 0; } public boolean contains(K key) { return isValidKey(key) && this.values[key.ordinal()]; } public boolean add(K key) { this.ensureCapacity(key.ordinal() + 1); boolean containedBefore = this.values[key.ordinal()]; this.values[key.ordinal()] = true; if (!containedBefore) ++this.size; return !containedBefore; } public boolean addAll(EnumerateSet other) { boolean added = false; for (int i = 0; i < other.values.length; ++i) { boolean value = other.values[i]; if (value) { this.ensureCapacity(i + 1); if (!values[i]) { values[i] = added = true; ++size; } } } return added; } public boolean remove(K key) { if (!isValidKey(key)) return false; boolean containedBefore = this.values[key.ordinal()]; this.values[key.ordinal()] = false; --this.size; return containedBefore; } public void clear() { this.values = new boolean[this.values.length]; this.size = 0; } public Set collect(Collection enumerables) { Set set = new LinkedHashSet<>(); for (K key : enumerables) { if (contains(key)) set.add(key); } return set; } @Override public String toString() { return "EnumerateSet{" + Arrays.toString(values) + '}'; } private boolean isValidKey(K key) { return key.ordinal() >= 0 && key.ordinal() < this.values.length; } private void ensureCapacity(int capacity) { if (capacity > this.values.length) this.values = Arrays.copyOf(this.values, capacity); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import java.util.AbstractCollection; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.function.Supplier; public class IslandPosition2ObjectMap { @Nullable private Values values; private final Map> backendMap = new LinkedHashMap<>(); private int size = 0; public int size() { return this.size; } public boolean isEmpty() { return this.size == 0; } @Nullable public V get(String worldName, long packedPos) { Long2ObjectMapView worldBackendData = this.backendMap.get(worldName); if (worldBackendData == null) return null; return worldBackendData.get(packedPos); } public V computeIfAbsent(String worldName, long packedPos, Supplier newValue) { Long2ObjectMapView worldBackendData = this.backendMap.computeIfAbsent(worldName, n -> CollectionsFactory.createLong2ObjectLinkedHashMap()); return worldBackendData.computeIfAbsent(packedPos, p -> { ++IslandPosition2ObjectMap.this.size; return newValue.get(); }); } @Nullable public V put(String worldName, long packedPos, V value) { Long2ObjectMapView worldBackendData = this.backendMap.computeIfAbsent(worldName, n -> CollectionsFactory.createLong2ObjectLinkedHashMap()); V oldValue = worldBackendData.put(packedPos, value); if (oldValue == null) ++this.size; return oldValue; } @Nullable public V remove(String worldName, long packedPos) { Long2ObjectMapView worldBackendData = this.backendMap.get(worldName); if (worldBackendData == null) return null; V oldValue = onRemove(worldBackendData.remove(packedPos)); if (oldValue == null) return null; if (worldBackendData.isEmpty()) IslandPosition2ObjectMap.this.backendMap.remove(worldName); return oldValue; } @Nullable private V onRemove(@Nullable V removedValue) { if (removedValue != null) --this.size; return removedValue; } public void clear() { this.backendMap.clear(); this.size = 0; } @NotNull public Collection values() { return this.values == null ? (this.values = new Values()) : this.values; } private class Values extends AbstractCollection { @Override public int size() { return IslandPosition2ObjectMap.this.size(); } @Override public boolean isEmpty() { return IslandPosition2ObjectMap.this.isEmpty(); } @Override public boolean contains(Object o) { throw new UnsupportedOperationException(); } @NotNull @Override public Iterator iterator() { return new ValuesItr(); } @Override public void clear() { IslandPosition2ObjectMap.this.clear(); } private class ValuesItr extends Itr { @Override protected V getNext() { return this.currentValue; } } } private abstract class Itr implements Iterator { protected final Iterator>> worldsIterator; protected Iterator> currentWorldIterator = Collections.emptyIterator(); protected String currentWorld; protected long currentPosition; protected V currentValue; protected Itr() { this.worldsIterator = IslandPosition2ObjectMap.this.backendMap.entrySet().iterator(); } @Override public final boolean hasNext() { return this.currentWorldIterator.hasNext() || this.worldsIterator.hasNext(); } @Override public final T next() { if (!this.currentWorldIterator.hasNext()) { if (!this.worldsIterator.hasNext()) { throw new NoSuchElementException(); } Map.Entry> nextWorld = this.worldsIterator.next(); this.currentWorldIterator = nextWorld.getValue().entryIterator(); this.currentWorld = nextWorld.getKey(); } Long2ObjectMapView.Entry nextPosition = this.currentWorldIterator.next(); this.currentPosition = nextPosition.getKey(); this.currentValue = nextPosition.getValue(); return getNext(); } protected abstract T getNext(); @Override public final void remove() { Long2ObjectMapView worldBackendData = IslandPosition2ObjectMap.this.backendMap.get(this.currentWorld); this.currentWorldIterator.remove(); IslandPosition2ObjectMap.this.onRemove(this.currentValue); if (worldBackendData.isEmpty()) this.worldsIterator.remove(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/Location2ObjectMap.java ================================================ package com.bgsoftware.superiorskyblock.core.collections; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.google.common.base.Preconditions; import org.bukkit.Location; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Set; import java.util.function.Consumer; public class Location2ObjectMap extends AbstractMap { private static final boolean IS_TALL_WORLD = ServerVersion.isAtLeast(ServerVersion.v1_18); @Nullable private KeySet keySet; @Nullable private Values values; @Nullable private EntrySet entrySet; private final Chunk2ObjectMap> backendMap = new Chunk2ObjectMap<>(); private int size = 0; @Override public int size() { return this.size; } @Override public boolean isEmpty() { return this.size == 0; } @Override public boolean containsKey(Object key) { return get(key) != null; } @Override public boolean containsValue(Object value) { return value != null && super.containsValue(value); } @Override public V get(Object key) { return key instanceof Location ? get((Location) key) : null; } @Nullable private V get(Location location) { String worldName = LazyWorldLocation.getWorldName(location); if (worldName == null) return null; int blockX = location.getBlockX(); int blockZ = location.getBlockZ(); long chunkPair = computeChunkPair(blockX >> 4, blockZ >> 4); ChunkMap chunkMap = this.backendMap.get(worldName, chunkPair); if (chunkMap == null) return null; return chunkMap.get(blockX & 0xF, location.getBlockY(), blockZ & 0xF); } @Nullable @Override public V put(Location location, V value) { String worldName = LazyWorldLocation.getWorldName(location); Preconditions.checkArgument(worldName != null, "cannot insert location with null world"); int blockX = location.getBlockX(); int blockZ = location.getBlockZ(); long chunkPair = computeChunkPair(blockX >> 4, blockZ >> 4); ChunkMap chunkMap = this.backendMap.computeIfAbsent(worldName, chunkPair, ChunkMap::new); V oldValue = chunkMap.put(blockX & 0xF, location.getBlockY(), blockZ & 0xF, value); if (oldValue == null) ++this.size; return oldValue; } @Override public V remove(Object key) { return key instanceof Location ? remove((Location) key) : null; } @Nullable public V remove(Location location) { String worldName = LazyWorldLocation.getWorldName(location); if (worldName == null) return null; int blockX = location.getBlockX(); int blockZ = location.getBlockZ(); long chunkPair = computeChunkPair(blockX >> 4, blockZ >> 4); ChunkMap chunkMap = this.backendMap.get(worldName, chunkPair); if (chunkMap == null) return null; V oldValue = onRemove(chunkMap.remove(blockX & 0xF, location.getBlockY(), blockZ & 0xF)); if (oldValue == null) return null; if (chunkMap.isEmpty()) { this.backendMap.remove(worldName, chunkPair); } return oldValue; } @Nullable private V onRemove(@Nullable V removedValue) { if (removedValue != null) --this.size; return removedValue; } @Override public void clear() { this.backendMap.clear(); this.size = 0; } @NotNull @Override public Set keySet() { return this.keySet == null ? (this.keySet = new KeySet()) : this.keySet; } @NotNull @Override public Collection values() { return this.values == null ? (this.values = new Values()) : this.values; } public void forEach(ChunkPosition chunkPosition, Consumer consumer) { ChunkMap chunkMap = this.backendMap.get(chunkPosition.getWorldName(), chunkPosition.asPair()); if (chunkMap == null) return; Iterator iterator = chunkMap.backendData.valueIterator(); while (iterator.hasNext()) consumer.accept(iterator.next()); } public void removeAll(ChunkPosition chunkPosition, Consumer predicate) { ChunkMap chunkMap = this.backendMap.remove(chunkPosition.getWorldName(), chunkPosition.asPair()); if (chunkMap == null) return; Iterator iterator = chunkMap.backendData.valueIterator(); while (iterator.hasNext()) predicate.accept(iterator.next()); chunkMap.backendData.clear(); } @NotNull @Override public Set> entrySet() { return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet; } private static long computeChunkPair(int chunkX, int chunkZ) { return ((chunkZ & 0xFFFFFFFFL) << 32) | (chunkX & 0xFFFFFFFFL); } private static int computeBlockIndex(int relativeX, int blockY, int relativeZ) { Preconditions.checkArgument(relativeX >= 0 && relativeX <= 0xF, "invalid relativeX: " + relativeX); Preconditions.checkArgument(relativeZ >= 0 && relativeZ <= 0xF, "invalid blockZ: " + relativeZ); int worldMinHeight = IS_TALL_WORLD ? 0 : -64; short relativeY = (short) (blockY - worldMinHeight); return (relativeY << 8) | (relativeX << 4) | relativeZ; } private static Location computeLocationFromBlockAndChunk(String worldName, long chunkPair, int blockIdx) { int chunkX = Chunk2ObjectMap.getChunkXFromPair(chunkPair); int chunkZ = Chunk2ObjectMap.getChunkZFromPair(chunkPair); int blockX = (chunkX << 4) + getRelativeBlockXFromIndex(blockIdx); int blockY = (IS_TALL_WORLD ? 0 : -64) + getRelativeBlockYFromIndex(blockIdx); int blockZ = (chunkZ << 4) + getRelativeBlockZFromIndex(blockIdx); return new LazyWorldLocation(worldName, blockX, blockY, blockZ, 0, 0); } private static int getRelativeBlockXFromIndex(int blockIdx) { return (blockIdx >> 4) & 0xF; } private static int getRelativeBlockYFromIndex(int blockIdx) { return blockIdx >> 8; } private static int getRelativeBlockZFromIndex(int blockIdx) { return blockIdx & 0xF; } private static class ChunkMap { private final Int2ObjectMapView backendData = CollectionsFactory.createInt2ObjectLinkedHashMap(); @Nullable public V get(int relativeX, int blockY, int relativeZ) { int blockIdx = computeBlockIndex(relativeX, blockY, relativeZ); return get(blockIdx); } @Nullable public V get(int blockIdx) { return this.backendData.get(blockIdx); } @Nullable public V put(int relativeX, int blockY, int relativeZ, V value) { int blockIdx = computeBlockIndex(relativeX, blockY, relativeZ); return put(blockIdx, value); } @Nullable public V put(int blockIdx, V value) { return this.backendData.put(blockIdx, value); } @Nullable public V remove(int relativeX, int blockY, int relativeZ) { int blockIdx = computeBlockIndex(relativeX, blockY, relativeZ); return this.remove(blockIdx); } @Nullable public V remove(int blockIdx) { return this.backendData.remove(blockIdx); } public boolean isEmpty() { return this.backendData.isEmpty(); } } private class KeySet extends AbstractSet { @Override public int size() { return Location2ObjectMap.this.size(); } @Override public boolean isEmpty() { return Location2ObjectMap.this.isEmpty(); } @Override public boolean contains(Object o) { return Location2ObjectMap.this.containsKey(o); } @NotNull @Override public Iterator iterator() { return new KeySetItr(); } @Override public void clear() { Location2ObjectMap.this.clear(); } private class KeySetItr extends Itr { @Override protected Location getNext() { return computeLocationFromBlockAndChunk(this.currWorld, this.currChunk, this.currBlockIdx); } } } private class Values extends AbstractCollection { @Override public int size() { return Location2ObjectMap.this.size(); } @Override public boolean isEmpty() { return Location2ObjectMap.this.isEmpty(); } @Override public boolean contains(Object o) { return Location2ObjectMap.this.containsValue(o); } @NotNull @Override public Iterator iterator() { return new ValuesItr(); } @Override public void clear() { Location2ObjectMap.this.clear(); } private class ValuesItr extends Itr { @Override protected V getNext() { return this.currValue; } } } private class EntrySet extends AbstractSet> { @Override public int size() { return Location2ObjectMap.this.size(); } @Override public boolean isEmpty() { return Location2ObjectMap.this.isEmpty(); } @Override public boolean contains(Object o) { Location key = null; if (o instanceof Entry) { o = ((Entry) o).getKey(); } if (o instanceof Location) key = (Location) o; return key != null && Location2ObjectMap.this.containsKey(o); } @NotNull @Override public Iterator> iterator() { return new EntrySetItr(); } @Override public void clear() { Location2ObjectMap.this.clear(); } private class EntrySetItr extends Itr> { @Override protected Entry getNext() { return new EntryImpl(this.currWorld, this.currChunk, this.currBlockIdx, this.currValue); } private class EntryImpl implements Entry { private final String worldName; private final long chunkPair; private final int blockIdx; private Location cachedLocation; private V cachedValue; EntryImpl(String worldName, long chunkPair, int blockIdx, V value) { this.worldName = worldName; this.chunkPair = chunkPair; this.blockIdx = blockIdx; this.cachedValue = value; } @Override public Location getKey() { return this.cachedLocation == null ? (this.cachedLocation = computeLocationFromBlockAndChunk(this.worldName, this.chunkPair, this.blockIdx)) : this.cachedLocation; } @Override public V getValue() { if (this.cachedValue == null) { this.cachedValue = Location2ObjectMap.this.backendMap .get(this.worldName, this.chunkPair) .get(this.blockIdx); } return this.cachedValue; } @Override public V setValue(V v) { V oldValue = this.cachedValue; this.cachedValue = v; Location2ObjectMap.this.backendMap .get(this.worldName, this.chunkPair) .put(this.blockIdx, this.cachedValue); return oldValue; } } } } private abstract class Itr implements Iterator { protected final Iterator>> worldsIterator; protected Iterator> currChunkIterator = Collections.emptyIterator(); protected String currWorld; protected long currChunk; protected ChunkMap currChunkMap; protected int currBlockIdx; protected V currValue; protected Itr() { this.worldsIterator = Location2ObjectMap.this.backendMap.entrySet().iterator(); } @Override public final boolean hasNext() { return this.currChunkIterator.hasNext() || this.worldsIterator.hasNext(); } @Override public final T next() { if (!this.currChunkIterator.hasNext()) { Entry> nextChunk = this.worldsIterator.next(); this.currWorld = nextChunk.getKey().getWorldName(); this.currChunk = nextChunk.getKey().asPair(); this.currChunkMap = nextChunk.getValue(); this.currChunkIterator = this.currChunkMap.backendData.entryIterator(); } Int2ObjectMapView.Entry nextBlock = this.currChunkIterator.next(); this.currBlockIdx = nextBlock.getKey(); this.currValue = nextBlock.getValue(); return getNext(); } protected abstract T getNext(); @Override public final void remove() { this.currChunkIterator.remove(); Location2ObjectMap.this.onRemove(this.currValue); if (this.currChunkMap.isEmpty()) this.worldsIterator.remove(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/creator/CollectionsCreator.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.creator; import com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; public interface CollectionsCreator { Int2ObjectMapView createInt2ObjectLinkedHashMap(); Int2ObjectMapView createInt2ObjectArrayMap(); Int2IntMapView createInt2IntHashMap(); Int2IntMapView createInt2IntArrayMap(); Long2ObjectMapView createLong2ObjectHashMap(); Long2ObjectMapView createLong2ObjectLinkedHashMap(); Long2ObjectMapView createLong2ObjectArrayMap(); Char2ObjectMapView createChar2ObjectArrayMap(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/creator/FastUtilCollectionsCreator.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.creator; import com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.CharIterator; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.IntIterator; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; import it.unimi.dsi.fastutil.chars.Char2ObjectArrayMap; import it.unimi.dsi.fastutil.chars.Char2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectArrayMap; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.Iterator; import java.util.Map; import java.util.OptionalInt; public class FastUtilCollectionsCreator implements CollectionsCreator { public static final FastUtilCollectionsCreator INSTANCE = new FastUtilCollectionsCreator(); private FastUtilCollectionsCreator() { } @Override public Int2ObjectMapView createInt2ObjectLinkedHashMap() { return new Int2ObjectFastUtilMapView<>(new Int2ObjectLinkedOpenHashMap<>()); } @Override public Int2ObjectMapView createInt2ObjectArrayMap() { return new Int2ObjectFastUtilMapView<>(new Int2ObjectArrayMap<>()); } @Override public Int2IntMapView createInt2IntHashMap() { return new Int2IntFastUtilMapView(new Int2IntOpenHashMap()); } @Override public Int2IntMapView createInt2IntArrayMap() { return new Int2IntFastUtilMapView(new Int2IntArrayMap()); } @Override public Long2ObjectMapView createLong2ObjectHashMap() { return new Long2ObjectFastUtilMapView<>(new Long2ObjectOpenHashMap<>()); } @Override public Long2ObjectMapView createLong2ObjectLinkedHashMap() { return new Long2ObjectFastUtilMapView<>(new Long2ObjectLinkedOpenHashMap<>()); } @Override public Long2ObjectMapView createLong2ObjectArrayMap() { return new Long2ObjectFastUtilMapView<>(new Long2ObjectArrayMap<>()); } @Override public Char2ObjectMapView createChar2ObjectArrayMap() { return new Char2ObjectFastUtilMapView<>(new Char2ObjectArrayMap<>()); } private static class Int2ObjectFastUtilMapView implements Int2ObjectMapView { private final Int2ObjectMap delegate; Int2ObjectFastUtilMapView(Int2ObjectMap delegate) { this.delegate = delegate; } @Override public V put(int key, V value) { return this.delegate.put(key, value); } @Override public V get(int key) { return this.delegate.get(key); } @Override public V remove(int key) { return this.delegate.remove(key); } @Override public int size() { return this.delegate.size(); } @Override public void clear() { this.delegate.clear(); } @Override public Iterator> entryIterator() { return new EntryIteratorWrapper<>(this.delegate.int2ObjectEntrySet().iterator()); } @Override public Iterator valueIterator() { return this.delegate.values().iterator(); } @Override public IntIterator keyIterator() { return new IntIteratorWrapper(this.delegate.keySet().iterator()); } private static class EntryIteratorWrapper implements Iterator> { private final Iterator> handle; EntryIteratorWrapper(Iterator> handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public Int2ObjectMapView.Entry next() { return new EntryWrapper(this.handle.next()); } @Override public void remove() { this.handle.remove(); } private class EntryWrapper implements Int2ObjectMapView.Entry { private final Int2ObjectMap.Entry handle; EntryWrapper(Int2ObjectMap.Entry handle) { this.handle = handle; } @Override public int getKey() { return this.handle.getIntKey(); } @Override public V getValue() { return this.handle.getValue(); } @Override public V setValue(V newValue) { return this.handle.setValue(newValue); } } } } private static class Int2IntFastUtilMapView implements Int2IntMapView { private final Int2IntMap delegate; Int2IntFastUtilMapView(Int2IntMap delegate) { this.delegate = delegate; } @Override public OptionalInt put(int key, int value) { int old = this.delegate.put(key, value); return old == this.delegate.defaultReturnValue() ? OptionalInt.empty() : OptionalInt.of(old); } @Override public OptionalInt get(int key) { int old = this.delegate.get(key); return old == this.delegate.defaultReturnValue() ? OptionalInt.empty() : OptionalInt.of(old); } @Override public OptionalInt remove(int key) { int old = this.delegate.remove(key); return old == this.delegate.defaultReturnValue() ? OptionalInt.empty() : OptionalInt.of(old); } @Override public int size() { return this.delegate.size(); } @Override public void clear() { this.delegate.clear(); } @Override public Iterator entryIterator() { return new EntryIteratorWrapper(this.delegate.int2IntEntrySet().iterator()); } @Override public IntIterator valueIterator() { return new IntIteratorWrapper(this.delegate.values().iterator()); } @Override public IntIterator keyIterator() { return new IntIteratorWrapper(this.delegate.keySet().iterator()); } @Override public Map asMap() { return this.delegate; } private static class EntryIteratorWrapper implements Iterator { private final Iterator handle; EntryIteratorWrapper(Iterator handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public Int2IntMapView.Entry next() { return new EntryWrapper(this.handle.next()); } @Override public void remove() { this.handle.remove(); } private static class EntryWrapper implements Int2IntMapView.Entry { private final Int2IntMap.Entry handle; EntryWrapper(Int2IntMap.Entry handle) { this.handle = handle; } @Override public int getKey() { return this.handle.getIntKey(); } @Override public int getValue() { return this.handle.getIntValue(); } @Override public int setValue(int newValue) { return this.handle.setValue(newValue); } } } } private static class Long2ObjectFastUtilMapView implements Long2ObjectMapView { private final Long2ObjectMap delegate; Long2ObjectFastUtilMapView(Long2ObjectMap delegate) { this.delegate = delegate; } @Override public V put(long key, V value) { return this.delegate.put(key, value); } @Override public V get(long key) { return this.delegate.get(key); } @Override public V remove(long key) { return this.delegate.remove(key); } @Override public int size() { return this.delegate.size(); } @Override public void clear() { this.delegate.clear(); } @Override public Iterator> entryIterator() { return new EntryIteratorWrapper<>(this.delegate.long2ObjectEntrySet().iterator()); } @Override public Iterator valueIterator() { return this.delegate.values().iterator(); } @Override public LongIterator keyIterator() { return new LongIteratorWrapper(this.delegate.keySet().iterator()); } private static class EntryIteratorWrapper implements Iterator> { private final Iterator> handle; EntryIteratorWrapper(Iterator> handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public Long2ObjectMapView.Entry next() { return new EntryWrapper(this.handle.next()); } @Override public void remove() { this.handle.remove(); } private class EntryWrapper implements Long2ObjectMapView.Entry { private final Long2ObjectMap.Entry handle; EntryWrapper(Long2ObjectMap.Entry handle) { this.handle = handle; } @Override public long getKey() { return this.handle.getLongKey(); } @Override public V getValue() { return this.handle.getValue(); } @Override public V setValue(V newValue) { return this.handle.setValue(newValue); } } } } private static class Char2ObjectFastUtilMapView implements Char2ObjectMapView { private final Char2ObjectMap delegate; Char2ObjectFastUtilMapView(Char2ObjectMap delegate) { this.delegate = delegate; } @Override public V put(char key, V value) { return this.delegate.put(key, value); } @Override public V get(char key) { return this.delegate.get(key); } @Override public V remove(char key) { return this.delegate.remove(key); } @Override public int size() { return this.delegate.size(); } @Override public void clear() { this.delegate.clear(); } @Override public Iterator> entryIterator() { return new EntryIteratorWrapper<>(this.delegate.char2ObjectEntrySet().iterator()); } @Override public Iterator valueIterator() { return this.delegate.values().iterator(); } @Override public CharIterator keyIterator() { return new CharIteratorWrapper(this.delegate.keySet().iterator()); } private static class EntryIteratorWrapper implements Iterator> { private final Iterator> handle; EntryIteratorWrapper(Iterator> handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public Char2ObjectMapView.Entry next() { return new EntryWrapper(this.handle.next()); } @Override public void remove() { this.handle.remove(); } private class EntryWrapper implements Char2ObjectMapView.Entry { private final Char2ObjectMap.Entry handle; EntryWrapper(Char2ObjectMap.Entry handle) { this.handle = handle; } @Override public char getKey() { return this.handle.getCharKey(); } @Override public V getValue() { return this.handle.getValue(); } @Override public V setValue(V newValue) { return this.handle.setValue(newValue); } } } } private static class IntIteratorWrapper implements IntIterator { private final it.unimi.dsi.fastutil.ints.IntIterator handle; IntIteratorWrapper(it.unimi.dsi.fastutil.ints.IntIterator handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public int next() { return this.handle.nextInt(); } @Override public void remove() { this.handle.remove(); } } private static class LongIteratorWrapper implements LongIterator { private final it.unimi.dsi.fastutil.longs.LongIterator handle; LongIteratorWrapper(it.unimi.dsi.fastutil.longs.LongIterator handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public long next() { return this.handle.nextLong(); } @Override public void remove() { this.handle.remove(); } } private static class CharIteratorWrapper implements CharIterator { private final it.unimi.dsi.fastutil.chars.CharIterator handle; CharIteratorWrapper(it.unimi.dsi.fastutil.chars.CharIterator handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public char next() { return this.handle.nextChar(); } @Override public void remove() { this.handle.remove(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/creator/JavaCollectionsCreator.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.creator; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.CharIterator; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.IntIterator; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.OptionalInt; public class JavaCollectionsCreator implements CollectionsCreator { public static final JavaCollectionsCreator INSTANCE = new JavaCollectionsCreator(); private JavaCollectionsCreator() { } @Override public Int2ObjectMapView createInt2ObjectLinkedHashMap() { return new Int2ObjectJavaMapView<>(new LinkedHashMap<>()); } @Override public Int2ObjectMapView createInt2ObjectArrayMap() { return new Int2ObjectJavaMapView<>(new ArrayMap<>()); } @Override public Int2IntMapView createInt2IntHashMap() { return new Int2IntJavaMapView(new HashMap<>()); } @Override public Int2IntMapView createInt2IntArrayMap() { return new Int2IntJavaMapView(new ArrayMap<>()); } @Override public Long2ObjectMapView createLong2ObjectHashMap() { return new Long2ObjectJavaMapView<>(new HashMap<>()); } @Override public Long2ObjectMapView createLong2ObjectLinkedHashMap() { return new Long2ObjectJavaMapView<>(new LinkedHashMap<>()); } @Override public Long2ObjectMapView createLong2ObjectArrayMap() { return new Long2ObjectJavaMapView<>(new ArrayMap<>()); } @Override public Char2ObjectMapView createChar2ObjectArrayMap() { return new Char2ObjectJavaMapView<>(new ArrayMap<>()); } private static class Int2ObjectJavaMapView implements Int2ObjectMapView { private final Map delegate; Int2ObjectJavaMapView(Map delegate) { this.delegate = delegate; } @Override public V put(int key, V value) { return this.delegate.put(key, value); } @Override public V get(int key) { return this.delegate.get(key); } @Override public V remove(int key) { return this.delegate.remove(key); } @Override public int size() { return this.delegate.size(); } @Override public void clear() { this.delegate.clear(); } @Override public Iterator> entryIterator() { return new EntryIteratorWrapper<>(this.delegate.entrySet().iterator()); } @Override public Iterator valueIterator() { return this.delegate.values().iterator(); } @Override public IntIterator keyIterator() { return new IntIteratorWrapper(this.delegate.keySet().iterator()); } private static class EntryIteratorWrapper implements Iterator> { private final Iterator> handle; EntryIteratorWrapper(Iterator> handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public Int2ObjectMapView.Entry next() { return new EntryWrapper(this.handle.next()); } @Override public void remove() { this.handle.remove(); } private class EntryWrapper implements Int2ObjectMapView.Entry { private final Map.Entry handle; EntryWrapper(Map.Entry handle) { this.handle = handle; } @Override public int getKey() { return this.handle.getKey(); } @Override public V getValue() { return this.handle.getValue(); } @Override public V setValue(V newValue) { return this.handle.setValue(newValue); } } } } private static class Int2IntJavaMapView implements Int2IntMapView { private final Map delegate; Int2IntJavaMapView(Map delegate) { this.delegate = delegate; } @Override public OptionalInt put(int key, int value) { Integer old = this.delegate.put(key, value); return old == null ? OptionalInt.empty() : OptionalInt.of(old); } @Override public OptionalInt get(int key) { Integer old = this.delegate.get(key); return old == null ? OptionalInt.empty() : OptionalInt.of(old); } @Override public OptionalInt remove(int key) { Integer old = this.delegate.remove(key); return old == null ? OptionalInt.empty() : OptionalInt.of(old); } @Override public int size() { return this.delegate.size(); } @Override public void clear() { this.delegate.clear(); } @Override public Iterator entryIterator() { return new EntryIteratorWrapper(this.delegate.entrySet().iterator()); } @Override public IntIterator valueIterator() { return new IntIteratorWrapper(this.delegate.values().iterator()); } @Override public IntIterator keyIterator() { return new IntIteratorWrapper(this.delegate.values().iterator()); } @Override public Map asMap() { return this.delegate; } private static class EntryIteratorWrapper implements Iterator { private final Iterator> handle; EntryIteratorWrapper(Iterator> handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public Int2IntMapView.Entry next() { return new EntryWrapper(this.handle.next()); } @Override public void remove() { this.handle.remove(); } private static class EntryWrapper implements Int2IntMapView.Entry { private final Map.Entry handle; EntryWrapper(Map.Entry handle) { this.handle = handle; } @Override public int getKey() { return this.handle.getKey(); } @Override public int getValue() { return this.handle.getValue(); } @Override public int setValue(int newValue) { return this.handle.setValue(newValue); } } } } private static class Long2ObjectJavaMapView implements Long2ObjectMapView { private final Map delegate; Long2ObjectJavaMapView(Map delegate) { this.delegate = delegate; } @Override public V put(long key, V value) { return this.delegate.put(key, value); } @Override public V get(long key) { return this.delegate.get(key); } @Override public V remove(long key) { return this.delegate.remove(key); } @Override public int size() { return this.delegate.size(); } @Override public void clear() { this.delegate.clear(); } @Override public Iterator> entryIterator() { return new EntryIteratorWrapper<>(this.delegate.entrySet().iterator()); } @Override public Iterator valueIterator() { return this.delegate.values().iterator(); } @Override public LongIterator keyIterator() { return new LongIteratorWrapper(this.delegate.keySet().iterator()); } private static class EntryIteratorWrapper implements Iterator> { private final Iterator> handle; EntryIteratorWrapper(Iterator> handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public Long2ObjectMapView.Entry next() { return new EntryWrapper(this.handle.next()); } @Override public void remove() { this.handle.remove(); } private class EntryWrapper implements Long2ObjectMapView.Entry { private final Map.Entry handle; EntryWrapper(Map.Entry handle) { this.handle = handle; } @Override public long getKey() { return this.handle.getKey(); } @Override public V getValue() { return this.handle.getValue(); } @Override public V setValue(V newValue) { return this.handle.setValue(newValue); } } } } private static class Char2ObjectJavaMapView implements Char2ObjectMapView { private final Map delegate; Char2ObjectJavaMapView(Map delegate) { this.delegate = delegate; } @Override public V put(char key, V value) { return this.delegate.put(key, value); } @Override public V get(char key) { return this.delegate.get(key); } @Override public V remove(char key) { return this.delegate.remove(key); } @Override public int size() { return this.delegate.size(); } @Override public void clear() { this.delegate.clear(); } @Override public Iterator> entryIterator() { return new EntryIteratorWrapper<>(this.delegate.entrySet().iterator()); } @Override public Iterator valueIterator() { return this.delegate.values().iterator(); } @Override public CharIterator keyIterator() { return new CharIteratorWrapper(this.delegate.keySet().iterator()); } private static class EntryIteratorWrapper implements Iterator> { private final Iterator> handle; EntryIteratorWrapper(Iterator> handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public Char2ObjectMapView.Entry next() { return new EntryWrapper(this.handle.next()); } @Override public void remove() { this.handle.remove(); } private class EntryWrapper implements Char2ObjectMapView.Entry { private final Map.Entry handle; EntryWrapper(Map.Entry handle) { this.handle = handle; } @Override public char getKey() { return this.handle.getKey(); } @Override public V getValue() { return this.handle.getValue(); } @Override public V setValue(V newValue) { return this.handle.setValue(newValue); } } } } private static class IntIteratorWrapper implements IntIterator { private final Iterator handle; IntIteratorWrapper(Iterator handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public int next() { return this.handle.next(); } @Override public void remove() { this.handle.remove(); } } private static class LongIteratorWrapper implements LongIterator { private final Iterator handle; LongIteratorWrapper(Iterator handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public long next() { return this.handle.next(); } @Override public void remove() { this.handle.remove(); } } private static class CharIteratorWrapper implements CharIterator { private final Iterator handle; CharIteratorWrapper(Iterator handle) { this.handle = handle; } @Override public boolean hasNext() { return this.handle.hasNext(); } @Override public char next() { return this.handle.next(); } @Override public void remove() { this.handle.remove(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Char2ObjectMapView.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; import com.bgsoftware.common.annotations.Nullable; import java.util.Iterator; public interface Char2ObjectMapView { @Nullable V put(char key, V value); @Nullable V get(char key); default V getOrDefault(char key, V def) { V value = get(key); return value == null ? def : value; } @Nullable V remove(char key); int size(); default boolean isEmpty() { return size() <= 0; } void clear(); Iterator> entryIterator(); Iterator valueIterator(); CharIterator keyIterator(); default V computeIfAbsent(char key, AbsentConsumer consumer) { V value = get(key); if (value == null) { value = consumer.accept(key); put(key, value); } return value; } interface AbsentConsumer { V accept(char key); } interface Entry { char getKey(); V getValue(); V setValue(V newValue); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/CharIterator.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; public interface CharIterator { boolean hasNext(); char next(); void remove(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/EmptyInt2IntMapView.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.OptionalInt; public class EmptyInt2IntMapView implements Int2IntMapView { public static final EmptyInt2IntMapView INSTANCE = new EmptyInt2IntMapView(); private EmptyInt2IntMapView() { } @Override public OptionalInt put(int key, int value) { throw new UnsupportedOperationException(); } @Override public OptionalInt get(int key) { return OptionalInt.empty(); } @Override public OptionalInt remove(int key) { throw new UnsupportedOperationException(); } @Override public int size() { return 0; } @Override public void clear() { throw new UnsupportedOperationException(); } @Override public Iterator entryIterator() { return Collections.emptyIterator(); } @Override public IntIterator valueIterator() { return EmptyIntIterator.INSTANCE; } @Override public IntIterator keyIterator() { return EmptyIntIterator.INSTANCE; } @Override public Map asMap() { return Collections.emptyMap(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/EmptyIntIterator.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; import java.util.NoSuchElementException; public class EmptyIntIterator implements IntIterator { public static final EmptyIntIterator INSTANCE = new EmptyIntIterator(); private EmptyIntIterator() { } @Override public boolean hasNext() { return false; } @Override public int next() { throw new NoSuchElementException(); } @Override public void remove() { throw new NoSuchElementException(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Int2IntMapView.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; import java.util.Iterator; import java.util.Map; import java.util.OptionalInt; public interface Int2IntMapView { OptionalInt put(int key, int value); OptionalInt get(int key); default int getOrDefault(int key, int def) { OptionalInt value = get(key); return value.isPresent() ? value.getAsInt() : def; } OptionalInt remove(int key); int size(); default boolean isEmpty() { return size() <= 0; } void clear(); Iterator entryIterator(); IntIterator valueIterator(); IntIterator keyIterator(); Map asMap(); default int computeIfAbsent(int key, AbsentConsumer consumer) { OptionalInt valueOptional = get(key); int value; if (valueOptional.isPresent()) { value = valueOptional.getAsInt(); } else { value = consumer.accept(key); put(key, value); } return value; } interface AbsentConsumer { int accept(int key); } interface Entry { int getKey(); int getValue(); int setValue(int newValue); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Int2ObjectMapView.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; import com.bgsoftware.common.annotations.Nullable; import java.util.Iterator; public interface Int2ObjectMapView { @Nullable V put(int key, V value); @Nullable V get(int key); default V getOrDefault(int key, V def) { V value = get(key); return value == null ? def : value; } @Nullable V remove(int key); int size(); default boolean isEmpty() { return size() <= 0; } void clear(); Iterator> entryIterator(); Iterator valueIterator(); IntIterator keyIterator(); default V computeIfAbsent(int key, AbsentConsumer consumer) { V value = get(key); if (value == null) { value = consumer.accept(key); put(key, value); } return value; } default void putAll(Int2ObjectMapView other) { if (!other.isEmpty()) { Iterator> iterator = other.entryIterator(); while (iterator.hasNext()) { Entry entry = iterator.next(); put(entry.getKey(), entry.getValue()); } } } interface AbsentConsumer { V accept(int key); } interface Entry { int getKey(); V getValue(); V setValue(V newValue); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/IntIterator.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; public interface IntIterator { boolean hasNext(); int next(); void remove(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Long2ObjectMapView.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; import com.bgsoftware.common.annotations.Nullable; import java.util.Iterator; public interface Long2ObjectMapView { @Nullable V put(long key, V value); @Nullable V get(long key); default V getOrDefault(long key, V def) { V value = get(key); return value == null ? def : value; } default void putAll(Long2ObjectMapView other) { Iterator> iterator = other.entryIterator(); while (iterator.hasNext()) { Entry entry = iterator.next(); put(entry.getKey(), entry.getValue()); } } @Nullable V remove(long key); int size(); default boolean isEmpty() { return size() <= 0; } void clear(); Iterator> entryIterator(); Iterator valueIterator(); LongIterator keyIterator(); default V computeIfAbsent(long key, AbsentConsumer consumer) { V value = get(key); if (value == null) { value = consumer.accept(key); put(key, value); } return value; } interface AbsentConsumer { V accept(long key); } interface Entry { long getKey(); V getValue(); V setValue(V newValue); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/LongIterator.java ================================================ package com.bgsoftware.superiorskyblock.core.collections.view; public interface LongIterator { boolean hasNext(); long next(); void remove(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/config/PvPWorldsCache.java ================================================ package com.bgsoftware.superiorskyblock.core.config; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; public class PvPWorldsCache { private final Set pvpWorldNames = new HashSet<>(); private final List pvpWorldPatterns = new LinkedList<>(); public PvPWorldsCache(List pvpWorlds) { for (String worldName : pvpWorlds) { Pattern worldNamePattern = getPatternRegex(worldName); if (worldNamePattern == null) { this.pvpWorldNames.add(worldName); } else { this.pvpWorldPatterns.add(worldNamePattern); } } } public boolean isPvPWorld(String worldName) { return isPvPWorldByName(worldName) || isPvPWorldByPattern(worldName); } private boolean isPvPWorldByName(String worldName) { return !this.pvpWorldNames.isEmpty() && this.pvpWorldNames.contains(worldName); } private boolean isPvPWorldByPattern(String worldName) { for (Pattern pattern : this.pvpWorldPatterns) { if (pattern.matcher(worldName).matches()) return true; } return false; } private static Pattern getPatternRegex(String value) { try { Pattern pattern = Pattern.compile(value); if (value.matches(".*[.*+?^${}()|\\[\\]\\\\].*")) return pattern; } catch (PatternSyntaxException ignored) { } return null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/DBColumn.java ================================================ package com.bgsoftware.superiorskyblock.core.database; import com.bgsoftware.superiorskyblock.api.objects.Pair; public class DBColumn extends Pair { public DBColumn(String columnName, Object value) { super(columnName, value); } public DBColumn withNameAndValue(String columnName, Object value) { setKey(columnName); setValue(value); return this; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java ================================================ package com.bgsoftware.superiorskyblock.core.database; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.cache.DatabaseCache; import com.bgsoftware.superiorskyblock.core.database.loader.DatabaseLoader; import com.bgsoftware.superiorskyblock.core.database.loader.backup.BackupDatabase; import com.bgsoftware.superiorskyblock.core.database.loader.sql.SQLDatabaseLoader; import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsDeserializer; import com.bgsoftware.superiorskyblock.core.database.serialization.PlayersDeserializer; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.Bukkit; import org.bukkit.Location; import java.io.File; import java.math.BigDecimal; import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; @SuppressWarnings("WeakerAccess") public class DataManager extends Manager { private static final UUID CONSOLE_UUID = new UUID(0, 0); private final List databaseLoaders = new LinkedList<>(); public DataManager(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override public void loadData() throws ManagerLoadException { loadDatabaseLoaders(); runState(DatabaseLoader.State.INITIALIZE); runState(DatabaseLoader.State.POST_INITIALIZE); runState(DatabaseLoader.State.PRE_LOAD_DATA); if (PluginEventsFactory.callPluginLoadDataEvent()) { loadPlayers(); loadIslands(); loadGrid(); } runState(DatabaseLoader.State.POST_LOAD_DATA); /* * Because of a bug caused leaders to be guests, I am looping through all the players and trying to fix it here. */ for (SuperiorPlayer superiorPlayer : plugin.getPlayers().getAllPlayers()) { if (superiorPlayer.getIslandLeader().getUniqueId().equals(superiorPlayer.getUniqueId()) && superiorPlayer.getIsland() != null && !superiorPlayer.getPlayerRole().isLastRole()) { Log.warn("Seems like ", superiorPlayer.getName(), " is an island leader, but have a guest role - fixing it..."); superiorPlayer.setPlayerRole(SPlayerRole.lastRole()); } } } public void addDatabaseLoader(DatabaseLoader databaseLoader) { this.databaseLoaders.add(databaseLoader); } public void saveDatabase(boolean async) { if (async && Bukkit.isPrimaryThread()) { BukkitExecutor.async(() -> saveDatabase(false)); return; } try { //Saving grid GridDatabaseBridge.deleteGrid(plugin.getGrid()); GridDatabaseBridge.insertGrid(plugin.getGrid()); } catch (Exception error) { Log.error(error, "An unexpected error occurred while saving database:"); } } public void closeConnection() { for (DatabaseLoader databaseLoader : databaseLoaders) { try { databaseLoader.setState(DatabaseLoader.State.SHUTDOWN); } catch (Throwable ignored) { } } } private void loadDatabaseLoaders() { addDatabaseLoader(new CopyOldDatabase()); addDatabaseLoader(new BackupDatabase(plugin)); addDatabaseLoader(new SQLDatabaseLoader(plugin)); } private void loadPlayers() { Log.info("Starting to load players..."); DatabaseBridge playersLoader = PlayersDatabaseBridge.getGlobalPlayersBridge(); DatabaseCache databaseCache = new DatabaseCache<>(); AtomicInteger playersCount = new AtomicInteger(); long startTime = System.currentTimeMillis(); PlayersDeserializer.deserializeMissions(playersLoader, databaseCache); PlayersDeserializer.deserializePlayerSettings(playersLoader, databaseCache); PlayersDeserializer.deserializePersistentDataContainer(playersLoader, databaseCache); playersLoader.loadAllObjects("players", resultSetRaw -> { DatabaseResult databaseResult = new DatabaseResult(resultSetRaw); Optional uuid = databaseResult.getUUID("uuid"); if (!uuid.isPresent()) { Log.warn("Cannot load player with null uuid, skipping..."); return; } if (uuid.get().equals(CONSOLE_UUID)) { Log.warn("Cannot load player with uuid 0 (it is reserved to CONSOLE), skipping..."); return; } DatabaseCache.Record playerRecord = databaseCache.computeIfAbsentInfo(uuid.get(), SuperiorPlayer::newBuilder); playerRecord.get() .setUniqueId(uuid.get()) .setName(databaseResult.getString("last_used_name").orElse("null")) .setDisbands(databaseResult.getInt("disbands").orElse(0)) .setTextureValue(databaseResult.getString("last_used_skin").orElse("")) .setLastTimeUpdated(databaseResult.getLong("last_time_updated").orElse(System.currentTimeMillis() / 1000)); checkCorruptedPlayerRecord(playerRecord); plugin.getPlayers().getPlayersContainer().addPlayer(playerRecord.get().build()); playersCount.incrementAndGet(); }); long endTime = System.currentTimeMillis(); Log.info("Finished loading " + playersCount.get() + " players (Took " + (endTime - startTime) + "ms)"); } private void checkCorruptedPlayerRecord(DatabaseCache.Record playerRecord) { if (playerRecord.getRecordedTables().contains("players_settings")) return; // We create a temporary SuperiorPlayer for inserting the corrupted record SuperiorPlayer superiorPlayer = playerRecord.get().build(); Log.warn("The player " + superiorPlayer.getUniqueId() + " does not have a players_settings record - fixing it..."); PlayersDatabaseBridge.insertPlayerSettings(superiorPlayer); } private void loadIslands() { Log.info("Starting to load islands..."); DatabaseBridge islandsLoader = plugin.getFactory().createDatabaseBridge((Island) null); DatabaseCache databaseCache = new DatabaseCache<>(); AtomicInteger islandsCount = new AtomicInteger(); long startTime = System.currentTimeMillis(); IslandsDeserializer.deserializeIslandHomes(islandsLoader, databaseCache); IslandsDeserializer.deserializeMembers(islandsLoader, databaseCache); IslandsDeserializer.deserializeBanned(islandsLoader, databaseCache); IslandsDeserializer.deserializePlayerPermissions(islandsLoader, databaseCache); IslandsDeserializer.deserializeRolePermissions(islandsLoader, databaseCache); IslandsDeserializer.deserializeUpgrades(islandsLoader, databaseCache); IslandsDeserializer.deserializeWarps(islandsLoader, databaseCache); IslandsDeserializer.deserializeBlockLimits(islandsLoader, databaseCache); IslandsDeserializer.deserializeRatings(islandsLoader, databaseCache); IslandsDeserializer.deserializeMissions(islandsLoader, databaseCache); IslandsDeserializer.deserializeIslandFlags(islandsLoader, databaseCache); IslandsDeserializer.deserializeGenerators(islandsLoader, databaseCache); IslandsDeserializer.deserializeVisitors(islandsLoader, databaseCache); IslandsDeserializer.deserializeEntityLimits(islandsLoader, databaseCache); IslandsDeserializer.deserializeEffects(islandsLoader, databaseCache); IslandsDeserializer.deserializeIslandChest(islandsLoader, databaseCache); IslandsDeserializer.deserializeRoleLimits(islandsLoader, databaseCache); IslandsDeserializer.deserializeWarpCategories(islandsLoader, databaseCache); IslandsDeserializer.deserializeIslandBank(islandsLoader, databaseCache); IslandsDeserializer.deserializeVisitorHomes(islandsLoader, databaseCache); IslandsDeserializer.deserializeIslandSettings(islandsLoader, databaseCache); IslandsDeserializer.deserializeBankTransactions(islandsLoader, databaseCache); IslandsDeserializer.deserializePersistentDataContainer(islandsLoader, databaseCache); islandsLoader.loadAllObjects("islands", resultSetRaw -> { DatabaseResult databaseResult = new DatabaseResult(resultSetRaw); Optional uuid = databaseResult.getUUID("uuid"); if (!uuid.isPresent()) { Log.warn("Cannot load island with invalid uuid, skipping..."); return; } Optional ownerUUID = databaseResult.getUUID("owner"); if (!ownerUUID.isPresent()) { Log.warn("Cannot load island with invalid owner uuid, skipping..."); return; } SuperiorPlayer owner = plugin.getPlayers().getSuperiorPlayer(ownerUUID.get(), false); if (owner == null) { Log.warn("Cannot load island with unrecognized owner uuid: " + ownerUUID.get() + ", skipping..."); return; } Optional center = databaseResult.getString("center").map(Serializers.LOCATION_SERIALIZER::deserialize); if (!center.isPresent()) { Log.warn("Cannot load island with invalid center, skipping..."); return; } DatabaseCache.Record islandRecord = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); Island.Builder builder = islandRecord.get() .setOwner(owner) .setUniqueId(uuid.get()) .setCenter(center.get()) .setName(databaseResult.getString("name").orElse("")) .setSchematicName(databaseResult.getString("island_type").orElse(null)) .setCreationTime(databaseResult.getLong("creation_time").orElse(System.currentTimeMillis() / 1000L)) .setDiscord(databaseResult.getString("discord").orElse("None")) .setPaypal(databaseResult.getString("paypal").orElse("None")) .setBonusWorth(databaseResult.getBigDecimal("worth_bonus").orElse(BigDecimal.ZERO)) .setBonusLevel(databaseResult.getBigDecimal("levels_bonus").orElse(BigDecimal.ZERO)) .setLocked(databaseResult.getBoolean("locked").orElse(false)) .setIgnored(databaseResult.getBoolean("ignored").orElse(false)) .setDescription(databaseResult.getString("description").orElse("")) .setLastTimeUpdated(databaseResult.getLong("last_time_updated").orElse(System.currentTimeMillis() / 1000L)); databaseResult.getString("generated_schematics").ifPresent(generatedSchematics -> { IslandsDeserializer.deserializeDimensionsList(generatedSchematics, builder::setGeneratedSchematic); }); databaseResult.getString("unlocked_worlds").ifPresent(unlockedWorlds -> { IslandsDeserializer.deserializeDimensionsList(unlockedWorlds, builder::setUnlockedWorld); }); databaseResult.getString("dirty_chunks").ifPresent(dirtyChunks -> { IslandsDeserializer.deserializeDirtyChunks(builder, dirtyChunks); }); databaseResult.getString("block_counts").ifPresent(blockCounts -> { IslandsDeserializer.deserializeBlockCounts(builder, blockCounts); }); databaseResult.getString("entity_counts").ifPresent(entityCounts -> { IslandsDeserializer.deserializeEntityCounts(builder, entityCounts); }); checkCorruptedIslandRecord(islandRecord); plugin.getGrid().getIslandsContainer().addIsland(builder.build()); islandsCount.incrementAndGet(); }); long endTime = System.currentTimeMillis(); Log.info("Finished loading " + islandsCount.get() + " islands (Took " + (endTime - startTime) + "ms)"); } private void checkCorruptedIslandRecord(DatabaseCache.Record islandRecord) { boolean hasIslandsBanks = islandRecord.getRecordedTables().contains("islands_banks"); boolean hasIslandsSettings = islandRecord.getRecordedTables().contains("islands_settings"); if (hasIslandsBanks && hasIslandsSettings) return; // We create a temporary Island for inserting the corrupted record Island island = islandRecord.get().build(); if (!hasIslandsBanks) { Log.warn("The island " + island.getUniqueId() + " does not have a islands_banks record - fixing it..."); IslandsDatabaseBridge.insertIslandBanks(island); } if (!hasIslandsSettings) { Log.warn("The island " + island.getUniqueId() + " does not have a islands_settings record - fixing it..."); IslandsDatabaseBridge.insertIslandSettings(island); } } private void loadGrid() { Log.info("Starting to load grid..."); DatabaseBridge gridLoader = plugin.getFactory().createDatabaseBridge((GridManager) null); gridLoader.loadAllObjects("grid", resultSet -> plugin.getGrid().loadGrid(new DatabaseResult(resultSet))); Log.info("Finished grid!"); } private void runState(DatabaseLoader.State state) throws ManagerLoadException { for (DatabaseLoader databaseLoader : databaseLoaders) { databaseLoader.setState(state); } } private class CopyOldDatabase implements DatabaseLoader { @Override public void setState(State state) throws ManagerLoadException { if (state == State.INITIALIZE) { File oldDataFile = new File(plugin.getDataFolder(), "database.db"); if (oldDataFile.exists()) { File newDataFile = new File(plugin.getDataFolder(), "datastore/database.db"); newDataFile.getParentFile().mkdirs(); if (!oldDataFile.renameTo(newDataFile)) throw new ManagerLoadException("Failed to move old database file", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/DatabaseResult.java ================================================ package com.bgsoftware.superiorskyblock.core.database; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.EnumHelper; import java.math.BigDecimal; import java.util.Map; import java.util.Optional; import java.util.UUID; public class DatabaseResult { private final Map resultSet; public DatabaseResult(Map resultSet) { this.resultSet = resultSet; } public Optional getString(String key) { return getObject(key, String.class); } public Optional getInt(String key) { return getObject(key, Integer.class); } public Optional getLong(String key) { Object value = getObject(key); if (value != null) { if (value instanceof Long) { return Optional.of((long) value); } else if (value instanceof Integer) { return Optional.of((long) (int) value); } } return Optional.empty(); } public Optional getDouble(String key) { Object value = getObject(key); if (value != null) { if (value instanceof Double) { return Optional.of((double) value); } else if (value instanceof Long) { return Optional.of((double) (long) value); } else if (value instanceof Integer) { return Optional.of((double) (int) value); } else if (value instanceof BigDecimal) { return Optional.of(((BigDecimal) value).doubleValue()); } } return Optional.empty(); } public Optional getBoolean(String key) { Object value = getObject(key); if (value != null) { if (value instanceof Integer) { return Optional.of((int) value == 1); } else if (value instanceof Boolean) { return Optional.of((boolean) value); } else if (value instanceof Byte) { return Optional.of((byte) value == 1); } } return Optional.empty(); } public Optional getByte(String key) { Object value = getObject(key); if (value != null) { if (value instanceof Byte) { return Optional.of((byte) value); } else if (value instanceof Boolean) { return Optional.of((Boolean) value ? (byte) 1 : 0); } else if (value instanceof Integer) { return Optional.of((byte) (int) value); } } return Optional.empty(); } public Optional getBigDecimal(String key) { Optional value = getString(key); try { return value.map(BigDecimal::new); } catch (NumberFormatException | NullPointerException ex) { return Optional.empty(); } } public Optional getUUID(String key) { Optional value = getString(key); if (!value.isPresent()) return Optional.empty(); try { return Optional.of(UUID.fromString(value.get())); } catch (IllegalArgumentException error) { return Optional.empty(); } } public > Optional getEnum(String key, Class enumType) { return getString(key).map(s -> EnumHelper.getEnum(enumType, s)); } public Optional getBlob(String key) { Object obj = getObject(key); if (obj instanceof String) { return Optional.of(((String) obj).getBytes()); } else if (obj instanceof byte[]) { return Optional.of((byte[]) obj); } return Optional.empty(); } private Optional getObject(String key, Class clazz) { Object value = getObject(key); return Optional.ofNullable(value == null || !value.getClass().isAssignableFrom(clazz) ? null : clazz.cast(value)); } @Nullable private Object getObject(String key) { return resultSet.get(key); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/EmptyDatabaseBridge.java ================================================ package com.bgsoftware.superiorskyblock.core.database.bridge; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.api.objects.Pair; import java.util.Map; import java.util.function.Consumer; public class EmptyDatabaseBridge implements DatabaseBridge { private static final EmptyDatabaseBridge instance = new EmptyDatabaseBridge(); private EmptyDatabaseBridge() { } public static EmptyDatabaseBridge getInstance() { return instance; } @Override public void loadAllObjects(String table, Consumer> resultConsumer) { // Do nothing. } @Override public void batchOperations(boolean batchOperations) { // Do nothing. } @Override public void updateObject(String table, @Nullable DatabaseFilter filter, Pair... columns) { // Do nothing. } @Override public void insertObject(String table, Pair... columns) { // Do nothing. } @Override public void deleteObject(String table, @Nullable DatabaseFilter filter) { // Do nothing. } @Override public void loadObject(String table, @Nullable DatabaseFilter filter, Consumer> resultConsumer) { // Do nothing. } @Override public void setDatabaseBridgeMode(DatabaseBridgeMode databaseBridgeMode) { // Do nothing. } @Override public DatabaseBridgeMode getDatabaseBridgeMode() { return DatabaseBridgeMode.IDLE; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java ================================================ package com.bgsoftware.superiorskyblock.core.database.bridge; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import java.util.function.Consumer; public class GridDatabaseBridge { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private GridDatabaseBridge() { } public static void saveLastIsland(GridManager gridManager, BlockPosition lastIsland) { runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue("last_island", Serializers.BLOCK_POSITION_SERIALIZER.serialize(lastIsland)); databaseBridge.updateObject("grid", null, column); } }); } public static void updateVersion(GridManager gridManager, int version) { runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> { databaseBridge.deleteObject("ssb_metadata", null); try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue("version", version); databaseBridge.insertObject("ssb_metadata", column); } }); } public static void insertGrid(GridManager gridManager) { runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("grid", pool.obtain().withNameAndValue("last_island", Serializers.BLOCK_POSITION_SERIALIZER.serialize(gridManager.getLastIslandPosition())), pool.obtain().withNameAndValue("max_island_size", plugin.getSettings().getMaxIslandSize()), pool.obtain().withNameAndValue("world", plugin.getSettings().getWorlds().getDefaultWorldName()) ); } }); } public static void deleteGrid(GridManager gridManager) { runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("grid", null)); } private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer databaseBridgeConsumer) { if (databaseBridge.getDatabaseBridgeMode() == DatabaseBridgeMode.SAVE_DATA) databaseBridgeConsumer.accept(databaseBridge); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java ================================================ package com.bgsoftware.superiorskyblock.core.database.bridge; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; public class IslandsDatabaseBridge { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Map>> SAVE_METHODS_TO_BE_EXECUTED = new ConcurrentHashMap<>(); private IslandsDatabaseBridge() { } public static void addMember(Island island, SuperiorPlayer superiorPlayer, long addTime) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_members", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), pool.obtain().withNameAndValue("role", superiorPlayer.getPlayerRole().getId()), pool.obtain().withNameAndValue("join_time", addTime) ); } }); } public static void removeMember(Island island, SuperiorPlayer superiorPlayer) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.deleteObject("islands_members", createFilter(pool, "island", island, pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()))); } }); } public static void saveMemberRole(Island island, SuperiorPlayer superiorPlayer) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_members", createFilter(pool, "island", island, pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString())), pool.obtain().withNameAndValue("role", superiorPlayer.getPlayerRole().getId()) ); } }); } public static void addBannedPlayer(Island island, SuperiorPlayer superiorPlayer, UUID banner, long banTime) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_bans", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), pool.obtain().withNameAndValue("banned_by", banner.toString()), pool.obtain().withNameAndValue("banned_time", banTime) ); } }); } public static void removeBannedPlayer(Island island, SuperiorPlayer superiorPlayer) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()); databaseBridge.deleteObject("islands_bans", createFilter(pool, "island", island, column)); } }); } public static void saveCoopLimit(Island island) { updateIslandSettingsValue(island, "coops_limit", island.getCoopLimit()); } public static void saveIslandHome(Island island, Dimension dimension, @Nullable WorldPosition worldPosition) { if (worldPosition == null) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("environment", dimension.getName()); databaseBridge.deleteObject("islands_homes", createFilter(pool, "island", island, column)); } }); } else { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_homes", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("environment", dimension.getName()), pool.obtain().withNameAndValue("location", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition)) ); } }); } } public static void saveVisitorLocation(Island island, Dimension dimension, @Nullable WorldPosition worldPosition) { if (worldPosition == null) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("environment", dimension.getName()); databaseBridge.deleteObject("islands_visitor_homes", createFilter(pool, "island", island, column)); } }); } else { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_visitor_homes", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("environment", dimension.getName()), pool.obtain().withNameAndValue("location", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition)) ); } }); } } public static void saveUnlockedWorlds(Island island) { updateIslandValue(island, "unlocked_worlds", IslandsSerializer.serializeDimensions(island.getUnlockedWorlds())); } public static void savePlayerPermission(Island island, SuperiorPlayer superiorPlayer, IslandPrivilege privilege, boolean status) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_player_permissions", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), pool.obtain().withNameAndValue("permission", privilege.getName()), pool.obtain().withNameAndValue("status", status) ); } }); } public static void clearPlayerPermission(Island island, SuperiorPlayer superiorPlayer) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()); databaseBridge.deleteObject("islands_player_permissions", createFilter(pool, "island", island, column)); } }); } public static void saveRolePermission(Island island, PlayerRole playerRole, IslandPrivilege privilege) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_role_permissions", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("role", playerRole.getId()), pool.obtain().withNameAndValue("permission", privilege.getName()) ); } }); } public static void clearRolePermissions(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_role_permissions", createFilter("island", island))); } public static void saveName(Island island) { updateIslandValue(island, "name", IslandNames.getNameForDatabase(island)); } public static void saveDescription(Island island) { updateIslandValue(island, "description", island.getDescription()); } public static void saveSize(Island island) { updateIslandSettingsValue(island, "size", island.getIslandSize()); } public static void saveDiscord(Island island) { updateIslandValue(island, "discord", island.getDiscord()); } public static void savePaypal(Island island) { updateIslandValue(island, "paypal", island.getPaypal()); } public static void saveLockedStatus(Island island) { updateIslandValue(island, "locked", island.isLocked()); } public static void saveIgnoredStatus(Island island) { updateIslandValue(island, "ignored", island.isIgnored()); } public static void saveLastTimeUpdate(Island island) { updateIslandValue(island, "last_time_updated", island.getLastTimeUpdate()); } public static void saveBankLimit(Island island) { updateIslandSettingsValue(island, "bank_limit", island.getBankLimit() + ""); } public static void saveBonusWorth(Island island) { updateIslandValue(island, "worth_bonus", island.getBonusWorth() + ""); } public static void saveBonusLevel(Island island) { updateIslandValue(island, "levels_bonus", island.getBonusLevel() + ""); } public static void saveUpgrade(Island island, Upgrade upgrade, int level) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_upgrades", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("upgrade", upgrade.getName()), pool.obtain().withNameAndValue("level", level) ); } }); } public static void saveCropGrowth(Island island) { updateIslandSettingsValue(island, "crop_growth_multiplier", island.getCropGrowthMultiplier()); } public static void saveSpawnerRates(Island island) { updateIslandSettingsValue(island, "spawner_rates_multiplier", island.getSpawnerRatesMultiplier()); } public static void saveMobDrops(Island island) { updateIslandSettingsValue(island, "mob_drops_multiplier", island.getMobDropsMultiplier()); } public static void saveBlockLimit(Island island, Key block, int limit) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_block_limits", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("block", block.toString()), pool.obtain().withNameAndValue("limit", limit) ); } }); } public static void clearBlockLimits(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_block_limits", createFilter("island", island))); } public static void removeBlockLimit(Island island, Key block) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("block", block.toString()); databaseBridge.deleteObject("islands_block_limits", createFilter(pool, "island", island, column)); } }); } public static void saveEntityLimit(Island island, Key entityType, int limit) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_entity_limits", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("entity", entityType.toString()), pool.obtain().withNameAndValue("limit", limit) ); } }); } public static void clearEntityLimits(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_entity_limits", createFilter("island", island))); } public static void removeEntityLimit(Island island, Key entity) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("entity", entity.toString()); databaseBridge.deleteObject("islands_entity_limits", createFilter(pool, "island", island, column)); } }); } public static void saveTeamLimit(Island island) { updateIslandSettingsValue(island, "members_limit", island.getTeamLimit()); } public static void saveWarpsLimit(Island island) { updateIslandSettingsValue(island, "warps_limit", island.getWarpsLimit()); } public static void saveIslandEffect(Island island, PotionEffectType potionEffectType, int level) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_effects", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("effect_type", potionEffectType.getName()), pool.obtain().withNameAndValue("level", level) ); } }); } public static void removeIslandEffect(Island island, PotionEffectType potionEffectType) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("effect_type", potionEffectType.getName()); databaseBridge.deleteObject("islands_effects", createFilter(pool, "island", island, column)); } }); } public static void clearIslandEffects(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_effects", createFilter("island", island))); } public static void saveRoleLimit(Island island, PlayerRole playerRole, int limit) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_role_limits", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("role", playerRole.getId()), pool.obtain().withNameAndValue("limit", limit) ); } }); } public static void removeRoleLimit(Island island, PlayerRole playerRole) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("role", playerRole.getId()); databaseBridge.deleteObject("islands_role_limits", createFilter(pool, "island", island, column)); } }); } public static void saveWarp(Island island, IslandWarp islandWarp) { WarpCategory category = islandWarp.getCategory(); ItemStack icon = islandWarp.getRawIcon(); runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain(); ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { databaseBridge.insertObject("islands_warps", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("name", islandWarp.getName()), pool.obtain().withNameAndValue("category", category == null ? "" : category.getName()), pool.obtain().withNameAndValue("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()))), pool.obtain().withNameAndValue("private", islandWarp.hasPrivateFlag()), pool.obtain().withNameAndValue("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) ); } }); } public static void updateWarpName(Island island, IslandWarp islandWarp, String oldName) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_warps", createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", oldName)), pool.obtain().withNameAndValue("name", islandWarp.getName()) ); } }); } public static void updateWarpLocation(Island island, IslandWarp islandWarp) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain(); ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { String islandWarpLocation = Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle())); databaseBridge.updateObject("islands_warps", createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", islandWarp.getName())), pool.obtain().withNameAndValue("location", islandWarpLocation) ); } }); } public static void updateWarpPrivateStatus(Island island, IslandWarp islandWarp) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_warps", createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", islandWarp.getName())), pool.obtain().withNameAndValue("private", islandWarp.hasPrivateFlag()) ); } }); } public static void updateWarpIcon(Island island, IslandWarp islandWarp) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { ItemStack icon = islandWarp.getRawIcon(); try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_warps", createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", islandWarp.getName())), pool.obtain().withNameAndValue("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) ); } }); } public static void removeWarp(Island island, IslandWarp islandWarp) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("name", islandWarp.getName()); databaseBridge.deleteObject("islands_warps", createFilter(pool, "island", island, column)); } }); } public static void saveRating(Island island, SuperiorPlayer superiorPlayer, Rating rating, long rateTime) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_ratings", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), pool.obtain().withNameAndValue("rating", rating.getValue()), pool.obtain().withNameAndValue("rating_time", rateTime) ); } }); } public static void removeRating(Island island, SuperiorPlayer superiorPlayer) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()); databaseBridge.deleteObject("islands_ratings", createFilter(pool, "island", island, column)); } }); } public static void clearRatings(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_ratings", createFilter("island", island))); } public static void saveMission(Island island, Mission mission, int finishCount) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_missions", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("name", mission.getName().toLowerCase(Locale.ENGLISH)), pool.obtain().withNameAndValue("finish_count", finishCount) ); } }); } public static void removeMission(Island island, Mission mission) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("name", mission.getName()); databaseBridge.deleteObject("islands_missions", createFilter(pool, "island", island, column)); } }); } public static void saveIslandFlag(Island island, IslandFlag islandFlag, int status) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_flags", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("name", islandFlag.getName()), pool.obtain().withNameAndValue("status", status) ); } }); } public static void removeIslandFlag(Island island, IslandFlag islandFlag) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("name", islandFlag.getName()); databaseBridge.deleteObject("islands_flags", createFilter(pool, "island", island, column)); } }); } public static void clearIslandFlags(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_flags", createFilter("island", island))); } public static void saveGeneratorRate(Island island, Dimension dimension, Key blockKey, int rate) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_generators", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("environment", dimension.getName()), pool.obtain().withNameAndValue("block", blockKey.toString()), pool.obtain().withNameAndValue("rate", rate) ); } }); } public static void removeGeneratorRate(Island island, Dimension dimension, Key blockKey) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.deleteObject("islands_generators", createFilter(pool, "island", island, pool.obtain().withNameAndValue("environment", dimension.getName()), pool.obtain().withNameAndValue("block", blockKey.toString())) ); } }); } public static void clearGeneratorRates(Island island, Dimension dimension) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("environment", dimension.getName()); databaseBridge.deleteObject("islands_generators", createFilter(pool, "island", island, column)); } }); } public static void saveGeneratedSchematics(Island island) { updateIslandValue(island, "generated_schematics", IslandsSerializer.serializeDimensions(island.getGeneratedSchematics())); } public static void saveDirtyChunks(DirtyChunksContainer dirtyChunksContainer) { updateIslandValue(dirtyChunksContainer.getIsland(), "dirty_chunks", IslandsSerializer.serializeDirtyChunkPositions(dirtyChunksContainer)); } public static void saveBlockCounts(Island island) { updateIslandValue(island, "block_counts", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())); } public static void saveEntityCounts(Island island) { updateIslandValue(island, "entity_counts", IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts())); } public static void saveIslandChest(Island island, IslandChest islandChest) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_chests", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("index", islandChest.getIndex()), pool.obtain().withNameAndValue("contents", Serializers.INVENTORY_SERIALIZER.serialize(islandChest.getContents())) ); } }); } public static void saveLastInterestTime(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue("last_interest_time", island.getLastInterestTime() * 1000); databaseBridge.updateObject("islands_banks", createFilter("island", island), column); } }); } public static void saveVisitor(Island island, SuperiorPlayer visitor, long visitTime) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_visitors", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("player", visitor.getUniqueId().toString()), pool.obtain().withNameAndValue("visit_time", visitTime) ); } }); } public static void saveWarpCategory(Island island, WarpCategory warpCategory) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_warp_categories", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("name", warpCategory.getName()), pool.obtain().withNameAndValue("slot", warpCategory.getSlot()), pool.obtain().withNameAndValue("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(warpCategory.getRawIcon())) ); } }); } public static void updateWarpCategory(Island island, IslandWarp islandWarp, String oldCategoryName) { WarpCategory category = islandWarp.getCategory(); runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_warps", createFilter(pool, "island", island, pool.obtain().withNameAndValue("category", oldCategoryName)), pool.obtain().withNameAndValue("category", category == null ? "" : category.getName()) ); } }); } public static void updateWarpCategoryName(Island island, WarpCategory warpCategory, String oldName) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_warp_categories", createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", oldName)), pool.obtain().withNameAndValue("name", warpCategory.getName()) ); } }); } public static void updateWarpCategorySlot(Island island, WarpCategory warpCategory) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_warp_categories", createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", warpCategory.getName())), pool.obtain().withNameAndValue("slot", warpCategory.getSlot()) ); } }); } public static void updateWarpCategoryIcon(Island island, WarpCategory warpCategory) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_warp_categories", createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", warpCategory.getName())), pool.obtain().withNameAndValue("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(warpCategory.getRawIcon())) ); } }); } public static void removeWarpCategory(Island island, WarpCategory warpCategory) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("name", warpCategory.getName()); databaseBridge.deleteObject("islands_warp_categories", createFilter(pool, "island", island, column)); } }); } public static void saveIslandLeader(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue("owner", island.getOwner().getUniqueId().toString()); databaseBridge.updateObject("islands", createFilter("uuid", island), column); } }); } public static void saveBankBalance(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue("balance", island.getIslandBank().getBalance() + ""); databaseBridge.updateObject("islands_banks", createFilter("island", island), column); } }); } public static void saveBankTransaction(Island island, BankTransaction bankTransaction) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("bank_transactions", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("player", bankTransaction.getPlayer() == null ? "" : bankTransaction.getPlayer().toString()), pool.obtain().withNameAndValue("bank_action", bankTransaction.getAction().name()), pool.obtain().withNameAndValue("position", bankTransaction.getPosition()), pool.obtain().withNameAndValue("time", bankTransaction.getTime()), pool.obtain().withNameAndValue("failure_reason", bankTransaction.getFailureReason()), pool.obtain().withNameAndValue("amount", bankTransaction.getAmount() + "") ); } }); } public static void savePersistentDataContainer(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_custom_data", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("data", island.getPersistentDataContainer().serialize()) ); } }); } public static void removePersistentDataContainer(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_custom_data", createFilter("island", island))); } public static void clearIslandSettings(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_settings", createFilter("island", island), pool.obtain().withNameAndValue("size", IslandUpgradeConstants.SYNCED_VALUE), pool.obtain().withNameAndValue("bank_limit", IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE.toString()), pool.obtain().withNameAndValue("coops_limit", IslandUpgradeConstants.SYNCED_VALUE), pool.obtain().withNameAndValue("members_limit", IslandUpgradeConstants.SYNCED_VALUE), pool.obtain().withNameAndValue("warps_limit", IslandUpgradeConstants.SYNCED_VALUE), pool.obtain().withNameAndValue("crop_growth_multiplier", IslandUpgradeConstants.SYNCED_VALUE), pool.obtain().withNameAndValue("spawner_rates_multiplier", IslandUpgradeConstants.SYNCED_VALUE), pool.obtain().withNameAndValue("mob_drops_multiplier", IslandUpgradeConstants.SYNCED_VALUE) ); } }); } public static void insertIsland(Island island, @Nullable List dirtyChunks) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { BlockPosition centerPosition = island.getCenterPosition(); WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands", pool.obtain().withNameAndValue("uuid", island.getUniqueId().toString()), pool.obtain().withNameAndValue("owner", island.getOwner().getUniqueId().toString()), pool.obtain().withNameAndValue("center", Serializers.LOCATION_SERIALIZER.serialize(LazyWorldLocation.of(worldInfo, centerPosition))), pool.obtain().withNameAndValue("creation_time", island.getCreationTime()), pool.obtain().withNameAndValue("island_type", island.getSchematicName()), pool.obtain().withNameAndValue("discord", island.getDiscord()), pool.obtain().withNameAndValue("paypal", island.getPaypal()), pool.obtain().withNameAndValue("worth_bonus", island.getBonusWorth() + ""), pool.obtain().withNameAndValue("levels_bonus", island.getBonusLevel() + ""), pool.obtain().withNameAndValue("locked", island.isLocked()), pool.obtain().withNameAndValue("ignored", island.isIgnored()), pool.obtain().withNameAndValue("name", IslandNames.getNameForDatabase(island)), pool.obtain().withNameAndValue("description", island.getDescription()), pool.obtain().withNameAndValue("generated_schematics", IslandsSerializer.serializeDimensions(island.getGeneratedSchematics())), pool.obtain().withNameAndValue("unlocked_worlds", IslandsSerializer.serializeDimensions(island.getUnlockedWorlds())), pool.obtain().withNameAndValue("last_time_updated", System.currentTimeMillis() / 1000L), pool.obtain().withNameAndValue("dirty_chunks", dirtyChunks == null ? "" : IslandsSerializer.serializeDirtyChunkPositions(dirtyChunks)), pool.obtain().withNameAndValue("block_counts", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())), pool.obtain().withNameAndValue("entity_counts", IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts())) ); } }); insertIslandBanks(island); insertIslandSettings(island); } public static void insertIslandBanks(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_banks", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("balance", island.getIslandBank().getBalance() + ""), pool.obtain().withNameAndValue("last_interest_time", island.getLastInterestTime()) ); } }); } public static void insertIslandSettings(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands_settings", pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), pool.obtain().withNameAndValue("size", island.getIslandSizeRaw()), pool.obtain().withNameAndValue("bank_limit", island.getBankLimitRaw() + ""), pool.obtain().withNameAndValue("coops_limit", island.getCoopLimitRaw()), pool.obtain().withNameAndValue("members_limit", island.getTeamLimitRaw()), pool.obtain().withNameAndValue("warps_limit", island.getWarpsLimitRaw()), pool.obtain().withNameAndValue("crop_growth_multiplier", island.getCropGrowthRaw()), pool.obtain().withNameAndValue("spawner_rates_multiplier", island.getSpawnerRatesRaw()), pool.obtain().withNameAndValue("mob_drops_multiplier", island.getMobDropsRaw()) ); } }); } public static void deleteIsland(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { DatabaseFilter islandFilter = createFilter("island", island); databaseBridge.deleteObject("islands", createFilter("uuid", island)); databaseBridge.deleteObject("islands_banks", islandFilter); databaseBridge.deleteObject("islands_settings", islandFilter); databaseBridge.deleteObject("bank_transactions", islandFilter); if (!island.getBannedPlayers().isEmpty()) databaseBridge.deleteObject("islands_bans", islandFilter); if (!island.getBlocksLimits().isEmpty()) databaseBridge.deleteObject("islands_block_limits", islandFilter); if (!island.isPersistentDataContainerEmpty()) databaseBridge.deleteObject("islands_custom_data", islandFilter); if (island.getChest().length > 0) databaseBridge.deleteObject("islands_chests", islandFilter); if (!island.getPotionEffects().isEmpty()) databaseBridge.deleteObject("islands_effects", islandFilter); if (!island.getEntitiesLimitsAsKeys().isEmpty()) databaseBridge.deleteObject("islands_entity_limits", islandFilter); if (!island.getAllSettings().isEmpty()) databaseBridge.deleteObject("islands_flags", islandFilter); for (Dimension dimension : Dimension.values()) { if (!island.getCustomGeneratorAmounts(dimension).isEmpty()) { databaseBridge.deleteObject("islands_generators", islandFilter); break; } } if (!island.getIslandHomes().isEmpty()) databaseBridge.deleteObject("islands_homes", islandFilter); if (!island.getIslandMembers(false).isEmpty()) databaseBridge.deleteObject("islands_members", islandFilter); if (!island.getCompletedMissions().isEmpty()) databaseBridge.deleteObject("islands_missions", islandFilter); if (!island.getPlayerPermissions().isEmpty()) databaseBridge.deleteObject("islands_player_permissions", islandFilter); if (!island.getRatings().isEmpty()) databaseBridge.deleteObject("islands_ratings", islandFilter); if (!island.getCustomRoleLimits().isEmpty()) databaseBridge.deleteObject("islands_role_limits", islandFilter); if (!island.getRolePermissions().isEmpty()) databaseBridge.deleteObject("islands_role_permissions", islandFilter); if (!island.getUpgrades().isEmpty()) databaseBridge.deleteObject("islands_upgrades", islandFilter); for (Dimension dimension : Dimension.values()) { if (island.getVisitorsPosition(dimension) != null) { databaseBridge.deleteObject("islands_visitor_homes", islandFilter); break; } } if (!island.getUniqueVisitors().isEmpty()) databaseBridge.deleteObject("islands_visitors", islandFilter); if (!island.getWarpCategories().isEmpty()) { databaseBridge.deleteObject("islands_warp_categories", islandFilter); databaseBridge.deleteObject("islands_warps", islandFilter); } }); } public static void markIslandChestsToBeSaved(Island island, IslandChest islandChest) { SAVE_METHODS_TO_BE_EXECUTED.computeIfAbsent(island.getUniqueId(), u -> new EnumMap<>(FutureSave.class)) .computeIfAbsent(FutureSave.ISLAND_CHESTS, e -> new HashSet<>()) .add(islandChest); } public static void markBlockCountsToBeSaved(Island island) { Set varsForBlockCounts = SAVE_METHODS_TO_BE_EXECUTED.computeIfAbsent(island.getUniqueId(), u -> new EnumMap<>(FutureSave.class)) .computeIfAbsent(FutureSave.BLOCK_COUNTS, e -> new HashSet<>()); if (varsForBlockCounts.isEmpty()) varsForBlockCounts.add(new Object()); } public static void markPersistentDataContainerToBeSaved(Island island) { Set varsForPersistentData = SAVE_METHODS_TO_BE_EXECUTED.computeIfAbsent(island.getUniqueId(), u -> new EnumMap<>(FutureSave.class)) .computeIfAbsent(FutureSave.PERSISTENT_DATA, e -> new HashSet<>()); if (varsForPersistentData.isEmpty()) varsForPersistentData.add(new Object()); } public static boolean isModified(Island island) { return SAVE_METHODS_TO_BE_EXECUTED.containsKey(island.getUniqueId()); } public static void executeFutureSaves(Island island) { Map> futureSaves = SAVE_METHODS_TO_BE_EXECUTED.remove(island.getUniqueId()); if (futureSaves != null) { for (Map.Entry> futureSaveEntry : futureSaves.entrySet()) { switch (futureSaveEntry.getKey()) { case BLOCK_COUNTS: saveBlockCounts(island); break; case ISLAND_CHESTS: for (Object islandChest : futureSaveEntry.getValue()) saveIslandChest(island, (IslandChest) islandChest); break; case PERSISTENT_DATA: savePersistentDataContainer(island); break; } } } } public static void executeFutureSaves(Island island, FutureSave futureSave) { Map> futureSaves = SAVE_METHODS_TO_BE_EXECUTED.get(island.getUniqueId()); if (futureSaves == null) return; Set values = futureSaves.remove(futureSave); if (values == null) return; if (futureSaves.isEmpty()) SAVE_METHODS_TO_BE_EXECUTED.remove(island.getUniqueId()); switch (futureSave) { case BLOCK_COUNTS: saveBlockCounts(island); break; case ISLAND_CHESTS: for (Object islandChest : values) saveIslandChest(island, (IslandChest) islandChest); break; case PERSISTENT_DATA: { if (island.isPersistentDataContainerEmpty()) removePersistentDataContainer(island); else savePersistentDataContainer(island); break; } } } private static void updateIslandValue(Island island, String columnName, Object value) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value); databaseBridge.updateObject("islands", createFilter("uuid", island), column); } }); } private static void updateIslandSettingsValue(Island island, String columnName, Object value) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value); databaseBridge.updateObject("islands_settings", createFilter("island", island), column); } }); } private static DatabaseFilter createFilter(String id, Island island) { return DatabaseFilter.fromFilter(id, island.getUniqueId().toString()); } private static DatabaseFilter createFilter(ObjectsPools.Batch pool, String id, Island island, DBColumn column) { List> filters = new LinkedList<>(); filters.add(pool.obtain().withNameAndValue(id, island.getUniqueId().toString())); filters.add(column); return DatabaseFilter.fromFilters(filters); } private static DatabaseFilter createFilter(ObjectsPools.Batch pool, String id, Island island, DBColumn... others) { List> filters = new LinkedList<>(); filters.add(pool.obtain().withNameAndValue(id, island.getUniqueId().toString())); if (others != null && others.length > 0) Collections.addAll(filters, others); return DatabaseFilter.fromFilters(filters); } private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer databaseBridgeConsumer) { if (databaseBridge.getDatabaseBridgeMode() == DatabaseBridgeMode.SAVE_DATA) databaseBridgeConsumer.accept(databaseBridge); } public enum FutureSave { BLOCK_COUNTS, ISLAND_CHESTS, PERSISTENT_DATA } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java ================================================ package com.bgsoftware.superiorskyblock.core.database.bridge; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.DBColumn; import java.util.EnumMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; public class PlayersDatabaseBridge { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Map>> SAVE_METHODS_TO_BE_EXECUTED = new ConcurrentHashMap<>(); private static final LazyReference GLOBAL_PLAYERS_BRIDGE = new LazyReference() { @Override protected DatabaseBridge create() { DatabaseBridge databaseBridge = plugin.getFactory().createDatabaseBridge((SuperiorPlayer) null); databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); return databaseBridge; } }; private PlayersDatabaseBridge() { } public static DatabaseBridge getGlobalPlayersBridge() { return GLOBAL_PLAYERS_BRIDGE.get(); } public static void saveTextureValue(SuperiorPlayer superiorPlayer) { updatePlayerValue(superiorPlayer, "last_used_skin", superiorPlayer.getTextureValue()); } public static void savePlayerName(SuperiorPlayer superiorPlayer) { updatePlayerValue(superiorPlayer, "last_used_name", superiorPlayer.getName()); } public static void saveUserLocale(SuperiorPlayer superiorPlayer) { Locale userLocale = superiorPlayer.getUserLocale(); updatePlayerSettingsValue(superiorPlayer, "language", userLocale.getLanguage() + "-" + userLocale.getCountry()); } public static void saveToggledBorder(SuperiorPlayer superiorPlayer) { updatePlayerSettingsValue(superiorPlayer, "toggled_border", superiorPlayer.hasWorldBorderEnabled()); } public static void saveDisbands(SuperiorPlayer superiorPlayer) { updatePlayerValue(superiorPlayer, "disbands", superiorPlayer.getDisbands()); } public static void saveToggledPanel(SuperiorPlayer superiorPlayer) { updatePlayerSettingsValue(superiorPlayer, "toggled_panel", superiorPlayer.hasToggledPanel()); } public static void saveIslandFly(SuperiorPlayer superiorPlayer) { updatePlayerSettingsValue(superiorPlayer, "island_fly", superiorPlayer.hasIslandFlyEnabled()); } public static void saveBorderColor(SuperiorPlayer superiorPlayer) { updatePlayerSettingsValue(superiorPlayer, "border_color", superiorPlayer.getBorderColor().name()); } public static void saveLastTimeStatus(SuperiorPlayer superiorPlayer) { updatePlayerValue(superiorPlayer, "last_time_updated", superiorPlayer.getLastTimeStatus()); } public static void saveMission(SuperiorPlayer superiorPlayer, Mission mission, int finishCount) { runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("players_missions", pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), pool.obtain().withNameAndValue("name", mission.getName().toLowerCase(Locale.ENGLISH)), pool.obtain().withNameAndValue("finish_count", finishCount) ); } }); } public static void removeMission(SuperiorPlayer superiorPlayer, Mission mission) { runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn column = pool.obtain().withNameAndValue("name", mission.getName().toLowerCase(Locale.ENGLISH)); databaseBridge.deleteObject("players_missions", createFilter(pool, "player", superiorPlayer, column)); } }); } public static void savePersistentDataContainer(SuperiorPlayer superiorPlayer) { runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("players_custom_data", pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), pool.obtain().withNameAndValue("data", superiorPlayer.getPersistentDataContainer().serialize()) ); } }); } public static void removePersistentDataContainer(SuperiorPlayer superiorPlayer) { runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("players_custom_data", createFilter("player", superiorPlayer))); } public static void insertPlayer(SuperiorPlayer superiorPlayer) { runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("players", pool.obtain().withNameAndValue("uuid", superiorPlayer.getUniqueId().toString()), pool.obtain().withNameAndValue("last_used_name", superiorPlayer.getName()), pool.obtain().withNameAndValue("last_used_skin", superiorPlayer.getTextureValue()), pool.obtain().withNameAndValue("disbands", superiorPlayer.getDisbands()), pool.obtain().withNameAndValue("last_time_updated", superiorPlayer.getLastTimeStatus()) ); } }); insertPlayerSettings(superiorPlayer); } public static void insertPlayerSettings(SuperiorPlayer superiorPlayer) { Locale userLocale = superiorPlayer.getUserLocale(); runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("players_settings", pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), pool.obtain().withNameAndValue("language", userLocale.getLanguage() + "-" + userLocale.getCountry()), pool.obtain().withNameAndValue("toggled_panel", superiorPlayer.hasToggledPanel()), pool.obtain().withNameAndValue("border_color", superiorPlayer.getBorderColor().name()), pool.obtain().withNameAndValue("toggled_border", superiorPlayer.hasWorldBorderEnabled()), pool.obtain().withNameAndValue("island_fly", superiorPlayer.hasIslandFlyEnabled()) ); } }); } public static void replacePlayer(SuperiorPlayer originalPlayer, SuperiorPlayer newPlayer) { DatabaseBridge playersReplacer = getGlobalPlayersBridge(); try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { DBColumn uuidColumn = pool.obtain().withNameAndValue("uuid", newPlayer.getUniqueId().toString()); DatabaseFilter uuidFilter = createFilter("uuid", originalPlayer); DBColumn playerColumn = pool.obtain().withNameAndValue("player", newPlayer.getUniqueId().toString()); DatabaseFilter playerFilter = createFilter("player", originalPlayer); // We go through all possible tables (both island and players) and replace the player uuids. playersReplacer.updateObject("players", uuidFilter, uuidColumn); playersReplacer.updateObject("players_settings", playerFilter, playerColumn); playersReplacer.updateObject("bank_transactions", playerFilter, playerColumn); playersReplacer.updateObject("islands_bans", playerFilter, playerColumn); playersReplacer.updateObject("islands_bans", createFilter("banned_by", originalPlayer), pool.obtain().withNameAndValue("banned_by", newPlayer.getUniqueId().toString())); playersReplacer.updateObject("islands_player_permissions", playerFilter, playerColumn); playersReplacer.updateObject("islands_ratings", playerFilter, playerColumn); playersReplacer.updateObject("islands_visitors", playerFilter, playerColumn); if (newPlayer.hasIsland()) { playersReplacer.updateObject("islands", createFilter("owner", originalPlayer), pool.obtain().withNameAndValue("owner", newPlayer.getUniqueId().toString())); playersReplacer.updateObject("islands_members", playerFilter, playerColumn); } if (!newPlayer.isPersistentDataContainerEmpty()) playersReplacer.updateObject("players_custom_data", playerFilter, playerColumn); if (!newPlayer.getCompletedMissions().isEmpty()) playersReplacer.updateObject("players_missions", playerFilter, playerColumn); } } public static void deletePlayer(SuperiorPlayer superiorPlayer) { DatabaseBridge playersReplacer = getGlobalPlayersBridge(); DatabaseFilter uuidFilter = createFilter("uuid", superiorPlayer); DatabaseFilter playerFilter = createFilter("player", superiorPlayer); // We go through all possible tables (both island and players) and delete the player record. playersReplacer.deleteObject("players", uuidFilter); playersReplacer.deleteObject("players_settings", playerFilter); playersReplacer.deleteObject("bank_transactions", playerFilter); playersReplacer.deleteObject("islands_bans", playerFilter); playersReplacer.deleteObject("islands_bans", createFilter("banned_by", superiorPlayer)); playersReplacer.deleteObject("islands_player_permissions", playerFilter); playersReplacer.deleteObject("islands_ratings", playerFilter); playersReplacer.deleteObject("islands_visitors", playerFilter); if (superiorPlayer.hasIsland()) { playersReplacer.deleteObject("islands", createFilter("owner", superiorPlayer)); playersReplacer.deleteObject("islands_members", playerFilter); } if (!superiorPlayer.isPersistentDataContainerEmpty()) playersReplacer.deleteObject("players_custom_data", playerFilter); if (!superiorPlayer.getCompletedMissions().isEmpty()) playersReplacer.deleteObject("players_missions", playerFilter); } public static void markPersistentDataContainerToBeSaved(SuperiorPlayer superiorPlayer) { Set varsForPersistentData = SAVE_METHODS_TO_BE_EXECUTED.computeIfAbsent(superiorPlayer.getUniqueId(), u -> new EnumMap<>(FutureSave.class)) .computeIfAbsent(FutureSave.PERSISTENT_DATA, e -> new HashSet<>()); if (varsForPersistentData.isEmpty()) varsForPersistentData.add(new Object()); } public static boolean isModified(SuperiorPlayer superiorPlayer) { return SAVE_METHODS_TO_BE_EXECUTED.containsKey(superiorPlayer.getUniqueId()); } public static void executeFutureSaves(SuperiorPlayer superiorPlayer) { Map> futureSaves = SAVE_METHODS_TO_BE_EXECUTED.remove(superiorPlayer.getUniqueId()); if (futureSaves != null) { for (Map.Entry> futureSaveEntry : futureSaves.entrySet()) { switch (futureSaveEntry.getKey()) { case PERSISTENT_DATA: { if (superiorPlayer.isPersistentDataContainerEmpty()) removePersistentDataContainer(superiorPlayer); else savePersistentDataContainer(superiorPlayer); break; } } } } } public static void executeFutureSaves(SuperiorPlayer superiorPlayer, FutureSave futureSave) { Map> futureSaves = SAVE_METHODS_TO_BE_EXECUTED.get(superiorPlayer.getUniqueId()); if (futureSaves == null) return; Set values = futureSaves.remove(futureSave); if (values == null) return; if (futureSaves.isEmpty()) SAVE_METHODS_TO_BE_EXECUTED.remove(superiorPlayer.getUniqueId()); switch (futureSave) { case PERSISTENT_DATA: { if (superiorPlayer.isPersistentDataContainerEmpty()) removePersistentDataContainer(superiorPlayer); else savePersistentDataContainer(superiorPlayer); break; } } } private static void updatePlayerValue(SuperiorPlayer superiorPlayer, String columnName, Object value) { runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value); databaseBridge.updateObject("players", createFilter("uuid", superiorPlayer), column); } }); } private static void updatePlayerSettingsValue(SuperiorPlayer superiorPlayer, String columnName, Object value) { runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value); databaseBridge.updateObject("players_settings", createFilter("player", superiorPlayer), column); } }); } private static DatabaseFilter createFilter(String id, SuperiorPlayer superiorPlayer) { return DatabaseFilter.fromFilter(id, superiorPlayer.getUniqueId().toString()); } private static DatabaseFilter createFilter(ObjectsPools.Batch pool, String id, SuperiorPlayer superiorPlayer, DBColumn column) { List> filters = new LinkedList<>(); filters.add(pool.obtain().withNameAndValue(id, superiorPlayer.getUniqueId().toString())); filters.add(column); return DatabaseFilter.fromFilters(filters); } private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer databaseBridgeConsumer) { if (databaseBridge.getDatabaseBridgeMode() == DatabaseBridgeMode.SAVE_DATA) databaseBridgeConsumer.accept(databaseBridge); } public enum FutureSave { PERSISTENT_DATA } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java ================================================ package com.bgsoftware.superiorskyblock.core.database.bridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlock; import java.util.function.Consumer; public class StackedBlocksDatabaseBridge { private StackedBlocksDatabaseBridge() { } public static void saveStackedBlock(StackedBlocksManager stackedBlocks, StackedBlock stackedBlock) { runOperationIfRunning(stackedBlocks.getDatabaseBridge(), databaseBridge -> { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("stacked_blocks", pool.obtain().withNameAndValue("location", Serializers.LOCATION_SPACED_SERIALIZER.serialize(stackedBlock.getLocation())), pool.obtain().withNameAndValue("amount", stackedBlock.getAmount()), pool.obtain().withNameAndValue("block_type", stackedBlock.getBlockKey().toString()) ); } }); } public static void deleteStackedBlock(StackedBlocksManager stackedBlocks, StackedBlock stackedBlock) { runOperationIfRunning(stackedBlocks.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("stacked_blocks", DatabaseFilter.fromFilter("location", Serializers.LOCATION_SPACED_SERIALIZER.serialize(stackedBlock.getLocation())))); } private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer databaseBridgeConsumer) { if (databaseBridge.getDatabaseBridgeMode() == DatabaseBridgeMode.SAVE_DATA) databaseBridgeConsumer.accept(databaseBridge); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/cache/DatabaseCache.java ================================================ package com.bgsoftware.superiorskyblock.core.database.cache; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.function.Supplier; public class DatabaseCache { private final Map> cache = new HashMap<>(); public DatabaseCache() { } public Record computeIfAbsentInfo(UUID uuid, Supplier value) { return cache.computeIfAbsent(uuid, u -> new Record<>(value.get())); } public static class Record { private final Set recordedTables = new HashSet<>(); private final T handle; private Record(T handle) { this.handle = handle; } public T get() { return this.handle; } public void recordTable(String tableName) { this.recordedTables.add(tableName); } public Set getRecordedTables() { return this.recordedTables; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/DatabaseLoader.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; public interface DatabaseLoader { void setState(State state) throws ManagerLoadException; enum State { INITIALIZE, POST_INITIALIZE, PRE_LOAD_DATA, POST_LOAD_DATA, SHUTDOWN } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/MachineStateDatabaseLoader.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import java.util.Collections; import java.util.EnumMap; import java.util.Map; public abstract class MachineStateDatabaseLoader implements DatabaseLoader { private final Map STATE_MACHINE_HANDLES = Collections.unmodifiableMap(new EnumMap(State.class) {{ put(State.INITIALIZE, MachineStateDatabaseLoader.this::handleInitialize); put(State.POST_INITIALIZE, MachineStateDatabaseLoader.this::handlePostInitialize); put(State.PRE_LOAD_DATA, MachineStateDatabaseLoader.this::handlePreLoadData); put(State.POST_LOAD_DATA, MachineStateDatabaseLoader.this::handlePostLoadData); put(State.SHUTDOWN, MachineStateDatabaseLoader.this::handleShutdown); }}); @Override public void setState(State state) throws ManagerLoadException { StateAction action = STATE_MACHINE_HANDLES.get(state); if (action != null) { try { action.run(); } catch (Throwable error) { if (error instanceof ManagerLoadException) throw error; throw new ManagerLoadException(error, ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } } } protected abstract void handleInitialize() throws ManagerLoadException; protected abstract void handlePostInitialize() throws ManagerLoadException; protected abstract void handlePreLoadData() throws ManagerLoadException; protected abstract void handlePostLoadData() throws ManagerLoadException; protected abstract void handleShutdown() throws ManagerLoadException; private interface StateAction { void run() throws ManagerLoadException; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/backup/BackupDatabase.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.backup; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.database.loader.DatabaseLoader; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.io.ZipFiles; import com.bgsoftware.superiorskyblock.core.logging.Log; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class BackupDatabase implements DatabaseLoader { private static final SimpleDateFormat BACKUP_FILE_NAME_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); private static final int MAX_BACKUP_FILES_PER_DAY = 1000; private final SuperiorSkyblockPlugin plugin; public BackupDatabase(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public void setState(State state) throws ManagerLoadException { if (state != State.PRE_LOAD_DATA || !plugin.getSettings().getDatabase().isBackup()) return; File datastoreFolder = new File(plugin.getDataFolder(), "datastore"); if (!datastoreFolder.exists()) return; String currentTime = BACKUP_FILE_NAME_DATE_FORMAT.format(new Date()); File backupFile = getBackupFile(currentTime, 1); if (backupFile == null) throw new ManagerLoadException("Could not create a backup file as file already exists", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); Log.info("Creating a backup file..."); backupFile.getParentFile().mkdirs(); try { ZipFiles.zipFolder(datastoreFolder, backupFile); } catch (IOException error) { backupFile.delete(); throw new ManagerLoadException(error, ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } Log.info("Backup done!"); } @Nullable private File getBackupFile(String time, int attempt) { File file = new File(plugin.getDataFolder(), String.format("backup/%s%s.zip", time, attempt > 1 ? "-" + attempt : "")); if (file.exists()) return attempt >= MAX_BACKUP_FILES_PER_DAY ? null : getBackupFile(time, attempt + 1); return file; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql; import com.bgsoftware.common.databasebridge.sql.query.Column; import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.DatabaseUpgrade_V0; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v1.DatabaseUpgrade_V1; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v2.DatabaseUpgrade_V2; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v3.DatabaseUpgrade_V3; import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.mutable.MutableInt; import java.sql.ResultSet; public class SQLDatabase { private static final Runnable[] DATABASE_UPGRADES = new Runnable[]{ DatabaseUpgrade_V0.INSTANCE, DatabaseUpgrade_V1.INSTANCE, DatabaseUpgrade_V2.INSTANCE, DatabaseUpgrade_V3.INSTANCE }; private SQLDatabase() { } public static void initializeDatabase() { createMetadataTable(); createIslandsTable(); createPlayersTable(); createGridTable(); createBankTransactionsTable(); createStackedBlocksTable(); } public static UpgradeResult upgradeDatabase() { MutableInt databaseVersionMutable = new MutableInt(0); DBSession.select("ssb_metadata", "", new QueryResult() .onSuccess(result -> databaseVersionMutable.set(result.getInt("version"))) .onFail(error -> { })); int databaseVersion = databaseVersionMutable.get(); while (databaseVersion < DATABASE_UPGRADES.length) { DATABASE_UPGRADES[databaseVersion++].run(); } return new UpgradeResult(databaseVersion > databaseVersionMutable.get(), databaseVersion); } public static int getCurrentDatabaseVersion() { return DATABASE_UPGRADES.length; } private static void createMetadataTable() { MutableInt databaseVersion = new MutableInt(0); // We check if "islands" table exists. If not, it's a new database, // therefore the DB version should be latest. Otherwise, 0. DBSession.select("islands", "", new QueryResult() .onFail(error -> databaseVersion.set(getCurrentDatabaseVersion()))); DBSession.createTable("ssb_metadata", new Column("version", "INTEGER DEFAULT " + databaseVersion.get()) ); } private static void createIslandsTable() { DBSession.createTable("islands", new Column("uuid", "UUID PRIMARY KEY"), new Column("owner", "UUID"), new Column("center", "TEXT"), new Column("creation_time", "BIGINT"), new Column("island_type", "TEXT"), new Column("discord", "TEXT"), new Column("paypal", "TEXT"), new Column("worth_bonus", "BIG_DECIMAL"), new Column("levels_bonus", "BIG_DECIMAL"), new Column("locked", "BOOLEAN"), new Column("ignored", "BOOLEAN"), new Column("name", "TEXT"), new Column("description", "TEXT"), new Column("generated_schematics", "INTEGER"), new Column("unlocked_worlds", "INTEGER"), new Column("last_time_updated", "BIGINT"), new Column("dirty_chunks", "LONGTEXT"), new Column("block_counts", "LONGTEXT"), new Column("entity_counts", "LONGTEXT") ); DBSession.createTable("islands_banks", new Column("island", "UUID PRIMARY KEY"), new Column("balance", "BIG_DECIMAL"), new Column("last_interest_time", "BIGINT") ); DBSession.createTable("islands_bans", new Column("island", "UUID"), new Column("player", "UUID"), new Column("banned_by", "UUID"), new Column("banned_time", "BIGINT") ); DBSession.createTable("islands_block_limits", new Column("island", "UUID"), new Column("block", "UNIQUE_TEXT"), new Column("`limit`", "INTEGER") ); DBSession.createTable("islands_chests", new Column("island", "UUID"), new Column("`index`", "INTEGER"), new Column("contents", "LONGBLOB") ); DBSession.createTable("islands_custom_data", new Column("island", "UUID PRIMARY KEY"), new Column("data", "BLOB") ); DBSession.createTable("islands_effects", new Column("island", "UUID"), new Column("effect_type", "UNIQUE_TEXT"), new Column("level", "INTEGER") ); DBSession.createTable("islands_entity_limits", new Column("island", "UUID"), new Column("entity", "UNIQUE_TEXT"), new Column("`limit`", "INTEGER") ); DBSession.createTable("islands_flags", new Column("island", "UUID"), new Column("name", "UNIQUE_TEXT"), new Column("status", "INTEGER") ); DBSession.createTable("islands_generators", new Column("island", "UUID"), new Column("environment", "VARCHAR(7)"), new Column("block", "UNIQUE_TEXT"), new Column("rate", "INTEGER") ); DBSession.createTable("islands_homes", new Column("island", "UUID"), new Column("environment", "VARCHAR(7)"), new Column("location", "TEXT") ); DBSession.createTable("islands_members", new Column("island", "UUID"), new Column("player", "UUID"), new Column("role", "INTEGER"), new Column("join_time", "BIGINT") ); DBSession.createTable("islands_missions", new Column("island", "UUID"), new Column("name", "LONG_UNIQUE_TEXT"), new Column("finish_count", "INTEGER") ); DBSession.createTable("islands_player_permissions", new Column("island", "UUID"), new Column("player", "UUID"), new Column("permission", "UNIQUE_TEXT"), new Column("status", "BOOLEAN") ); DBSession.createTable("islands_ratings", new Column("island", "UUID"), new Column("player", "UUID"), new Column("rating", "INTEGER"), new Column("rating_time", "BIGINT") ); DBSession.createTable("islands_role_limits", new Column("island", "UUID"), new Column("role", "INTEGER"), new Column("`limit`", "INTEGER") ); DBSession.createTable("islands_role_permissions", new Column("island", "UUID"), new Column("role", "INTEGER"), new Column("permission", "UNIQUE_TEXT") ); DBSession.createTable("islands_settings", new Column("island", "UUID PRIMARY KEY"), new Column("size", "INTEGER"), new Column("bank_limit", "BIG_DECIMAL"), new Column("coops_limit", "INTEGER"), new Column("members_limit", "INTEGER"), new Column("warps_limit", "INTEGER"), new Column("crop_growth_multiplier", "DECIMAL"), new Column("spawner_rates_multiplier", "DECIMAL"), new Column("mob_drops_multiplier", "DECIMAL") ); DBSession.createTable("islands_upgrades", new Column("island", "UUID"), new Column("upgrade", "LONG_UNIQUE_TEXT"), new Column("level", "INTEGER") ); DBSession.createTable("islands_visitor_homes", new Column("island", "UUID"), new Column("environment", "VARCHAR(7)"), new Column("location", "TEXT") ); DBSession.createTable("islands_visitors", new Column("island", "UUID"), new Column("player", "UUID"), new Column("visit_time", "BIGINT") ); DBSession.createTable("islands_warp_categories", new Column("island", "UUID"), new Column("name", "LONG_UNIQUE_TEXT"), new Column("slot", "INTEGER"), new Column("icon", "TEXT") ); DBSession.createTable("islands_warps", new Column("island", "UUID"), new Column("name", "LONG_UNIQUE_TEXT"), new Column("category", "TEXT"), new Column("location", "TEXT"), new Column("private", "BOOLEAN"), new Column("icon", "TEXT") ); } private static void createPlayersTable() { DBSession.createTable("players", new Column("uuid", "UUID PRIMARY KEY"), new Column("last_used_name", "TEXT"), new Column("last_used_skin", "TEXT"), new Column("disbands", "INTEGER"), new Column("last_time_updated", "BIGINT") ); DBSession.createTable("players_custom_data", new Column("player", "UUID PRIMARY KEY"), new Column("data", "BLOB") ); DBSession.createTable("players_missions", new Column("player", "UUID"), new Column("name", "LONG_UNIQUE_TEXT"), new Column("finish_count", "INTEGER") ); DBSession.createTable("players_settings", new Column("player", "UUID PRIMARY KEY"), new Column("language", "TEXT"), new Column("toggled_panel", "BOOLEAN"), new Column("border_color", "TEXT"), new Column("toggled_border", "BOOLEAN"), new Column("island_fly", "BOOLEAN") ); } private static void createGridTable() { DBSession.createTable("grid", new Column("last_island", "TEXT"), new Column("max_island_size", "INTEGER"), new Column("world", "TEXT") ); } private static void createBankTransactionsTable() { DBSession.createTable("bank_transactions", new Column("island", "UUID"), new Column("player", "UUID"), new Column("bank_action", "TEXT"), new Column("position", "INTEGER"), new Column("time", "BIGINT"), new Column("failure_reason", "TEXT"), new Column("amount", "TEXT") ); } private static void createStackedBlocksTable() { DBSession.createTable("stacked_blocks", new Column("location", "LONG_UNIQUE_TEXT PRIMARY KEY"), new Column("block_type", "TEXT"), new Column("amount", "INTEGER") ); } public static class UpgradeResult { private final boolean upgraded; private final int databaseVersion; UpgradeResult(boolean upgraded, int databaseVersion) { this.upgraded = upgraded; this.databaseVersion = databaseVersion; } public boolean isUpgraded() { return upgraded; } public int getDatabaseVersion() { return databaseVersion; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabaseLoader.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql; import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.loader.MachineStateDatabaseLoader; import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import java.sql.ResultSet; public class SQLDatabaseLoader extends MachineStateDatabaseLoader { private final SuperiorSkyblockPlugin plugin; public SQLDatabaseLoader(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public void setState(State state) throws ManagerLoadException { if (!plugin.getFactory().hasCustomDatabaseBridge()) super.setState(state); } @Override protected void handleInitialize() throws ManagerLoadException { if (!DBSession.createConnection(plugin)) { throw new ManagerLoadException("Couldn't connect to the database.\nMake sure all information is correct.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } try { DBSession.select("ssb_metadata", "", new QueryResult().onSuccess(resultSet -> { int databaseVersion = resultSet.getInt("version"); if (databaseVersion > SQLDatabase.getCurrentDatabaseVersion()) throw new IllegalStateException("Database is in newer version: " + databaseVersion + " > " + SQLDatabase.getCurrentDatabaseVersion()); }).onFail(error -> { })); } catch (IllegalStateException error) { throw new ManagerLoadException(error.getMessage(), ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } SQLDatabase.UpgradeResult databaseUpgradeResult = SQLDatabase.upgradeDatabase(); SQLDatabase.initializeDatabase(); if (databaseUpgradeResult.isUpgraded()) GridDatabaseBridge.updateVersion(plugin.getGrid(), databaseUpgradeResult.getDatabaseVersion()); DBSession.select("grid", "", new QueryResult() .onFail(error -> GridDatabaseBridge.insertGrid(plugin.getGrid()))); } @Override protected void handlePostInitialize() { DBSession.createIndex("islands_bans_index", "islands_bans", "island", "player"); DBSession.createIndex("block_limits_index", "islands_block_limits", "island", "block"); DBSession.createIndex("islands_chests_index", "islands_chests", "island", "`index`"); DBSession.createIndex("islands_effects_index", "islands_effects", "island", "effect_type"); DBSession.createIndex("entity_limits_index", "islands_entity_limits", "island", "entity"); DBSession.createIndex("islands_flags_index", "islands_flags", "island", "name"); DBSession.createIndex("islands_generators_index", "islands_generators", "island", "environment", "block"); DBSession.createIndex("islands_homes_index", "islands_homes", "island", "environment"); DBSession.createIndex("islands_members_index", "islands_members", "island", "player"); DBSession.createIndex("islands_missions_index", "islands_missions", "island", "name"); DBSession.createIndex("player_permissions_index", "islands_player_permissions", "island", "player", "permission"); DBSession.createIndex("islands_ratings_index", "islands_ratings", "island", "player"); DBSession.createIndex("role_limits_index", "islands_role_limits", "island", "role"); DBSession.createIndex("role_permissions_index", "islands_role_permissions", "island", "permission"); DBSession.createIndex("islands_upgrades_index", "islands_upgrades", "island", "upgrade"); DBSession.createIndex("visitor_homes_index", "islands_visitor_homes", "island", "environment"); DBSession.createIndex("islands_visitors_index", "islands_visitors", "island", "player"); DBSession.createIndex("warp_categories_index", "islands_warp_categories", "island", "name"); DBSession.createIndex("islands_warps_index", "islands_warps", "island", "name"); DBSession.createIndex("players_missions_index", "players_missions", "player", "name"); } @Override protected void handlePreLoadData() { DBSession.setJournalMode("MEMORY", QueryResult.EMPTY_QUERY_RESULT); } @Override protected void handlePostLoadData() { DBSession.setJournalMode("DELETE", QueryResult.EMPTY_QUERY_RESULT); } @Override protected void handleShutdown() { DBSession.close(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0; import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.database.loader.sql.SQLDatabase; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.BankTransactionsAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.GridAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.StackedBlockAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.EmptyParameterGuardDeserializer; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.IDeserializer; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.JsonDeserializer; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.MultipleDeserializer; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.RawDeserializer; import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import org.bukkit.World; import org.bukkit.potion.PotionEffectType; import java.io.File; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiConsumer; public class DatabaseConverter { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final UUID CONSOLE_UUID = new UUID(0, 0); private static File databaseFile; private static boolean isRemoteDatabase; private static final List loadedPlayers = new ArrayList<>(); private static final List loadedIslands = new ArrayList<>(); private static final List loadedBlocks = new ArrayList<>(); private static final List loadedBankTransactions = new ArrayList<>(); private static final IDeserializer deserializer = new MultipleDeserializer( EmptyParameterGuardDeserializer.getInstance(), JsonDeserializer.INSTANCE, RawDeserializer.INSTANCE ); private static GridAttributes gridAttributes; private DatabaseConverter() { } public static void tryConvertDatabase() { boolean isOldDatabaseFormat = isDatabaseOldFormat(); if (isOldDatabaseFormat) { convertDatabase(); saveConvertedData(); } } private static void convertDatabase() { Log.info("[Database-Converter] Detected old database - starting to convert data..."); DBSession.select("players", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { loadedPlayers.add(loadPlayer(new ResultSetMapBridge(resultSet))); } }).onFail(QueryResult.PRINT_ERROR)); Log.info("[Database-Converter] Found ", loadedPlayers.size(), " players in the database."); DBSession.select("islands", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { loadedIslands.add(loadIsland(new ResultSetMapBridge(resultSet))); } }).onFail(QueryResult.PRINT_ERROR)); Log.info("[Database-Converter] Found ", loadedIslands.size(), " islands in the database."); DBSession.select("stackedBlocks", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { loadedBlocks.add(loadStackedBlock(new ResultSetMapBridge(resultSet))); } }).onFail(QueryResult.PRINT_ERROR)); Log.info("[Database-Converter] Found ", loadedBlocks.size(), " stacked blocks in the database."); // Ignoring errors as the bankTransactions table may not exist. AtomicBoolean foundBankTransaction = new AtomicBoolean(false); DBSession.select("bankTransactions", "", new QueryResult().onSuccess(resultSet -> { foundBankTransaction.set(true); while (resultSet.next()) { loadedBankTransactions.add(loadBankTransaction(new ResultSetMapBridge(resultSet))); } })); if (foundBankTransaction.get()) { Log.info("[Database-Converter] Found ", loadedBankTransactions.size(), " bank transactions in the database."); } DBSession.select("grid", "", new QueryResult().onSuccess(resultSet -> { if (resultSet.next()) { gridAttributes = new GridAttributes() .setValue(GridAttributes.Field.LAST_ISLAND, resultSet.getString("lastIsland")) .setValue(GridAttributes.Field.MAX_ISLAND_SIZE, resultSet.getString("maxIslandSize")) .setValue(GridAttributes.Field.WORLD, resultSet.getString("world")); } }).onFail(QueryResult.PRINT_ERROR)); MutableObject failedBackupError = new MutableObject<>(null); if (!isRemoteDatabase) { DBSession.close(); if (!databaseFile.renameTo(new File(databaseFile.getParentFile(), "database-bkp.db"))) { failedBackupError.setValue(new RuntimeException("Failed to rename file to database-bkp.db")); } else { DBSession.createConnection(plugin); SQLDatabase.initializeDatabase(); } } if (failedBackupError.getValue() != null) { Log.error(failedBackupError.getValue(), "[Database-Converter] Failed to create a backup for the database file:"); } else { Log.info("[Database-Converter] Successfully created a backup for the database."); } } private static void saveConvertedData() { savePlayers(); saveIslands(); saveStackedBlocks(); saveBankTransactions(); saveGrid(); } private static boolean isDatabaseOldFormat() { isRemoteDatabase = isRemoteDatabase(); if (!isRemoteDatabase) { databaseFile = new File(plugin.getDataFolder(), "datastore/database.db"); if (!databaseFile.exists()) return false; } AtomicBoolean isOldFormat = new AtomicBoolean(true); DBSession.select("stackedBlocks", "", new QueryResult().onFail(error -> { isOldFormat.set(false); })); return isOldFormat.get(); } private static boolean isRemoteDatabase() { switch (plugin.getSettings().getDatabase().getType()) { case "MYSQL": case "MARIADB": case "POSTGRESQL": return true; default: return false; } } private static void savePlayers() { Log.info("[Database-Converter] Converting players..."); CustomSQLDatabaseTransaction playersTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}players VALUES(?,?,?,?,?)"); CustomSQLDatabaseTransaction playersMissionsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}players_missions VALUES(?,?,?)"); CustomSQLDatabaseTransaction playersSettingsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}players_settings VALUES(?,?,?,?,?,?)"); for (PlayerAttributes playerAttributes : loadedPlayers) { insertPlayer(playerAttributes, playersTransaction, playersMissionsTransaction, playersSettingsTransaction); } try { DBSession.execute(playersMissionsTransaction, playersSettingsTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } } private static void saveIslands() { long currentTime = System.currentTimeMillis(); Log.info("[Database-Converter] Converting islands..."); CustomSQLDatabaseTransaction islandsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); CustomSQLDatabaseTransaction islandsBanksTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_banks VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsBansTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_bans VALUES(?,?,?,?)"); CustomSQLDatabaseTransaction islandsBlockLimitsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_block_limits VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsChestsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_chests VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsEffectsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_effects VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsEntityLimitsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_entity_limits VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsFlagsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_flags VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsGeneratorsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_generators VALUES(?,?,?,?)"); CustomSQLDatabaseTransaction islandsHomesTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_homes VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsMembersTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_members VALUES(?,?,?,?)"); CustomSQLDatabaseTransaction islandsMissionsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_missions VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsPlayerPermissionsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_player_permissions VALUES(?,?,?,?)"); CustomSQLDatabaseTransaction islandsRatingsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_ratings VALUES(?,?,?,?)"); CustomSQLDatabaseTransaction islandsRoleLimitsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_role_limits VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsRolePermissionsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_role_permissions VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsSettingsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_settings VALUES(?,?,?,?,?,?,?,?,?)"); CustomSQLDatabaseTransaction islandsUpgradesTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_upgrades VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsVisitorHomesTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_visitor_homes VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsVisitorsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_visitors VALUES(?,?,?)"); CustomSQLDatabaseTransaction islandsWarpCategoriesTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_warp_categories VALUES(?,?,?,?)"); CustomSQLDatabaseTransaction islandsWarpsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}islands_warps VALUES(?,?,?,?,?,?)"); for (IslandAttributes islandAttributes : loadedIslands) { insertIsland(islandAttributes, currentTime, islandsTransaction, islandsBanksTransaction, islandsBansTransaction, islandsBlockLimitsTransaction, islandsChestsTransaction, islandsEffectsTransaction, islandsEntityLimitsTransaction, islandsFlagsTransaction, islandsGeneratorsTransaction, islandsHomesTransaction, islandsMembersTransaction, islandsMissionsTransaction, islandsPlayerPermissionsTransaction, islandsRatingsTransaction, islandsRoleLimitsTransaction, islandsRolePermissionsTransaction, islandsSettingsTransaction, islandsUpgradesTransaction, islandsVisitorHomesTransaction, islandsVisitorsTransaction, islandsWarpCategoriesTransaction, islandsWarpsTransaction); } try { DBSession.execute( islandsTransaction, islandsBanksTransaction, islandsBansTransaction, islandsBlockLimitsTransaction, islandsChestsTransaction, islandsEffectsTransaction, islandsEntityLimitsTransaction, islandsFlagsTransaction, islandsGeneratorsTransaction, islandsHomesTransaction, islandsMembersTransaction, islandsMissionsTransaction, islandsPlayerPermissionsTransaction, islandsRatingsTransaction, islandsRoleLimitsTransaction, islandsRolePermissionsTransaction, islandsSettingsTransaction, islandsUpgradesTransaction, islandsVisitorHomesTransaction, islandsVisitorsTransaction, islandsWarpCategoriesTransaction, islandsWarpsTransaction ).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } } private static void saveStackedBlocks() { Log.info("[Database-Converter] Converting stacked blocks..."); CustomSQLDatabaseTransaction stackedBlocksTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}stacked_blocks VALUES(?,?,?)"); for (StackedBlockAttributes stackedBlockAttributes : loadedBlocks) { stackedBlocksTransaction .bindObject(stackedBlockAttributes.getValue(StackedBlockAttributes.Field.LOCATION)) .bindObject(stackedBlockAttributes.getValue(StackedBlockAttributes.Field.BLOCK_TYPE)) .bindObject(stackedBlockAttributes.getValue(StackedBlockAttributes.Field.AMOUNT)) .newBatch(); } try { DBSession.execute(stackedBlocksTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } } private static void saveBankTransactions() { Log.info("[Database-Converter] Converting bank transactions..."); CustomSQLDatabaseTransaction bankTransactionsTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}bank_transactions VALUES(?,?,?,?,?,?,?)"); for (BankTransactionsAttributes bankTransactionsAttributes : loadedBankTransactions) { bankTransactionsTransaction .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.ISLAND)) .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.PLAYER)) .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.BANK_ACTION)) .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.POSITION)) .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.TIME)) .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.FAILURE_REASON)) .bindObject(bankTransactionsAttributes.getValue(BankTransactionsAttributes.Field.AMOUNT)) .newBatch(); } try { DBSession.execute(bankTransactionsTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } } private static void saveGrid() { if (gridAttributes == null) return; Log.info("[Database-Converter] Converting grid data..."); CustomSQLDatabaseTransaction deleteGridTransaction = new CustomSQLDatabaseTransaction("DELETE FROM {prefix}grid;"); try { DBSession.execute(deleteGridTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } CustomSQLDatabaseTransaction insertGridTransaction = new CustomSQLDatabaseTransaction( "REPLACE INTO {prefix}grid VALUES(?,?,?)"); insertGridTransaction .bindObject(gridAttributes.getValue(GridAttributes.Field.LAST_ISLAND)) .bindObject(gridAttributes.getValue(GridAttributes.Field.MAX_ISLAND_SIZE)) .bindObject(gridAttributes.getValue(GridAttributes.Field.WORLD)); try { DBSession.execute(insertGridTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } } @SuppressWarnings("unchecked") private static void insertPlayer(PlayerAttributes playerAttributes, CustomSQLDatabaseTransaction playersTransaction, CustomSQLDatabaseTransaction playersMissionsTransaction, CustomSQLDatabaseTransaction playersSettingsTransaction) { String playerUUID = playerAttributes.getValue(PlayerAttributes.Field.UUID); playersTransaction.bindObject(playerUUID) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.LAST_USED_NAME)) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.LAST_USED_SKIN)) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.DISBANDS)) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.LAST_TIME_UPDATED)) .newBatch(); ((Map) playerAttributes.getValue(PlayerAttributes.Field.COMPLETED_MISSIONS)).forEach((missionName, finishCount) -> playersMissionsTransaction.bindObject(playerUUID) .bindObject(missionName.toLowerCase(Locale.ENGLISH)) .bindObject(finishCount) .newBatch()); playersSettingsTransaction.bindObject(playerUUID) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.LANGUAGE)) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.TOGGLED_PANEL)) .bindObject(((BorderColor) playerAttributes.getValue(PlayerAttributes.Field.BORDER_COLOR)).name()) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.TOGGLED_BORDER)) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.ISLAND_FLY)) .newBatch(); } @SuppressWarnings({"unchecked"}) private static void insertIsland(IslandAttributes islandAttributes, long currentTime, CustomSQLDatabaseTransaction islandsTransaction, CustomSQLDatabaseTransaction islandsBanksTransaction, CustomSQLDatabaseTransaction islandsBansTransaction, CustomSQLDatabaseTransaction islandsBlockLimitsTransaction, CustomSQLDatabaseTransaction islandsChestsTransaction, CustomSQLDatabaseTransaction islandsEffectsTransaction, CustomSQLDatabaseTransaction islandsEntityLimitsTransaction, CustomSQLDatabaseTransaction islandsFlagsTransaction, CustomSQLDatabaseTransaction islandsGeneratorsTransaction, CustomSQLDatabaseTransaction islandsHomesTransaction, CustomSQLDatabaseTransaction islandsMembersTransaction, CustomSQLDatabaseTransaction islandsMissionsTransaction, CustomSQLDatabaseTransaction islandsPlayerPermissionsTransaction, CustomSQLDatabaseTransaction islandsRatingsTransaction, CustomSQLDatabaseTransaction islandsRoleLimitsTransaction, CustomSQLDatabaseTransaction islandsRolePermissionsTransaction, CustomSQLDatabaseTransaction islandsSettingsTransaction, CustomSQLDatabaseTransaction islandsUpgradesTransaction, CustomSQLDatabaseTransaction islandsVisitorHomesTransaction, CustomSQLDatabaseTransaction islandsVisitorsTransaction, CustomSQLDatabaseTransaction islandsWarpCategoriesTransaction, CustomSQLDatabaseTransaction islandsWarpsTransaction) { String islandUUID = islandAttributes.getValue(IslandAttributes.Field.UUID); islandsTransaction.bindObject(islandUUID) .bindObject(islandAttributes.getValue(IslandAttributes.Field.OWNER)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.CENTER)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.CREATION_TIME)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.ISLAND_TYPE)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.DISCORD)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.PAYPAL)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.WORTH_BONUS)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.LEVELS_BONUS)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.LOCKED)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.IGNORED)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.NAME)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.DESCRIPTION)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.GENERATED_SCHEMATICS)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.UNLOCKED_WORLDS)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.LAST_TIME_UPDATED)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.DIRTY_CHUNKS)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.BLOCK_COUNTS)) .newBatch(); islandsBanksTransaction.bindObject(islandUUID) .bindObject(islandAttributes.getValue(IslandAttributes.Field.BANK_BALANCE)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.BANK_LAST_INTEREST)) .newBatch(); ((List) islandAttributes.getValue(IslandAttributes.Field.BANS)).forEach(playerAttributes -> islandsBansTransaction.bindObject(islandUUID) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.UUID)) .bindObject(CONSOLE_UUID.toString()) .bindObject(currentTime) .newBatch()); ((KeyMap) islandAttributes.getValue(IslandAttributes.Field.BLOCK_LIMITS)).forEach((key, limit) -> islandsBlockLimitsTransaction.bindObject(islandUUID) .bindObject(key.toString()) .bindObject(limit) .newBatch()); ((List) islandAttributes.getValue(IslandAttributes.Field.ISLAND_CHESTS)).forEach(islandChestAttributes -> islandsChestsTransaction.bindObject(islandUUID) .bindObject(islandChestAttributes.getValue(IslandChestAttributes.Field.INDEX)) .bindObject(islandChestAttributes.getValue(IslandChestAttributes.Field.CONTENTS)) .newBatch()); ((Map) islandAttributes.getValue(IslandAttributes.Field.EFFECTS)).forEach((type, level) -> islandsEffectsTransaction.bindObject(islandUUID) .bindObject(type.getName()) .bindObject(level) .newBatch()); ((KeyMap) islandAttributes.getValue(IslandAttributes.Field.ENTITY_LIMITS)).forEach((entity, limit) -> islandsEntityLimitsTransaction.bindObject(islandUUID) .bindObject(entity.toString()) .bindObject(limit) .newBatch()); ((Map) islandAttributes.getValue(IslandAttributes.Field.ISLAND_FLAGS)).forEach((islandFlag, status) -> islandsFlagsTransaction.bindObject(islandUUID) .bindObject(islandFlag.getName()) .bindObject(status) .newBatch()); runOnEnvironments((KeyMap[]) islandAttributes.getValue(IslandAttributes.Field.GENERATORS), (generatorRates, environment) -> generatorRates.forEach((block, rate) -> islandsGeneratorsTransaction.bindObject(islandUUID) .bindObject(environment.name()) .bindObject(block.toString()) .bindObject(rate) .newBatch())); runOnEnvironments((String[]) islandAttributes.getValue(IslandAttributes.Field.HOMES), (islandHome, environment) -> islandsHomesTransaction.bindObject(islandUUID) .bindObject(environment.name()) .bindObject(islandHome) .newBatch()); ((List) islandAttributes.getValue(IslandAttributes.Field.MEMBERS)).forEach(playerAttributes -> islandsMembersTransaction.bindObject(islandUUID) .bindObject(playerAttributes.getValue(PlayerAttributes.Field.UUID)) .bindObject(((PlayerRole) playerAttributes.getValue(PlayerAttributes.Field.ISLAND_ROLE)).getId()) .bindObject(currentTime) .newBatch()); ((Map) islandAttributes.getValue(IslandAttributes.Field.MISSIONS)).forEach((mission, finishCount) -> islandsMissionsTransaction.bindObject(islandUUID) .bindObject(mission) .bindObject(finishCount) .newBatch()); ((Map) islandAttributes.getValue(IslandAttributes.Field.PLAYER_PERMISSIONS)).forEach((playerUUID, node) -> { for (Map.Entry playerPermission : node.getCustomPermissions().entrySet()) islandsPlayerPermissionsTransaction.bindObject(islandUUID) .bindObject(playerUUID.toString()) .bindObject(playerPermission.getKey().getName()) .bindObject(playerPermission.getValue()) .newBatch(); }); ((Map) islandAttributes.getValue(IslandAttributes.Field.RATINGS)).forEach((playerUUID, rating) -> islandsRatingsTransaction.bindObject(islandUUID) .bindObject(playerUUID.toString()) .bindObject(rating.getValue()) .bindObject(currentTime) .newBatch()); ((Map) islandAttributes.getValue(IslandAttributes.Field.ROLE_LIMITS)).forEach((role, limit) -> islandsRoleLimitsTransaction.bindObject(islandUUID) .bindObject(role.getId()) .bindObject(limit) .newBatch()); ((Map) islandAttributes.getValue(IslandAttributes.Field.ROLE_PERMISSIONS)).forEach((privilege, role) -> islandsRolePermissionsTransaction.bindObject(islandUUID) .bindObject(role.getId()) .bindObject(privilege.getName()) .newBatch()); islandsSettingsTransaction.bindObject(islandUUID) .bindObject(islandAttributes.getValue(IslandAttributes.Field.ISLAND_SIZE)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.BANK_LIMIT)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.COOP_LIMIT)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.TEAM_LIMIT)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.WARPS_LIMIT)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.CROP_GROWTH_MULTIPLIER)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.SPAWNER_RATES_MULTIPLIER)) .bindObject(islandAttributes.getValue(IslandAttributes.Field.MOB_DROPS_MULTIPLIER)) .newBatch(); ((Map) islandAttributes.getValue(IslandAttributes.Field.UPGRADES)).forEach((upgradeName, level) -> islandsUpgradesTransaction.bindObject(islandUUID) .bindObject(upgradeName) .bindObject(level) .newBatch()); String visitorHome = islandAttributes.getValue(IslandAttributes.Field.VISITOR_HOMES); if (visitorHome != null && !visitorHome.isEmpty()) islandsVisitorHomesTransaction.bindObject(islandUUID) .bindObject(World.Environment.NORMAL.name()) .bindObject(visitorHome) .newBatch(); ((List>) islandAttributes.getValue(IslandAttributes.Field.VISITORS)).forEach(visitor -> islandsVisitorsTransaction.bindObject(islandUUID) .bindObject(visitor.getKey().toString()) .bindObject(visitor.getValue()) .newBatch()); ((List) islandAttributes.getValue(IslandAttributes.Field.WARP_CATEGORIES)).forEach(warpCategoryAttributes -> islandsWarpCategoriesTransaction.bindObject(islandUUID) .bindObject(warpCategoryAttributes.getValue(WarpCategoryAttributes.Field.NAME)) .bindObject(warpCategoryAttributes.getValue(WarpCategoryAttributes.Field.SLOT)) .bindObject(warpCategoryAttributes.getValue(WarpCategoryAttributes.Field.ICON)) .newBatch()); ((List) islandAttributes.getValue(IslandAttributes.Field.WARPS)).forEach(islandWarpAttributes -> islandsWarpsTransaction.bindObject(islandUUID) .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.NAME)) .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.CATEGORY)) .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.LOCATION)) .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.PRIVATE_STATUS)) .bindObject(islandWarpAttributes.getValue(IslandWarpAttributes.Field.ICON)) .newBatch()); } private static void runOnEnvironments(T[] arr, BiConsumer consumer) { for (World.Environment environment : World.Environment.values()) { if (arr[environment.ordinal()] != null) { consumer.accept(arr[environment.ordinal()], environment); } } } private static PlayerAttributes loadPlayer(ResultSetMapBridge resultSet) { PlayerRole playerRole; try { playerRole = SPlayerRole.fromId(Integer.parseInt(resultSet.get("islandRole", "-1"))); } catch (Exception ex) { playerRole = SPlayerRole.of((String) resultSet.get("islandRole")); } long currentTime = System.currentTimeMillis(); return new PlayerAttributes() .setValue(PlayerAttributes.Field.UUID, resultSet.get("player")) .setValue(PlayerAttributes.Field.ISLAND_LEADER, resultSet.get("teamLeader", resultSet.get("player"))) .setValue(PlayerAttributes.Field.LAST_USED_NAME, resultSet.get("name", "null")) .setValue(PlayerAttributes.Field.LAST_USED_SKIN, resultSet.get("textureValue", "")) .setValue(PlayerAttributes.Field.ISLAND_ROLE, playerRole) .setValue(PlayerAttributes.Field.DISBANDS, resultSet.get("disbands", plugin.getSettings().getDisbandCount())) .setValue(PlayerAttributes.Field.LAST_TIME_UPDATED, resultSet.get("lastTimeStatus", currentTime / 1000)) .setValue(PlayerAttributes.Field.COMPLETED_MISSIONS, deserializer.deserializeMissions(resultSet.get("missions", ""))) .setValue(PlayerAttributes.Field.TOGGLED_PANEL, resultSet.get("toggledPanel", plugin.getSettings().isDefaultToggledPanel())) .setValue(PlayerAttributes.Field.ISLAND_FLY, resultSet.get("islandFly", plugin.getSettings().isDefaultIslandFly())) .setValue(PlayerAttributes.Field.BORDER_COLOR, BorderColor.valueOf(resultSet.get("borderColor", plugin.getSettings().getDefaultBorderColor()))) .setValue(PlayerAttributes.Field.LANGUAGE, resultSet.get("language", plugin.getSettings().getDefaultLanguage())) .setValue(PlayerAttributes.Field.TOGGLED_BORDER, resultSet.get("toggledBorder", plugin.getSettings().isDefaultWorldBorder()) ); } private static IslandAttributes loadIsland(ResultSetMapBridge resultSet) { UUID ownerUUID = UUID.fromString((String) resultSet.get("owner")); UUID islandUUID; String uuidRaw = resultSet.get("uuid", null); if (Text.isBlank(uuidRaw)) { islandUUID = ownerUUID; } else { islandUUID = UUID.fromString(uuidRaw); } int generatedSchematics = 0; String generatedSchematicsRaw = resultSet.get("generatedSchematics", "0"); try { generatedSchematics = Integer.parseInt(generatedSchematicsRaw); } catch (Exception ex) { if (generatedSchematicsRaw.contains("normal")) generatedSchematics |= 8; if (generatedSchematicsRaw.contains("nether")) generatedSchematics |= 4; if (generatedSchematicsRaw.contains("the_end")) generatedSchematics |= 3; } int unlockedWorlds = 0; String unlockedWorldsRaw = resultSet.get("unlockedWorlds", "0"); try { unlockedWorlds = Integer.parseInt(unlockedWorldsRaw); } catch (Exception ex) { if (unlockedWorldsRaw.contains("nether")) unlockedWorlds |= 1; if (unlockedWorldsRaw.contains("the_end")) unlockedWorlds |= 2; } long currentTime = System.currentTimeMillis(); return new IslandAttributes() .setValue(IslandAttributes.Field.UUID, islandUUID.toString()) .setValue(IslandAttributes.Field.OWNER, ownerUUID.toString()) .setValue(IslandAttributes.Field.CENTER, (String) resultSet.get("center")) .setValue(IslandAttributes.Field.CREATION_TIME, resultSet.get("creationTime", currentTime / 1000)) .setValue(IslandAttributes.Field.ISLAND_TYPE, resultSet.get("schemName", "")) .setValue(IslandAttributes.Field.DISCORD, resultSet.get("discord", "None")) .setValue(IslandAttributes.Field.PAYPAL, resultSet.get("paypal", "None")) .setValue(IslandAttributes.Field.WORTH_BONUS, resultSet.get("bonusWorth", "")) .setValue(IslandAttributes.Field.LEVELS_BONUS, resultSet.get("bonusLevel", "")) .setValue(IslandAttributes.Field.LOCKED, resultSet.get("locked", false)) .setValue(IslandAttributes.Field.IGNORED, resultSet.get("ignored", false)) .setValue(IslandAttributes.Field.NAME, resultSet.get("name", "")) .setValue(IslandAttributes.Field.DESCRIPTION, resultSet.get("description", "")) .setValue(IslandAttributes.Field.GENERATED_SCHEMATICS, generatedSchematics) .setValue(IslandAttributes.Field.UNLOCKED_WORLDS, unlockedWorlds) .setValue(IslandAttributes.Field.LAST_TIME_UPDATED, resultSet.get("lastTimeUpdate", currentTime / 1000)) .setValue(IslandAttributes.Field.DIRTY_CHUNKS, deserializer.deserializeDirtyChunks(resultSet.get("dirtyChunks", ""))) .setValue(IslandAttributes.Field.BLOCK_COUNTS, deserializer.deserializeBlockCounts(resultSet.get("blockCounts", ""))) .setValue(IslandAttributes.Field.HOMES, deserializer.deserializeHomes(resultSet.get("teleportLocation", ""))) .setValue(IslandAttributes.Field.MEMBERS, deserializer.deserializePlayers(resultSet.get("members", ""))) .setValue(IslandAttributes.Field.BANS, deserializer.deserializePlayers(resultSet.get("banned", ""))) .setValue(IslandAttributes.Field.PLAYER_PERMISSIONS, deserializer.deserializePlayerPerms(resultSet.get("permissionNodes", ""))) .setValue(IslandAttributes.Field.ROLE_PERMISSIONS, deserializer.deserializeRolePerms(resultSet.get("permissionNodes", ""))) .setValue(IslandAttributes.Field.UPGRADES, deserializer.deserializeUpgrades(resultSet.get("upgrades", ""))) .setValue(IslandAttributes.Field.WARPS, deserializer.deserializeWarps(resultSet.get("warps", ""))) .setValue(IslandAttributes.Field.BLOCK_LIMITS, deserializer.deserializeBlockLimits(resultSet.get("blockLimits", ""))) .setValue(IslandAttributes.Field.RATINGS, deserializer.deserializeRatings(resultSet.get("ratings", ""))) .setValue(IslandAttributes.Field.MISSIONS, deserializer.deserializeMissions(resultSet.get("missions", ""))) .setValue(IslandAttributes.Field.ISLAND_FLAGS, deserializer.deserializeIslandFlags(resultSet.get("settings", ""))) .setValue(IslandAttributes.Field.GENERATORS, deserializer.deserializeGenerators(resultSet.get("generator", ""))) .setValue(IslandAttributes.Field.VISITORS, deserializer.deserializeVisitors(resultSet.get("uniqueVisitors", ""))) .setValue(IslandAttributes.Field.ENTITY_LIMITS, deserializer.deserializeEntityLimits(resultSet.get("entityLimits", ""))) .setValue(IslandAttributes.Field.EFFECTS, deserializer.deserializeEffects(resultSet.get("islandEffects", ""))) .setValue(IslandAttributes.Field.ISLAND_CHESTS, deserializer.deserializeIslandChests(resultSet.get("islandChest", ""))) .setValue(IslandAttributes.Field.ROLE_LIMITS, deserializer.deserializeRoleLimits(resultSet.get("roleLimits", ""))) .setValue(IslandAttributes.Field.WARP_CATEGORIES, deserializer.deserializeWarpCategories(resultSet.get("warpCategories", ""))) .setValue(IslandAttributes.Field.BANK_BALANCE, resultSet.get("islandBank", "")) .setValue(IslandAttributes.Field.BANK_LAST_INTEREST, resultSet.get("lastInterest", currentTime / 1000)) .setValue(IslandAttributes.Field.VISITOR_HOMES, resultSet.get("visitorsLocation", "")) .setValue(IslandAttributes.Field.ISLAND_SIZE, resultSet.get("islandSize", IslandUpgradeConstants.SYNCED_VALUE)) .setValue(IslandAttributes.Field.TEAM_LIMIT, resultSet.get("teamLimit", IslandUpgradeConstants.SYNCED_VALUE)) .setValue(IslandAttributes.Field.WARPS_LIMIT, resultSet.get("warpsLimit", IslandUpgradeConstants.SYNCED_VALUE)) .setValue(IslandAttributes.Field.CROP_GROWTH_MULTIPLIER, resultSet.get("cropGrowth", IslandUpgradeConstants.SYNCED_VALUE)) .setValue(IslandAttributes.Field.SPAWNER_RATES_MULTIPLIER, resultSet.get("spawnerRates", IslandUpgradeConstants.SYNCED_VALUE)) .setValue(IslandAttributes.Field.MOB_DROPS_MULTIPLIER, resultSet.get("mobDrops", IslandUpgradeConstants.SYNCED_VALUE)) .setValue(IslandAttributes.Field.COOP_LIMIT, resultSet.get("coopLimit", IslandUpgradeConstants.SYNCED_VALUE)) .setValue(IslandAttributes.Field.BANK_LIMIT, resultSet.get("bankLimit", IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE.toString())); } private static StackedBlockAttributes loadStackedBlock(ResultSetMapBridge resultSet) { String world = (String) resultSet.get("world"); int x = (int) resultSet.get("x"); int y = (int) resultSet.get("y"); int z = (int) resultSet.get("z"); String amount = (String) resultSet.get("amount"); String blockType = (String) resultSet.get("item"); return new StackedBlockAttributes() .setValue(StackedBlockAttributes.Field.LOCATION, world + ", " + x + ", " + y + ", " + z) .setValue(StackedBlockAttributes.Field.BLOCK_TYPE, blockType) .setValue(StackedBlockAttributes.Field.AMOUNT, amount); } private static BankTransactionsAttributes loadBankTransaction(ResultSetMapBridge resultSet) { return new BankTransactionsAttributes() .setValue(BankTransactionsAttributes.Field.ISLAND, resultSet.get("island")) .setValue(BankTransactionsAttributes.Field.PLAYER, resultSet.get("player")) .setValue(BankTransactionsAttributes.Field.BANK_ACTION, resultSet.get("bankAction")) .setValue(BankTransactionsAttributes.Field.POSITION, resultSet.get("position")) .setValue(BankTransactionsAttributes.Field.TIME, resultSet.get("time")) .setValue(BankTransactionsAttributes.Field.FAILURE_REASON, resultSet.get("failureReason")) .setValue(BankTransactionsAttributes.Field.AMOUNT, resultSet.get("amount")); } public static PlayerAttributes getPlayerAttributes(String uuid) { return loadedPlayers.stream().filter(playerAttributes -> playerAttributes.getValue(PlayerAttributes.Field.UUID).equals(uuid)) .findFirst() .orElse(null); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseUpgrade_V0.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0; import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; public class DatabaseUpgrade_V0 implements Runnable { public static final DatabaseUpgrade_V0 INSTANCE = new DatabaseUpgrade_V0(); private DatabaseUpgrade_V0() { } @Override public void run() { upgradeIslandsTables(); upgradePlayersTables(); upgradeStackedBlocksTables(); DatabaseConverter.tryConvertDatabase(); } private void upgradeIslandsTables() { DBSession.modifyColumnType("islands", "dirty_chunks", "LONGTEXT"); DBSession.modifyColumnType("islands", "block_counts", "LONGTEXT"); DBSession.modifyColumnType("islands_chests", "contents", "LONGBLOB"); DBSession.modifyColumnType("islands_missions", "name", "LONG_UNIQUE_TEXT"); // Up to 1.9.0.574, decimals would not be saved correctly in MySQL // This occurred because the field type was DECIMAL(10,0) instead of DECIMAL(10,2) // Updating the column types to "DECIMAL" again should fix the issue. // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1021 DBSession.modifyColumnType("islands_settings", "crop_growth_multiplier", "DECIMAL"); DBSession.modifyColumnType("islands_settings", "spawner_rates_multiplier", "DECIMAL"); DBSession.modifyColumnType("islands_settings", "mob_drops_multiplier", "DECIMAL"); DBSession.modifyColumnType("islands_upgrades", "upgrade", "LONG_UNIQUE_TEXT"); DBSession.removePrimaryKey("islands_upgrades", "island"); DBSession.modifyColumnType("islands_warp_categories", "name", "LONG_UNIQUE_TEXT"); DBSession.modifyColumnType("islands_warps", "name", "LONG_UNIQUE_TEXT"); } private void upgradePlayersTables() { DBSession.modifyColumnType("players_missions", "name", "LONG_UNIQUE_TEXT"); } private void upgradeStackedBlocksTables() { // Before v1.8.1.363, location column of stacked_blocks was limited to 30 chars. // In order to make sure all tables keep the large number, we modify the column to 255-chars long // each time the plugin attempts to create the table. // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/730 DBSession.modifyColumnType("stacked_blocks", "location", "LONG_UNIQUE_TEXT"); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/AttributesRegistry.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; import java.util.EnumMap; public abstract class AttributesRegistry> { private final EnumMap fieldValues; protected AttributesRegistry(Class classType) { fieldValues = new EnumMap<>(classType); } public AttributesRegistry setValue(K field, Object value) { fieldValues.put(field, value); return this; } public T getValue(K field) { Object value = fieldValues.get(field); // noinspection all return (T) value; } public T getValue(K field, Class type) { Object value = fieldValues.get(field); // noinspection all return type.cast(value); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/BankTransactionsAttributes.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; public class BankTransactionsAttributes extends AttributesRegistry { public BankTransactionsAttributes() { super(Field.class); } @Override public BankTransactionsAttributes setValue(Field field, Object value) { return (BankTransactionsAttributes) super.setValue(field, value); } public enum Field { ISLAND, PLAYER, BANK_ACTION, POSITION, TIME, FAILURE_REASON, AMOUNT } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/GridAttributes.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; public class GridAttributes extends AttributesRegistry { public GridAttributes() { super(Field.class); } @Override public GridAttributes setValue(Field field, Object value) { return (GridAttributes) super.setValue(field, value); } public enum Field { LAST_ISLAND, MAX_ISLAND_SIZE, WORLD } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/IslandAttributes.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; public class IslandAttributes extends AttributesRegistry { public IslandAttributes() { super(Field.class); } @Override public IslandAttributes setValue(Field field, Object value) { return (IslandAttributes) super.setValue(field, value); } public enum Field { UUID, OWNER, CENTER, CREATION_TIME, ISLAND_TYPE, DISCORD, PAYPAL, WORTH_BONUS, LEVELS_BONUS, LOCKED, IGNORED, NAME, DESCRIPTION, GENERATED_SCHEMATICS, UNLOCKED_WORLDS, LAST_TIME_UPDATED, DIRTY_CHUNKS, BLOCK_COUNTS, HOMES, MEMBERS, BANS, PLAYER_PERMISSIONS, ROLE_PERMISSIONS, UPGRADES, WARPS, BLOCK_LIMITS, RATINGS, MISSIONS, ISLAND_FLAGS, GENERATORS, VISITORS, ENTITY_LIMITS, EFFECTS, ISLAND_CHESTS, ROLE_LIMITS, WARP_CATEGORIES, BANK_BALANCE, BANK_LAST_INTEREST, VISITOR_HOMES, ISLAND_SIZE, TEAM_LIMIT, WARPS_LIMIT, CROP_GROWTH_MULTIPLIER, SPAWNER_RATES_MULTIPLIER, MOB_DROPS_MULTIPLIER, COOP_LIMIT, BANK_LIMIT } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/IslandChestAttributes.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; public class IslandChestAttributes extends AttributesRegistry { public IslandChestAttributes() { super(Field.class); } @Override public IslandChestAttributes setValue(Field field, Object value) { return (IslandChestAttributes) super.setValue(field, value); } public enum Field { INDEX, CONTENTS } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/IslandWarpAttributes.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; public class IslandWarpAttributes extends AttributesRegistry { public IslandWarpAttributes() { super(Field.class); } @Override public IslandWarpAttributes setValue(Field field, Object value) { return (IslandWarpAttributes) super.setValue(field, value); } public enum Field { NAME, CATEGORY, LOCATION, PRIVATE_STATUS, ICON } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/PlayerAttributes.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; public class PlayerAttributes extends AttributesRegistry { public PlayerAttributes() { super(Field.class); } @Override public PlayerAttributes setValue(Field field, Object value) { return (PlayerAttributes) super.setValue(field, value); } public enum Field { UUID, ISLAND_LEADER, LAST_USED_NAME, LAST_USED_SKIN, ISLAND_ROLE, DISBANDS, LAST_TIME_UPDATED, COMPLETED_MISSIONS, TOGGLED_PANEL, ISLAND_FLY, BORDER_COLOR, LANGUAGE, TOGGLED_BORDER } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/StackedBlockAttributes.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; public class StackedBlockAttributes extends AttributesRegistry { public StackedBlockAttributes() { super(Field.class); } @Override public StackedBlockAttributes setValue(Field field, Object value) { return (StackedBlockAttributes) super.setValue(field, value); } public enum Field { LOCATION, BLOCK_TYPE, AMOUNT } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/attributes/WarpCategoryAttributes.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes; public class WarpCategoryAttributes extends AttributesRegistry { public WarpCategoryAttributes() { super(Field.class); } @Override public WarpCategoryAttributes setValue(Field field, Object value) { return (WarpCategoryAttributes) super.setValue(field, value); } public enum Field { NAME, SLOT, ICON } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/EmptyParameterGuardDeserializer.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import org.bukkit.World; import org.bukkit.potion.PotionEffectType; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Supplier; public class EmptyParameterGuardDeserializer implements IDeserializer { private static final EmptyParameterGuardDeserializer INSTANCE = new EmptyParameterGuardDeserializer(); public static EmptyParameterGuardDeserializer getInstance() { return INSTANCE; } private EmptyParameterGuardDeserializer() { } private static T checkParam(String param, Supplier emptyValue) { if (Text.isBlank(param)) return emptyValue.get(); throw new RuntimeException(); // Will continue to other deserializers } @Override public Map deserializeMissions(String missions) { return checkParam(missions, Collections::emptyMap); } @Override public String[] deserializeHomes(String locationParam) { return checkParam(locationParam, () -> new String[World.Environment.values().length]); } @Override public List deserializePlayers(String players) { return checkParam(players, Collections::emptyList); } @Override public Map deserializePlayerPerms(String permissionNodes) { return checkParam(permissionNodes, Collections::emptyMap); } @Override public Map deserializeRolePerms(String permissionNodes) { return checkParam(permissionNodes, Collections::emptyMap); } @Override public Map deserializeUpgrades(String upgrades) { return checkParam(upgrades, Collections::emptyMap); } @Override public List deserializeWarps(String islandWarps) { return checkParam(islandWarps, Collections::emptyList); } @Override public KeyMap deserializeBlockLimits(String blocks) { return checkParam(blocks, KeyMaps::createEmptyMap); } @Override public Map deserializeRatings(String ratings) { return checkParam(ratings, Collections::emptyMap); } @Override public Map deserializeIslandFlags(String settings) { return checkParam(settings, Collections::emptyMap); } @Override public KeyMap[] deserializeGenerators(String generator) { return checkParam(generator, () -> new KeyMap[World.Environment.values().length]); } @Override public List> deserializeVisitors(String visitors) { return checkParam(visitors, Collections::emptyList); } @Override public KeyMap deserializeEntityLimits(String entities) { return checkParam(entities, KeyMaps::createEmptyMap); } @Override public Map deserializeEffects(String effects) { return checkParam(effects, Collections::emptyMap); } @Override public List deserializeIslandChests(String islandChest) { return checkParam(islandChest, Collections::emptyList); } @Override public Map deserializeRoleLimits(String roles) { return checkParam(roles, Collections::emptyMap); } @Override public List deserializeWarpCategories(String categories) { return checkParam(categories, Collections::emptyList); } @Override public String deserializeBlockCounts(String blockCountsParam) { return checkParam(blockCountsParam, () -> "[]"); } @Override public String deserializeDirtyChunks(String dirtyChunksParam) { return checkParam(dirtyChunksParam, () -> "[]"); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/IDeserializer.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import org.bukkit.potion.PotionEffectType; import java.util.List; import java.util.Map; import java.util.UUID; public interface IDeserializer { Map deserializeMissions(String missions); String[] deserializeHomes(String locationParam); List deserializePlayers(String players); Map deserializePlayerPerms(String permissionNodes); Map deserializeRolePerms(String permissionNodes); Map deserializeUpgrades(String upgrades); List deserializeWarps(String islandWarps); KeyMap deserializeBlockLimits(String blocks); Map deserializeRatings(String ratings); Map deserializeIslandFlags(String settings); KeyMap[] deserializeGenerators(String generator); List> deserializeVisitors(String visitors); KeyMap deserializeEntityLimits(String entities); Map deserializeEffects(String effects); List deserializeIslandChests(String islandChest); Map deserializeRoleLimits(String roles); List deserializeWarpCategories(String categories); String deserializeBlockCounts(String blockCountsParam); String deserializeDirtyChunks(String dirtyChunksParam); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/JsonDeserializer.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.DatabaseConverter; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import org.bukkit.World; import org.bukkit.potion.PotionEffectType; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; public class JsonDeserializer implements IDeserializer { public static final JsonDeserializer INSTANCE = new JsonDeserializer(); private static final Gson gson = new Gson(); private JsonDeserializer() { } public Map deserializeMissions(String missions) { Map completedMissions = new HashMap<>(); JsonArray missionsArray = gson.fromJson(missions, JsonArray.class); missionsArray.forEach(missionElement -> { JsonObject missionObject = missionElement.getAsJsonObject(); String name = missionObject.get("name").getAsString(); int finishCount = missionObject.get("finishCount").getAsInt(); completedMissions.put(name, finishCount); }); return completedMissions; } public String[] deserializeHomes(String locationParam) { String[] locations = new String[World.Environment.values().length]; JsonArray locationsArray = gson.fromJson(locationParam, JsonArray.class); locationsArray.forEach(locationElement -> { JsonObject locationObject = locationElement.getAsJsonObject(); try { int i = World.Environment.valueOf(locationObject.get("env").getAsString()).ordinal(); locations[i] = locationObject.get("location").getAsString(); } catch (Exception ignored) { } }); return locations; } public List deserializePlayers(String players) { List playerAttributes = new LinkedList<>(); JsonArray playersArray = gson.fromJson(players, JsonArray.class); playersArray.forEach(uuid -> { PlayerAttributes _playerAttributes = DatabaseConverter.getPlayerAttributes(uuid.getAsString()); if (_playerAttributes != null) playerAttributes.add(_playerAttributes); }); return Collections.unmodifiableList(playerAttributes); } public Map deserializePlayerPerms(String permissionNodes) { Map playerPermissions = new ArrayMap<>(); JsonObject globalObject = gson.fromJson(permissionNodes, JsonObject.class); JsonArray playersArray = globalObject.getAsJsonArray("players"); playersArray.forEach(playerElement -> { JsonObject playerObject = playerElement.getAsJsonObject(); try { UUID uuid = UUID.fromString(playerObject.get("uuid").getAsString()); JsonArray permsArray = playerObject.getAsJsonArray("permissions"); PlayerPrivilegeNode playerPermissionNode = new PlayerPrivilegeNode(null, null, ""); playerPermissions.put(uuid, playerPermissionNode); for (JsonElement permElement : permsArray) { try { JsonObject permObject = permElement.getAsJsonObject(); IslandPrivilege islandPrivilege = IslandPrivilege.getByName(permObject.get("name").getAsString()); playerPermissionNode.setPermission(islandPrivilege, permObject.get("status").getAsString().equals("1")); } catch (Exception ignored) { } } } catch (Exception ignored) { } }); return playerPermissions; } public Map deserializeRolePerms(String permissionNodes) { Map rolePermissions = new ArrayMap<>(); JsonObject globalObject = gson.fromJson(permissionNodes, JsonObject.class); JsonArray rolesArray = globalObject.getAsJsonArray("roles"); rolesArray.forEach(roleElement -> { JsonObject roleObject = roleElement.getAsJsonObject(); PlayerRole playerRole = SPlayerRole.fromId(roleObject.get("id").getAsInt()); roleObject.getAsJsonArray("permissions").forEach(permElement -> { try { IslandPrivilege islandPrivilege = IslandPrivilege.getByName(permElement.getAsString()); rolePermissions.put(islandPrivilege, playerRole); } catch (Exception ignored) { } }); }); return rolePermissions; } public Map deserializeUpgrades(String upgrades) { Map upgradesMap = new HashMap<>(); JsonArray upgradesArray = gson.fromJson(upgrades, JsonArray.class); upgradesArray.forEach(upgradeElement -> { JsonObject upgradeObject = upgradeElement.getAsJsonObject(); String name = upgradeObject.get("name").getAsString(); int level = upgradeObject.get("level").getAsInt(); upgradesMap.put(name, level); }); return upgradesMap; } public List deserializeWarps(String islandWarps) { List islandWarpList = new LinkedList<>(); JsonArray warpsArray = gson.fromJson(islandWarps, JsonArray.class); warpsArray.forEach(warpElement -> { JsonObject warpObject = warpElement.getAsJsonObject(); String name = warpObject.get("name").getAsString(); String warpCategory = warpObject.get("category").getAsString(); String location = warpObject.get("location").getAsString(); boolean privateWarp = warpObject.get("private").getAsInt() == 1; String icon = warpObject.has("icon") ? warpObject.get("icon").getAsString() : ""; islandWarpList.add(new IslandWarpAttributes() .setValue(IslandWarpAttributes.Field.NAME, name) .setValue(IslandWarpAttributes.Field.CATEGORY, warpCategory) .setValue(IslandWarpAttributes.Field.LOCATION, location) .setValue(IslandWarpAttributes.Field.PRIVATE_STATUS, privateWarp) .setValue(IslandWarpAttributes.Field.ICON, icon)); }); return Collections.unmodifiableList(islandWarpList); } public KeyMap deserializeBlockLimits(String blocks) { KeyMap blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); JsonArray blockLimitsArray = gson.fromJson(blocks, JsonArray.class); blockLimitsArray.forEach(blockLimitElement -> { JsonObject blockLimitObject = blockLimitElement.getAsJsonObject(); Key blockKey = Keys.ofMaterialAndData(blockLimitObject.get("id").getAsString()); int limit = blockLimitObject.get("limit").getAsInt(); blockLimits.put(blockKey, limit); }); return blockLimits; } public Map deserializeRatings(String ratings) { Map ratingsMap = new ArrayMap<>(); JsonArray ratingsArray = gson.fromJson(ratings, JsonArray.class); ratingsArray.forEach(ratingElement -> { JsonObject ratingObject = ratingElement.getAsJsonObject(); try { UUID uuid = UUID.fromString(ratingObject.get("player").getAsString()); Rating rating = Rating.valueOf(ratingObject.get("rating").getAsInt()); ratingsMap.put(uuid, rating); } catch (Exception ignored) { } }); return ratingsMap; } public Map deserializeIslandFlags(String settings) { Map islandFlags = new ArrayMap<>(); JsonArray islandFlagsArray = gson.fromJson(settings, JsonArray.class); islandFlagsArray.forEach(islandFlagElement -> { JsonObject islandFlagObject = islandFlagElement.getAsJsonObject(); try { IslandFlag islandFlag = IslandFlag.getByName(islandFlagObject.get("name").getAsString()); byte status = islandFlagObject.get("status").getAsByte(); islandFlags.put(islandFlag, status); } catch (Exception ignored) { } }); return islandFlags; } public KeyMap[] deserializeGenerators(String generator) { // noinspection all KeyMap[] cobbleGenerator = new KeyMap[World.Environment.values().length]; JsonArray generatorWorldsArray = gson.fromJson(generator, JsonArray.class); generatorWorldsArray.forEach(generatorWorldElement -> { JsonObject generatorWorldObject = generatorWorldElement.getAsJsonObject(); try { int i = World.Environment.valueOf(generatorWorldObject.get("env").getAsString()).ordinal(); generatorWorldObject.getAsJsonArray("rates").forEach(generatorElement -> { JsonObject generatorObject = generatorElement.getAsJsonObject(); Key blockKey = Keys.ofMaterialAndData(generatorObject.get("id").getAsString()); int rate = generatorObject.get("rate").getAsInt(); (cobbleGenerator[i] = KeyMaps.createArrayMap(KeyIndicator.MATERIAL)).put(blockKey, rate); }); } catch (Exception ignored) { } }); return cobbleGenerator; } public List> deserializeVisitors(String visitors) { List> visitorsList = new LinkedList<>(); JsonArray playersArray = gson.fromJson(visitors, JsonArray.class); playersArray.forEach(playerElement -> { JsonObject playerObject = playerElement.getAsJsonObject(); try { UUID uuid = UUID.fromString(playerObject.get("uuid").getAsString()); long lastTimeRecorded = playerObject.get("lastTimeRecorded").getAsLong(); visitorsList.add(new Pair<>(uuid, lastTimeRecorded)); } catch (Exception ignored) { } }); return Collections.unmodifiableList(visitorsList); } public KeyMap deserializeEntityLimits(String entities) { KeyMap entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); JsonArray entityLimitsArray = gson.fromJson(entities, JsonArray.class); entityLimitsArray.forEach(entityLimitElement -> { JsonObject entityLimitObject = entityLimitElement.getAsJsonObject(); Key entity = Keys.ofEntityType(entityLimitObject.get("id").getAsString()); int limit = entityLimitObject.get("limit").getAsInt(); entityLimits.put(entity, limit); }); return entityLimits; } public Map deserializeEffects(String effects) { Map islandEffects = new ArrayMap<>(); JsonArray effectsArray = gson.fromJson(effects, JsonArray.class); effectsArray.forEach(effectElement -> { JsonObject effectObject = effectElement.getAsJsonObject(); PotionEffectType potionEffectType = PotionEffectType.getByName(effectObject.get("type").getAsString()); if (potionEffectType != null) { int level = effectObject.get("level").getAsInt(); islandEffects.put(potionEffectType, level); } }); return islandEffects; } public List deserializeIslandChests(String islandChest) { List islandChestList = new LinkedList<>(); JsonArray islandChestsArray = gson.fromJson(islandChest, JsonArray.class); islandChestsArray.forEach(islandChestElement -> { JsonObject islandChestObject = islandChestElement.getAsJsonObject(); int index = islandChestObject.get("index").getAsInt(); String contents = islandChestObject.get("contents").getAsString(); islandChestList.add(new IslandChestAttributes() .setValue(IslandChestAttributes.Field.INDEX, index) .setValue(IslandChestAttributes.Field.CONTENTS, contents)); }); return Collections.unmodifiableList(islandChestList); } public Map deserializeRoleLimits(String roles) { Map roleLimits = new ArrayMap<>(); JsonArray roleLimitsArray = gson.fromJson(roles, JsonArray.class); roleLimitsArray.forEach(roleElement -> { JsonObject roleObject = roleElement.getAsJsonObject(); PlayerRole playerRole = SPlayerRole.fromId(roleObject.get("id").getAsInt()); if (playerRole != null) { int limit = roleObject.get("limit").getAsInt(); roleLimits.put(playerRole, limit); } }); return roleLimits; } public List deserializeWarpCategories(String categories) { List warpCategories = new LinkedList<>(); JsonArray warpCategoriesArray = gson.fromJson(categories, JsonArray.class); warpCategoriesArray.forEach(warpCategoryElement -> { JsonObject warpCategoryObject = warpCategoryElement.getAsJsonObject(); String name = warpCategoryObject.get("name").getAsString(); int slot = warpCategoryObject.get("slot").getAsInt(); String icon = warpCategoryObject.get("icon").getAsString(); warpCategories.add(new WarpCategoryAttributes() .setValue(WarpCategoryAttributes.Field.NAME, name) .setValue(WarpCategoryAttributes.Field.SLOT, slot) .setValue(WarpCategoryAttributes.Field.ICON, icon)); }); return Collections.unmodifiableList(warpCategories); } @Override public String deserializeBlockCounts(String blockCountsParam) { gson.fromJson(blockCountsParam, JsonArray.class); return blockCountsParam; } @Override public String deserializeDirtyChunks(String dirtyChunksParam) { gson.fromJson(dirtyChunksParam, JsonObject.class); return dirtyChunksParam; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/MultipleDeserializer.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import org.bukkit.potion.PotionEffectType; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Function; public class MultipleDeserializer implements IDeserializer { private final List deserializers; public MultipleDeserializer(IDeserializer... deserializers) { this.deserializers = Arrays.asList(deserializers); } private T runDeserializers(Function function) { for (IDeserializer deserializer : deserializers) { try { return function.apply(deserializer); } catch (Exception ignored) { } } throw new RuntimeException("No valid deserializer found."); } @Override public Map deserializeMissions(String missions) { return runDeserializers(deserializer -> deserializer.deserializeMissions(missions)); } @Override public String[] deserializeHomes(String locationParam) { return runDeserializers(deserializer -> deserializer.deserializeHomes(locationParam)); } @Override public List deserializePlayers(String players) { return runDeserializers(deserializer -> deserializer.deserializePlayers(players)); } @Override public Map deserializePlayerPerms(String permissionNodes) { return runDeserializers(deserializer -> deserializer.deserializePlayerPerms(permissionNodes)); } @Override public Map deserializeRolePerms(String permissionNodes) { return runDeserializers(deserializer -> deserializer.deserializeRolePerms(permissionNodes)); } @Override public Map deserializeUpgrades(String upgrades) { return runDeserializers(deserializer -> deserializer.deserializeUpgrades(upgrades)); } @Override public List deserializeWarps(String islandWarps) { return runDeserializers(deserializer -> deserializer.deserializeWarps(islandWarps)); } @Override public KeyMap deserializeBlockLimits(String blocks) { return runDeserializers(deserializer -> deserializer.deserializeBlockLimits(blocks)); } @Override public Map deserializeRatings(String ratings) { return runDeserializers(deserializer -> deserializer.deserializeRatings(ratings)); } @Override public Map deserializeIslandFlags(String settings) { return runDeserializers(deserializer -> deserializer.deserializeIslandFlags(settings)); } @Override public KeyMap[] deserializeGenerators(String generator) { return runDeserializers(deserializer -> deserializer.deserializeGenerators(generator)); } @Override public List> deserializeVisitors(String visitors) { return runDeserializers(deserializer -> deserializer.deserializeVisitors(visitors)); } @Override public KeyMap deserializeEntityLimits(String entities) { return runDeserializers(deserializer -> deserializer.deserializeEntityLimits(entities)); } @Override public Map deserializeEffects(String effects) { return runDeserializers(deserializer -> deserializer.deserializeEffects(effects)); } @Override public List deserializeIslandChests(String islandChest) { return runDeserializers(deserializer -> deserializer.deserializeIslandChests(islandChest)); } @Override public Map deserializeRoleLimits(String roles) { return runDeserializers(deserializer -> deserializer.deserializeRoleLimits(roles)); } @Override public List deserializeWarpCategories(String categories) { return runDeserializers(deserializer -> deserializer.deserializeWarpCategories(categories)); } @Override public String deserializeBlockCounts(String blockCountsParam) { return runDeserializers(deserializer -> deserializer.deserializeBlockCounts(blockCountsParam)); } @Override public String deserializeDirtyChunks(String dirtyChunksParam) { return runDeserializers(deserializer -> deserializer.deserializeDirtyChunks(dirtyChunksParam)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/RawDeserializer.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.DirtyChunk; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.DatabaseConverter; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandChestAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes; import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.World; import org.bukkit.potion.PotionEffectType; import java.math.BigInteger; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; public class RawDeserializer implements IDeserializer { public static final RawDeserializer INSTANCE = new RawDeserializer(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private RawDeserializer() { } @Override public Map deserializeMissions(String missions) { Map completedMissions = new HashMap<>(); if (missions != null) { for (String mission : missions.split(";")) { String[] missionSections = mission.split("="); int completeAmount = missionSections.length > 1 ? Integer.parseInt(missionSections[1]) : 1; completedMissions.put(missionSections[0], completeAmount); } } return completedMissions; } @Override public String[] deserializeHomes(String locationParam) { String[] islandHomes = new String[World.Environment.values().length]; if (locationParam == null) return islandHomes; String _locationParam = locationParam.contains("=") ? locationParam : "normal=" + locationParam; for (String worldSection : _locationParam.split(";")) { try { String[] locationSection = worldSection.split("="); String environment = locationSection[0].toUpperCase(Locale.ENGLISH); islandHomes[World.Environment.valueOf(environment).ordinal()] = locationSection[1]; } catch (Exception ignored) { } } return islandHomes; } @Override public List deserializePlayers(String players) { List playerAttributesList = new LinkedList<>(); if (players != null) { for (String uuid : players.split(",")) { try { PlayerAttributes playerAttributes = DatabaseConverter.getPlayerAttributes(uuid); if (playerAttributes != null) playerAttributesList.add(playerAttributes); } catch (Exception ignored) { } } } return Collections.unmodifiableList(playerAttributesList); } @Override public Map deserializePlayerPerms(String permissionNodes) { Map playerPermissions = new ArrayMap<>(); if (permissionNodes == null) return playerPermissions; for (String entry : permissionNodes.split(",")) { try { String[] sections = entry.split("="); try { try { int id = Integer.parseInt(sections[0]); SPlayerRole.fromId(id); } catch (Exception ex) { SPlayerRole.of(sections[0]); } } catch (Exception ex) { playerPermissions.put(UUID.fromString(sections[0]), new PlayerPrivilegeNode(null, null, sections.length == 1 ? "" : sections[1])); } } catch (Exception ignored) { } } return playerPermissions; } @Override public Map deserializeRolePerms(String permissionNodes) { Map rolePermissions = new ArrayMap<>(); if (permissionNodes == null) return rolePermissions; for (String entry : permissionNodes.split(",")) { try { String[] sections = entry.split("="); PlayerRole playerRole; try { int id = Integer.parseInt(sections[0]); playerRole = SPlayerRole.fromId(id); } catch (Exception ex) { playerRole = SPlayerRole.of(sections[0]); } if (sections.length != 1) { String[] permission = sections[1].split(";"); for (String perm : permission) { String[] permissionSections = perm.split(":"); try { IslandPrivilege islandPrivilege = IslandPrivilege.getByName(permissionSections[0]); if (permissionSections.length == 2 && permissionSections[1].equals("1")) { rolePermissions.put(islandPrivilege, playerRole); } } catch (Exception ignored) { } } } } catch (Exception ignored) { } } return rolePermissions; } @Override public Map deserializeUpgrades(String upgrades) { Map upgradesMap = new HashMap<>(); if (upgrades != null) { for (String entry : upgrades.split(",")) { try { String[] sections = entry.split("="); upgradesMap.put(sections[0], Integer.parseInt(sections[1])); } catch (Exception ignored) { } } } return upgradesMap; } @Override public List deserializeWarps(String islandWarps) { List warpAttributes = new LinkedList<>(); if (islandWarps == null) return warpAttributes; for (String entry : islandWarps.split(";")) { try { String[] sections = entry.split("="); String name = Formatters.STRIP_COLOR_FORMATTER.format(sections[0].trim()); String category = ""; boolean privateFlag = sections.length == 3 && Boolean.parseBoolean(sections[2]); if (name.contains("-")) { String[] nameSections = name.split("-"); category = nameSections[0]; name = nameSections[1]; } if (name.isEmpty()) continue; if (!IslandUtils.isWarpNameLengthValid(name)) name = name.substring(0, IslandUtils.getMaxWarpNameLength()); if (!IslandUtils.isWarpNameLengthValid(category)) category = category.substring(0, IslandUtils.getMaxWarpNameLength()); warpAttributes.add(new IslandWarpAttributes() .setValue(IslandWarpAttributes.Field.NAME, name) .setValue(IslandWarpAttributes.Field.CATEGORY, category) .setValue(IslandWarpAttributes.Field.LOCATION, sections[1]) .setValue(IslandWarpAttributes.Field.PRIVATE_STATUS, privateFlag) .setValue(IslandWarpAttributes.Field.ICON, sections[3])); } catch (Exception ignored) { } } return Collections.unmodifiableList(warpAttributes); } @Override public KeyMap deserializeBlockLimits(String blocks) { KeyMap blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); if (blocks != null) { for (String limit : blocks.split(",")) { try { String[] sections = limit.split("="); blockLimits.put(Keys.ofMaterialAndData(sections[0]), Integer.parseInt(sections[1])); } catch (Exception ignored) { } } } return blockLimits; } @Override public Map deserializeRatings(String ratings) { Map ratingsMap = new ArrayMap<>(); if (ratings != null) { for (String entry : ratings.split(";")) { try { String[] sections = entry.split("="); ratingsMap.put(UUID.fromString(sections[0]), Rating.valueOf(Integer.parseInt(sections[1]))); } catch (Exception ignored) { } } } return ratingsMap; } @Override public Map deserializeIslandFlags(String settings) { Map islandSettings = new ArrayMap<>(); if (settings != null) { for (String setting : settings.split(";")) { try { if (setting.contains("=")) { String[] settingSections = setting.split("="); islandSettings.put(IslandFlag.getByName(settingSections[0]), Byte.valueOf(settingSections[1])); } else { if (!plugin.getSettings().getDefaultSettings().contains(setting)) islandSettings.put(IslandFlag.getByName(setting), (byte) 1); } } catch (Exception ignored) { } } } return islandSettings; } @Override @SuppressWarnings("unchecked") public KeyMap[] deserializeGenerators(String generator) { KeyMap[] cobbleGenerator = new KeyMap[World.Environment.values().length]; if (generator == null) return cobbleGenerator; if (generator.contains(";")) { for (String env : generator.split(";")) { String[] sections = env.split(":"); try { World.Environment environment = World.Environment.valueOf(sections[0]); deserializeGenerators(sections[1], cobbleGenerator[environment.ordinal()] = KeyMaps.createArrayMap(KeyIndicator.MATERIAL)); } catch (Exception ignored) { } } } else { deserializeGenerators(generator, cobbleGenerator[0] = KeyMaps.createArrayMap(KeyIndicator.MATERIAL)); } return cobbleGenerator; } @Override public List> deserializeVisitors(String visitorsRaw) { List> visitors = new LinkedList<>(); if (visitorsRaw != null) { for (String visitor : visitorsRaw.split(",")) { try { String[] visitorSections = visitor.split(";"); long lastTimeJoined = visitorSections.length == 2 ? Long.parseLong(visitorSections[1]) : System.currentTimeMillis(); visitors.add(new Pair<>(UUID.fromString(visitorSections[0]), lastTimeJoined)); } catch (Exception ignored) { } } } return Collections.unmodifiableList(visitors); } @Override public KeyMap deserializeEntityLimits(String entities) { KeyMap entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); if (entities != null) { for (String limit : entities.split(",")) { try { String[] sections = limit.split("="); entityLimits.put(Keys.ofEntityType(sections[0]), Integer.parseInt(sections[1])); } catch (Exception ignored) { } } } return entityLimits; } @Override public Map deserializeEffects(String effects) { Map islandEffects = new ArrayMap<>(); if (effects != null) { for (String effect : effects.split(",")) { String[] sections = effect.split("="); PotionEffectType potionEffectType = PotionEffectType.getByName(sections[0]); if (potionEffectType != null) islandEffects.put(potionEffectType, Integer.parseInt(sections[1])); } } return islandEffects; } @Override public List deserializeIslandChests(String islandChest) { List islandChestAttributes = new LinkedList<>(); if (Text.isBlank(islandChest)) return islandChestAttributes; String[] islandChestsSections = islandChest.split("\n"); for (int i = 0; i < islandChestsSections.length; i++) { islandChestAttributes.add(new IslandChestAttributes() .setValue(IslandChestAttributes.Field.INDEX, i) .setValue(IslandChestAttributes.Field.CONTENTS, islandChestsSections[i])); } return Collections.unmodifiableList(islandChestAttributes); } @Override public Map deserializeRoleLimits(String roles) { Map roleLimits = new ArrayMap<>(); if (roles != null) { for (String limit : roles.split(",")) { try { String[] sections = limit.split("="); PlayerRole playerRole = SPlayerRole.fromId(Integer.parseInt(sections[0])); if (playerRole != null) roleLimits.put(playerRole, Integer.parseInt(sections[1])); } catch (Exception ignored) { } } } return roleLimits; } @Override public List deserializeWarpCategories(String categories) { List warpCategoryAttributes = new LinkedList<>(); if (categories == null) return warpCategoryAttributes; for (String entry : categories.split(";")) { try { String[] sections = entry.split("="); String name = Formatters.STRIP_COLOR_FORMATTER.format(sections[0].trim()); int slot = Integer.parseInt(sections[1]); String icon = sections[2]; warpCategoryAttributes.add(new WarpCategoryAttributes() .setValue(WarpCategoryAttributes.Field.NAME, name) .setValue(WarpCategoryAttributes.Field.SLOT, slot) .setValue(WarpCategoryAttributes.Field.ICON, icon)); } catch (Exception ignored) { } } return Collections.unmodifiableList(warpCategoryAttributes); } @Override public String deserializeBlockCounts(String blockCountsParam) { KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); if (blockCountsParam != null) { for (String blockCountSection : blockCountsParam.split(";")) { String[] blockCountSections = blockCountSection.split("="); try { blockCounts.put(Keys.ofMaterialAndData(blockCountSections[0]), new BigInteger(blockCountSections[1])); } catch (NumberFormatException ignored) { } } } return IslandsSerializer.serializeBlockCounts(blockCounts); } @Override public String deserializeDirtyChunks(String dirtyChunksParam) { List dirtyChunks = new LinkedList<>(); if (dirtyChunksParam != null) { if (dirtyChunksParam.contains("|")) { String[] serializedSections = dirtyChunksParam.split("\\|"); for (String section : serializedSections) { String[] worldSections = section.split("="); if (worldSections.length == 2) { String[] dirtyChunkSections = worldSections[1].split(";"); for (String dirtyChunk : dirtyChunkSections) { String[] dirtyChunkSection = dirtyChunk.split(","); if (dirtyChunkSection.length == 2) { dirtyChunks.add(new DirtyChunk(worldSections[0], Integer.parseInt(dirtyChunkSection[0]), Integer.parseInt(dirtyChunkSection[1]))); } } } } } else { String[] dirtyChunkSections = dirtyChunksParam.split(";"); for (String dirtyChunk : dirtyChunkSections) { String[] dirtyChunkSection = dirtyChunk.split(","); if (dirtyChunkSection.length == 3) { dirtyChunks.add(new DirtyChunk(dirtyChunkSection[0], Integer.parseInt(dirtyChunkSection[1]), Integer.parseInt(dirtyChunkSection[2]))); } } } } return IslandsSerializer.serializeDirtyChunks(dirtyChunks); } private void deserializeGenerators(String generator, KeyMap cobbleGenerator) { for (String limit : generator.split(",")) { try { String[] sections = limit.split("="); cobbleGenerator.put(Keys.ofMaterialAndData(sections[0]), Integer.parseInt(sections[1])); } catch (Exception ignored) { } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v1/DatabaseUpgrade_V1.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v1; import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; public class DatabaseUpgrade_V1 implements Runnable { public static final DatabaseUpgrade_V1 INSTANCE = new DatabaseUpgrade_V1(); private DatabaseUpgrade_V1() { } @Override public void run() { DBSession.addColumn("islands", "entity_counts", "LONGTEXT"); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v2/DatabaseUpgrade_V2.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v2; import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge; import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import org.bukkit.inventory.ItemStack; import java.sql.ResultSet; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; public class DatabaseUpgrade_V2 implements Runnable { public static final DatabaseUpgrade_V2 INSTANCE = new DatabaseUpgrade_V2(); private DatabaseUpgrade_V2() { } @Override public void run() { // Update all item stacks saved to DB to the new serialization updateWarpsIcons(); updateWarpCategoriesIcons(); updateIslandChests(); } private static void updateWarpsIcons() { List warpIcons = new LinkedList<>(); MutableBoolean isFailed = new MutableBoolean(false); DBSession.select("islands_warps", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet)); String island = databaseResult.getString("island").orElse(null); if (island == null) continue; String name = databaseResult.getString("name").orElse(null); if (name == null) continue; String serializedIcon = databaseResult.getString("icon").orElse(null); if (serializedIcon == null) continue; ItemStack icon = Serializers.ITEM_STACK_SERIALIZER.deserialize(serializedIcon); warpIcons.add(new DatabaseItem(icon, island, name)); } }).onFail(error -> isFailed.set(true))); if (isFailed.get()) return; CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction( "UPDATE {prefix}islands_warps SET icon=? WHERE island=? AND name=?"); updateManyItems(warpIcons, updateTransaction); } private static void updateWarpCategoriesIcons() { List categoryIcons = new LinkedList<>(); MutableBoolean isFailed = new MutableBoolean(false); DBSession.select("islands_warp_categories", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet)); String island = databaseResult.getString("island").orElse(null); if (island == null) continue; String name = databaseResult.getString("name").orElse(null); if (name == null) continue; String serializedIcon = databaseResult.getString("icon").orElse(null); if (serializedIcon == null) continue; ItemStack icon = Serializers.ITEM_STACK_SERIALIZER.deserialize(serializedIcon); categoryIcons.add(new DatabaseItem(icon, island, name)); } }).onFail(error -> isFailed.set(true))); if (isFailed.get()) return; CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction( "UPDATE {prefix}islands_warp_categories SET icon=? WHERE island=? AND name=?"); updateManyItems(categoryIcons, updateTransaction); } private static void updateIslandChests() { List islandContents = new LinkedList<>(); MutableBoolean isFailed = new MutableBoolean(false); DBSession.select("islands_chests", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet)); String island = databaseResult.getString("island").orElse(null); if (island == null) continue; Integer index = databaseResult.getInt("index").orElse(null); if (index == null) continue; byte[] serializedContents = databaseResult.getBlob("contents").orElse(null); if (serializedContents == null) continue; ItemStack[] contents = Serializers.INVENTORY_SERIALIZER.deserialize(serializedContents); islandContents.add(new DatabaseChest(island, index, contents)); } }).onFail(error -> isFailed.set(true))); if (isFailed.get()) return; CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction( "UPDATE {prefix}islands_chests SET contents=? WHERE island=? AND `index`=?"); for (DatabaseChest chestData : islandContents) { updateTransaction .bindObject(Serializers.INVENTORY_SERIALIZER.serialize(chestData.contents)) .bindObject(chestData.island) .bindObject(chestData.index) .newBatch(); } try { DBSession.execute(updateTransaction).get(); } catch (InterruptedException | ExecutionException ignored) { } } private static void updateManyItems(List items, CustomSQLDatabaseTransaction updateTransaction) { for (DatabaseItem iconData : items) { updateTransaction .bindObject(Serializers.ITEM_STACK_SERIALIZER.serialize(iconData.itemStack)) .bindObject(iconData.island) .bindObject(iconData.identifier) .newBatch(); } try { DBSession.execute(updateTransaction).get(); } catch (InterruptedException | ExecutionException ignored) { } } private static class DatabaseItem { private final ItemStack itemStack; private final String island; private final String identifier; DatabaseItem(ItemStack itemStack, String island, String identifier) { this.itemStack = itemStack; this.island = island; this.identifier = identifier; } } private static class DatabaseChest { private final String island; private final int index; private final ItemStack[] contents; DatabaseChest(String island, int index, ItemStack[] contents) { this.island = island; this.index = index; this.contents = contents; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v3/DatabaseUpgrade_V3.java ================================================ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v3; import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import java.sql.ResultSet; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; public class DatabaseUpgrade_V3 implements Runnable { public static final DatabaseUpgrade_V3 INSTANCE = new DatabaseUpgrade_V3(); private DatabaseUpgrade_V3() { } @Override public void run() { List itemsToUpdate = new LinkedList<>(); MutableBoolean isFailed = new MutableBoolean(false); DBSession.select("islands", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet)); String uuid = databaseResult.getString("uuid").orElse(null); if (uuid == null) continue; Integer generatedSchematics = databaseResult.getInt("generated_schematics").orElse(null); if (generatedSchematics == null) continue; Integer unlockedWorlds = databaseResult.getInt("unlocked_worlds").orElse(null); if (unlockedWorlds == null) continue; itemsToUpdate.add(new DatabaseItem(uuid, convertGeneratedSchematicsMask(generatedSchematics), convertUnlockedWorldsMask(unlockedWorlds))); } }).onFail(error -> isFailed.set(true))); if (isFailed.get()) return; DBSession.modifyColumnType("islands", "generated_schematics", "TEXT"); DBSession.modifyColumnType("islands", "unlocked_worlds", "TEXT"); CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction( "UPDATE {prefix}islands SET generated_schematics=?,unlocked_worlds=? WHERE uuid=?"); updateManyItems(itemsToUpdate, updateTransaction); } private static String convertGeneratedSchematicsMask(int generatedSchematicsMask) { StringBuilder generatedSchematics = new StringBuilder(); if ((generatedSchematicsMask & 8) == 8) generatedSchematics.append(",NORMAL"); if ((generatedSchematicsMask & 4) == 4) generatedSchematics.append(",NETHER"); if ((generatedSchematicsMask & 3) == 3) generatedSchematics.append(",THE_END"); return generatedSchematics.length() == 0 ? generatedSchematics.toString() : generatedSchematics.substring(1); } private static String convertUnlockedWorldsMask(int unlockedWorldsMask) { StringBuilder unlockedWorlds = new StringBuilder(); if ((unlockedWorldsMask & 4) == 4) unlockedWorlds.append(",NORMAL"); if ((unlockedWorldsMask & 1) == 1) unlockedWorlds.append(",NETHER"); if ((unlockedWorldsMask & 2) == 2) unlockedWorlds.append(",THE_END"); return unlockedWorlds.length() == 0 ? unlockedWorlds.toString() : unlockedWorlds.substring(1); } private static void updateManyItems(List items, CustomSQLDatabaseTransaction updateTransaction) { for (DatabaseItem item : items) { updateTransaction .bindObject(item.generatedWorlds) .bindObject(item.unlockedWorlds) .bindObject(item.uuid) .newBatch(); } try { DBSession.execute(updateTransaction).get(); } catch (InterruptedException | ExecutionException ignored) { } } private static class DatabaseItem { private final String uuid; private final String generatedWorlds; private final String unlockedWorlds; DatabaseItem(String uuid, String generatedWorlds, String unlockedWorlds) { this.uuid = uuid; this.generatedWorlds = generatedWorlds; this.unlockedWorlds = unlockedWorlds; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java ================================================ package com.bgsoftware.superiorskyblock.core.database.serialization; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.cache.DatabaseCache; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.bank.SBankTransaction; import com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; public class IslandsDeserializer { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Gson GSON = new GsonBuilder().create(); private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); private static final int SYNCED_VALUE = -2; private IslandsDeserializer() { } public static void deserializeMembers(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_members", membersRow -> { DatabaseResult members = new DatabaseResult(membersRow); Optional uuid = members.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island members for null islands, skipping..."); return; } Optional playerUUID = members.getUUID("player"); if (!playerUUID.isPresent()) { Log.warn("Cannot load island members with invalid uuids for ", uuid.get(), ", skipping..."); return; } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false); if (superiorPlayer == null) { Log.warn("Cannot load island member with unrecognized uuid: " + playerUUID.get() + ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_members"); PlayerRole playerRole = members.getInt("role").map(SPlayerRole::fromId) .orElse(SPlayerRole.defaultRole()); superiorPlayer.setPlayerRole(playerRole); builder.addIslandMember(superiorPlayer); }); } public static void deserializeBanned(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_bans", bansRow -> { DatabaseResult bans = new DatabaseResult(bansRow); Optional uuid = bans.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load banned players for null islands, skipping..."); return; } Optional playerUUID = bans.getUUID("player"); if (!playerUUID.isPresent()) { Log.warn("Cannot load banned players with invalid uuids for ", uuid.get(), ", skipping..."); return; } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false); if (superiorPlayer == null) { Log.warn("Cannot load island ban with unrecognized uuid: " + playerUUID.get() + ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_bans"); builder.addBannedPlayer(superiorPlayer); }); } public static void deserializeVisitors(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_visitors", visitorsRow -> { DatabaseResult visitors = new DatabaseResult(visitorsRow); Optional uuid = visitors.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island visitors for null islands, skipping..."); return; } Optional playerUUID = visitors.getUUID("player"); if (!playerUUID.isPresent()) { Log.warn("Cannot load island visitors with invalid uuids for ", uuid.get(), ", skipping..."); return; } SuperiorPlayer visitorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false); if (visitorPlayer == null) { Log.warn("Cannot load island visitor with unrecognized uuid: " + playerUUID.get() + ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_visitors"); long visitTime = visitors.getLong("visit_time").orElse(System.currentTimeMillis()); builder.addUniqueVisitor(visitorPlayer, visitTime); }); } public static void deserializePlayerPermissions(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_player_permissions", playerPermissionRow -> { DatabaseResult playerPermissions = new DatabaseResult(playerPermissionRow); Optional uuid = playerPermissions.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load player permissions for null islands, skipping..."); return; } Optional playerUUID = playerPermissions.getUUID("player"); if (!playerUUID.isPresent()) { Log.warn("Cannot load player permissions for invalid players on ", uuid.get(), ", skipping..."); return; } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false); if (superiorPlayer == null) { Log.warn("Cannot load island player permissions with unrecognized uuid: " + playerUUID.get() + ", skipping..."); return; } IslandPrivilege islandPrivilege = playerPermissions.getString("permission").map(name -> { try { return IslandPrivilege.getByName(name); } catch (NullPointerException error) { IslandPrivilege.register(name); return IslandPrivilege.getByName(name); } }).orElseThrow(IllegalStateException::new); Optional status = playerPermissions.getByte("status"); if (!status.isPresent()) { Log.warn("Cannot load player permissions with invalid status for player ", playerUUID.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_player_permissions"); builder.setPlayerPermission(superiorPlayer, islandPrivilege, status.get() == 1); }); } public static void deserializeRolePermissions(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_role_permissions", rolePermissionsRow -> { DatabaseResult rolePermissions = new DatabaseResult(rolePermissionsRow); Optional uuid = rolePermissions.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load role permissions for null islands, skipping..."); return; } Optional playerRole = rolePermissions.getInt("role").map(SPlayerRole::fromId); if (!playerRole.isPresent()) { Log.warn("Cannot load role permissions with invalid role for ", uuid.get(), ", skipping..."); return; } IslandPrivilege islandPrivilege = rolePermissions.getString("permission").map(name -> { try { return IslandPrivilege.getByName(name); } catch (NullPointerException error) { IslandPrivilege.register(name); return IslandPrivilege.getByName(name); } }).orElseThrow(IllegalStateException::new); Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_role_permissions"); builder.setRolePermission(islandPrivilege, playerRole.get()); }); } public static void deserializeUpgrades(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_upgrades", upgradesRow -> { DatabaseResult upgrades = new DatabaseResult(upgradesRow); Optional uuid = upgrades.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load upgrades for null islands, skipping..."); return; } Optional upgrade = upgrades.getString("upgrade").map(plugin.getUpgrades()::getUpgrade); if (!upgrade.isPresent()) { Log.warn("Cannot load upgrades with invalid upgrade names for ", uuid.get(), ", skipping..."); return; } Optional level = upgrades.getInt("level"); if (!level.isPresent()) { Log.warn("Cannot load upgrades with invalid levels for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_upgrades"); builder.setUpgrade(upgrade.get(), level.get()); }); } public static void deserializeWarps(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_warps", islandWarpsRow -> { DatabaseResult islandWarp = new DatabaseResult(islandWarpsRow); Optional uuid = islandWarp.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load warps for null islands, skipping..."); return; } Optional name = islandWarp.getString("name").map(_name -> { return IslandUtils.isWarpNameLengthValid(_name) ? _name : _name.substring(0, IslandUtils.getMaxWarpNameLength()); }); if (!name.isPresent() || name.get().isEmpty()) { Log.warn("Cannot load warps with invalid names for ", uuid.get(), ", skipping..."); return; } Optional location = islandWarp.getString("location").map(Serializers.LOCATION_SERIALIZER::deserialize); if (!location.isPresent()) { Log.warn("Cannot load warps with invalid locations for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_warps"); builder.addWarp(name.get(), islandWarp.getString("category").orElse(""), location.get(), islandWarp.getBoolean("private").orElse(!plugin.getSettings().isPublicWarps()), islandWarp.getString("icon").map(Serializers.ITEM_STACK_SERIALIZER::deserialize).orElse(null)); }); } public static void deserializeDirtyChunks(Island.Builder builder, String dirtyChunks) { if (Text.isBlank(dirtyChunks)) return; JsonObject dirtyChunksObject = GSON.fromJson(dirtyChunks, JsonObject.class); dirtyChunksObject.entrySet().forEach(dirtyChunkEntry -> { String worldName = dirtyChunkEntry.getKey(); JsonArray dirtyChunksArray = dirtyChunkEntry.getValue().getAsJsonArray(); dirtyChunksArray.forEach(dirtyChunkElement -> { String[] chunkPositionSections = dirtyChunkElement.getAsString().split(","); builder.setDirtyChunk(worldName, Integer.parseInt(chunkPositionSections[0]), Integer.parseInt(chunkPositionSections[1])); }); }); } public static void deserializeBlockCounts(Island.Builder builder, String blocks) { if (Text.isBlank(blocks)) return; JsonArray blockCounts = GSON.fromJson(blocks, JsonArray.class); blockCounts.forEach(blockCountElement -> { JsonObject blockCountObject = blockCountElement.getAsJsonObject(); Key blockKey = Keys.ofMaterialAndData(blockCountObject.get("id").getAsString()); BigInteger amount = new BigInteger(blockCountObject.get("amount").getAsString()); builder.setBlockCount(blockKey, amount); }); } public static void deserializeEntityCounts(Island.Builder builder, String entities) { if (Text.isBlank(entities)) return; JsonArray entityCounts = GSON.fromJson(entities, JsonArray.class); entityCounts.forEach(entityCountElement -> { JsonObject entityCountObject = entityCountElement.getAsJsonObject(); Key entityKey = Keys.ofEntityType(entityCountObject.get("id").getAsString()); BigInteger amount = new BigInteger(entityCountObject.get("amount").getAsString()); builder.setEntityCount(entityKey, amount); }); } public static void deserializeDimensionsList(String dimensions, Consumer consumer) { if (Text.isBlank(dimensions)) return; for (String dimensionName : dimensions.split(",")) { try { Dimension dimension = Dimension.getByName(dimensionName); consumer.accept(dimension); } catch (NullPointerException ignored) { } } } public static void deserializeBlockLimits(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_block_limits", blockLimitRow -> { DatabaseResult blockLimits = new DatabaseResult(blockLimitRow); Optional uuid = blockLimits.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load block limits for null islands, skipping..."); return; } Optional block = blockLimits.getString("block").map(Keys::ofMaterialAndData); if (!block.isPresent()) { Log.warn("Cannot load block limits for invalid blocks for ", uuid.get(), ", skipping..."); return; } Optional limit = blockLimits.getInt("limit"); if (!limit.isPresent()) { Log.warn("Cannot load block limits with invalid limits for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_block_limits"); builder.setBlockLimit(block.get(), limit.get()); }); } public static void deserializeEntityLimits(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_entity_limits", entityLimitsRow -> { DatabaseResult entityLimits = new DatabaseResult(entityLimitsRow); Optional uuid = entityLimits.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load entity limits for null islands, skipping..."); return; } Optional entity = entityLimits.getString("entity").map(Keys::ofEntityType); if (!entity.isPresent()) { Log.warn("Cannot load entity limits for invalid entities on ", uuid.get(), ", skipping..."); return; } Optional limit = entityLimits.getInt("limit"); if (!limit.isPresent()) { Log.warn("Cannot load entity limits with invalid limits for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_entity_limits"); builder.setEntityLimit(entity.get(), limit.get()); }); } public static void deserializeRatings(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_ratings", ratingsRow -> { DatabaseResult ratings = new DatabaseResult(ratingsRow); Optional uuid = ratings.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load ratings for null islands, skipping..."); return; } Optional playerUUID = ratings.getUUID("player"); if (!playerUUID.isPresent()) { Log.warn("Cannot load ratings with invalid players for ", uuid.get(), ", skipping..."); return; } SuperiorPlayer ratingPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false); if (ratingPlayer == null) { Log.warn("Cannot load island rating with unrecognized uuid: " + playerUUID.get() + ", skipping..."); return; } Optional rating = ratings.getInt("rating").map(value -> { try { return Rating.valueOf(value); } catch (ArrayIndexOutOfBoundsException error) { return null; } }); if (!rating.isPresent()) { Log.warn("Cannot load ratings with invalid rating value for ", playerUUID.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_ratings"); builder.setRating(ratingPlayer, rating.get()); }); } public static void deserializeMissions(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_missions", missionsRow -> { DatabaseResult missions = new DatabaseResult(missionsRow); Optional uuid = missions.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island missions for null islands, skipping..."); return; } Optional missionName = missions.getString("name"); Optional> mission = missionName.map(plugin.getMissions()::getMission); if (!mission.isPresent()) { if (!missionName.isPresent()) { Log.warn("Cannot load island missions with invalid missions for ", uuid.get(), ", skipping..."); } else { Log.warn("Cannot load island missions with invalid mission ", missionName.get(), " for ", uuid.get(), ", skipping..."); } return; } Optional finishCount = missions.getInt("finish_count"); if (!finishCount.isPresent()) { Log.warn("Cannot load island missions with invalid finish count for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_missions"); builder.setCompletedMission(mission.get(), finishCount.get()); }); } public static void deserializeIslandFlags(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_flags", islandFlagRow -> { DatabaseResult islandFlagResult = new DatabaseResult(islandFlagRow); Optional uuid = islandFlagResult.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island flags for null islands, skipping..."); return; } IslandFlag islandFlag = islandFlagResult.getString("name").map(name -> { try { return IslandFlag.getByName(name); } catch (NullPointerException error) { IslandFlag.register(name); return IslandFlag.getByName(name); } }).orElseThrow(IllegalStateException::new); Optional status = islandFlagResult.getByte("status"); if (!status.isPresent()) { Log.warn("Cannot load island flags with invalid status for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_flags"); builder.setIslandFlag(islandFlag, status.get() == 1); }); } public static void deserializeGenerators(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_generators", generatorsRow -> { DatabaseResult generators = new DatabaseResult(generatorsRow); Optional uuid = generators.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load generator rates for null islands, skipping..."); return; } Optional dimension = generators.getString("environment").map(Dimension::getByName); if (!dimension.isPresent()) { Log.warn("Cannot load generator rates with invalid environment for ", uuid.get(), ", skipping..."); return; } Optional block = generators.getString("block").map(Keys::ofMaterialAndData); if (!block.isPresent()) { Log.warn("Cannot load generator rates with invalid block for ", uuid.get(), ", skipping..."); return; } Optional rate = generators.getInt("rate"); if (!rate.isPresent()) { Log.warn("Cannot load generator rates with invalid rate for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_generators"); builder.setGeneratorRate(block.get(), rate.get(), dimension.get()); }); } public static void deserializeIslandHomes(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_homes", islandHomesRow -> { DatabaseResult islandHomes = new DatabaseResult(islandHomesRow); Optional uuid = islandHomes.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island homes for null islands, skipping..."); return; } Optional dimension = islandHomes.getString("environment").map(Dimension::getByName); if (!dimension.isPresent()) { Log.warn("Cannot load island homes with invalid environment for ", uuid.get(), ", skipping..."); return; } Optional location = islandHomes.getString("location").map(Serializers.WORLD_POSITION_SERIALIZER::deserialize); if (!location.isPresent()) { Log.warn("Cannot load island homes with invalid location for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_homes"); builder.setIslandHome(dimension.get(), location.get()); }); } public static void deserializeVisitorHomes(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_visitor_homes", islandVisitorHomesRow -> { DatabaseResult islandVisitorHomes = new DatabaseResult(islandVisitorHomesRow); Optional uuid = islandVisitorHomes.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island homes for null islands, skipping..."); return; } Optional dimension = islandVisitorHomes.getString("environment").map(Dimension::getByName); if (!dimension.isPresent()) { Log.warn("Cannot load island homes with invalid environment for ", uuid.get(), ", skipping..."); return; } Optional location = islandVisitorHomes.getString("location").map(Serializers.WORLD_POSITION_SERIALIZER::deserialize); if (!location.isPresent()) { Log.warn("Cannot load island homes with invalid location for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_visitor_homes"); builder.setVisitorHome(dimension.get(), location.get()); }); } public static void deserializeEffects(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_effects", islandEffectRow -> { DatabaseResult islandEffects = new DatabaseResult(islandEffectRow); Optional uuid = islandEffects.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island effects for null islands, skipping..."); return; } Optional effectType = islandEffects.getString("effect_type") .map(PotionEffectType::getByName); if (!effectType.isPresent()) { Log.warn("Cannot load island effects with invalid effect for ", uuid.get(), ", skipping..."); return; } Optional level = islandEffects.getInt("level"); if (!level.isPresent()) { Log.warn("Cannot load island effects with invalid level for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_effects"); builder.setIslandEffect(effectType.get(), level.get()); }); } public static void deserializeIslandChest(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_chests", islandChestsRow -> { DatabaseResult islandChests = new DatabaseResult(islandChestsRow); Optional uuid = islandChests.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island chests for null islands, skipping..."); return; } Optional index = islandChests.getInt("index"); if (!index.isPresent() || index.get() < 0) { Log.warn("Cannot load island chest with invalid index for ", uuid.get(), ", skipping..."); return; } Optional contents = islandChests.getBlob("contents").map(Serializers.INVENTORY_SERIALIZER::deserialize); if (!contents.isPresent()) { Log.warn("Cannot load island chest with invalid contents for ", uuid.get(), ", skipping..."); return; } int contentsLength = contents.get().length; ItemStack[] chestContents; if (contentsLength % 9 != 0) { int amountOfRows = Math.min(1, Math.max(6, (contentsLength / 9) + 1)); chestContents = new ItemStack[amountOfRows * 9]; int amountOfContentsToCopy = Math.min(contentsLength, chestContents.length); System.arraycopy(contents.get(), 0, chestContents, 0, amountOfContentsToCopy); } else if (contentsLength > 54) { chestContents = new ItemStack[54]; System.arraycopy(contents.get(), 0, chestContents, 0, 54); } else if (contentsLength < 9) { chestContents = new ItemStack[9]; System.arraycopy(contents.get(), 0, chestContents, 0, contentsLength); } else { chestContents = contents.get(); } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_chests"); builder.setIslandChest(index.get(), chestContents); }); } public static void deserializeRoleLimits(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_role_limits", roleLimitRaw -> { DatabaseResult roleLimits = new DatabaseResult(roleLimitRaw); Optional uuid = roleLimits.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load role limits for null islands, skipping..."); return; } Optional playerRole = roleLimits.getInt("role").map(SPlayerRole::fromId); if (!playerRole.isPresent()) { Log.warn("Cannot load role limit for invalid role on ", uuid.get(), ", skipping..."); return; } Optional limit = roleLimits.getInt("limit"); if (!limit.isPresent()) { Log.warn("Cannot load role limit for invalid limit on ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_role_limits"); builder.setRoleLimit(playerRole.get(), limit.get()); }); } public static void deserializeWarpCategories(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_warp_categories", warpCategoryRow -> { DatabaseResult warpCategory = new DatabaseResult(warpCategoryRow); Optional uuid = warpCategory.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load warp categories for null islands, skipping..."); return; } Optional name = warpCategory.getString("name").map(Formatters.STRIP_COLOR_FORMATTER::format); if (!name.isPresent() || name.get().isEmpty()) { Log.warn("Cannot load warp categories with invalid name for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_warp_categories"); builder.addWarpCategory(name.get(), warpCategory.getInt("slot").orElse(-1), warpCategory.getString("icon").map(Serializers.ITEM_STACK_SERIALIZER::deserialize).orElse(null)); }); } public static void deserializeIslandBank(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_banks", islandBankRow -> { DatabaseResult islandBank = new DatabaseResult(islandBankRow); Optional uuid = islandBank.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island banks for null islands, skipping..."); return; } Optional balance = islandBank.getBigDecimal("balance"); if (!balance.isPresent()) { Log.warn("Cannot load island banks with invalid balance for ", uuid.get(), ", skipping..."); return; } long currentTime = System.currentTimeMillis() / 1000; Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_banks"); builder.setBalance(balance.get()); long lastInterestTime = islandBank.getLong("last_interest_time").orElse(currentTime); builder.setLastInterestTime(lastInterestTime > currentTime ? lastInterestTime / 1000 : lastInterestTime); }); } public static void deserializeIslandSettings(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_settings", islandSettingsRow -> { DatabaseResult islandSettings = new DatabaseResult(islandSettingsRow); Optional uuid = islandSettings.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load island settings of null island, skipping "); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_settings"); builder.setIslandSize(islandSettings.getInt("size").orElse(SYNCED_VALUE)); builder.setTeamLimit(islandSettings.getInt("members_limit").orElse(SYNCED_VALUE)); builder.setWarpsLimit(islandSettings.getInt("warps_limit").orElse(SYNCED_VALUE)); builder.setCropGrowth(islandSettings.getDouble("crop_growth_multiplier").orElse((double) SYNCED_VALUE)); builder.setSpawnerRates(islandSettings.getDouble("spawner_rates_multiplier").orElse((double) SYNCED_VALUE)); builder.setMobDrops(islandSettings.getDouble("mob_drops_multiplier").orElse((double) SYNCED_VALUE)); builder.setCoopLimit(islandSettings.getInt("coops_limit").orElse(SYNCED_VALUE)); builder.setBankLimit(islandSettings.getBigDecimal("bank_limit").orElse(SYNCED_BANK_LIMIT_VALUE)); }); } public static void deserializeBankTransactions(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { if (!BuiltinModules.BANK.getConfiguration().isBankLogs() || !BuiltinModules.BANK.getConfiguration().isCacheAllLogs()) return; databaseBridge.loadAllObjects("bank_transactions", bankTransactionRow -> { DatabaseResult bankTransaction = new DatabaseResult(bankTransactionRow); Optional uuid = bankTransaction.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load bank transaction for null islands, skipping..."); return; } Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "bank_transactions"); SBankTransaction.fromDatabase(bankTransaction).ifPresent(builder::addBankTransaction); }); } public static void deserializePersistentDataContainer(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_custom_data", customDataRow -> { DatabaseResult customData = new DatabaseResult(customDataRow); Optional uuid = customData.getUUID("island"); if (!uuid.isPresent()) { Log.warn("Cannot load custom data for null islands, skipping..."); return; } byte[] persistentData = customData.getBlob("data").orElse(new byte[0]); if (persistentData.length == 0) return; Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_custom_data"); builder.setPersistentData(persistentData); }); } private static Island.Builder lookupIsland(DatabaseCache databaseCache, UUID uuid, String tableName) { DatabaseCache.Record islandRecord = databaseCache.computeIfAbsentInfo(uuid, IslandBuilderImpl::new); islandRecord.recordTable(tableName); return islandRecord.get(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.database.serialization; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.DirtyChunk; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import java.math.BigInteger; import java.util.Collection; import java.util.List; import java.util.Map; public class IslandsSerializer { private static final Gson gson = new GsonBuilder().create(); private IslandsSerializer() { } public static String serializeBlockCounts(Map blockCounts) { JsonArray blockCountsArray = new JsonArray(); blockCounts.forEach((key, amount) -> { JsonObject blockCountObject = new JsonObject(); blockCountObject.addProperty("id", key.toString()); blockCountObject.addProperty("amount", amount.toString()); blockCountsArray.add(blockCountObject); }); return gson.toJson(blockCountsArray); } public static String serializeEntityCounts(Map entityCounts) { JsonArray entityCountsArray = new JsonArray(); entityCounts.forEach((key, amount) -> { JsonObject blockCountObject = new JsonObject(); blockCountObject.addProperty("id", key.toString()); blockCountObject.addProperty("amount", amount.toString()); entityCountsArray.add(blockCountObject); }); return gson.toJson(entityCountsArray); } public static String serializeDirtyChunks(List dirtyChunks) { JsonObject dirtyChunksObject = new JsonObject(); dirtyChunks.forEach(dirtyChunk -> { JsonArray dirtyChunksArray; if (dirtyChunksObject.has(dirtyChunk.getWorldName())) { dirtyChunksArray = dirtyChunksObject.getAsJsonArray(dirtyChunk.getWorldName()); } else { dirtyChunksArray = new JsonArray(); dirtyChunksObject.add(dirtyChunk.getWorldName(), dirtyChunksArray); } dirtyChunksArray.add(new JsonPrimitive(dirtyChunk.getX() + "," + dirtyChunk.getZ())); }); return gson.toJson(dirtyChunksObject); } public static String serializeDirtyChunkPositions(List dirtyChunks) { JsonObject dirtyChunksObject = new JsonObject(); dirtyChunks.forEach(dirtyChunk -> serializeDirtyChunkPosition(dirtyChunksObject, dirtyChunk)); return gson.toJson(dirtyChunksObject); } public static String serializeDirtyChunkPositions(DirtyChunksContainer container) { JsonObject dirtyChunksObject = new JsonObject(); container.getDirtyChunks(dirtyChunk -> serializeDirtyChunkPosition(dirtyChunksObject, dirtyChunk)); return gson.toJson(dirtyChunksObject); } public static String serializeDimensions(Collection dimensions) { StringBuilder serialized = new StringBuilder(); for (Dimension dimension : dimensions) serialized.append(",").append(dimension.getName()); return serialized.length() == 0 ? serialized.toString() : serialized.substring(1); } private static void serializeDirtyChunkPosition(JsonObject dirtyChunksObject, ChunkPosition dirtyChunk) { JsonArray dirtyChunksArray; if (dirtyChunksObject.has(dirtyChunk.getWorldName())) { dirtyChunksArray = dirtyChunksObject.getAsJsonArray(dirtyChunk.getWorldName()); } else { dirtyChunksArray = new JsonArray(); dirtyChunksObject.add(dirtyChunk.getWorldName(), dirtyChunksArray); } dirtyChunksArray.add(new JsonPrimitive(dirtyChunk.getX() + "," + dirtyChunk.getZ())); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/PlayersDeserializer.java ================================================ package com.bgsoftware.superiorskyblock.core.database.serialization; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.cache.DatabaseCache; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import java.util.Optional; import java.util.UUID; public class PlayersDeserializer { static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private PlayersDeserializer() { } public static void deserializeMissions(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("players_missions", missionsRow -> { DatabaseResult missions = new DatabaseResult(missionsRow); Optional player = missions.getString("player"); if (!player.isPresent()) { Log.warn("Cannot load player mission of null player, skipping..."); return; } UUID uuid = UUID.fromString(player.get()); SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid, "players_missions"); Optional name = missions.getString("name"); if (!name.isPresent()) { Log.warn("Cannot load player mission of null mission for ", uuid, ", skipping..."); return; } Optional finishCount = missions.getInt("finish_count"); if (!finishCount.isPresent()) { Log.warn("Cannot load player mission of invalid finish count for ", uuid, ", skipping..."); return; } Mission mission = plugin.getMissions().getMission(name.get()); if (mission != null) builder.setCompletedMission(mission, finishCount.get()); }); } public static void deserializePlayerSettings(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("players_settings", playerSettingsRow -> { DatabaseResult playerSettings = new DatabaseResult(playerSettingsRow); Optional player = playerSettings.getString("player"); if (!player.isPresent()) { Log.warn("&cCannot load player settings of null player, skipping..."); return; } UUID uuid = UUID.fromString(player.get()); SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid, "players_settings"); playerSettings.getBoolean("toggled_panel").ifPresent(builder::setToggledPanel); playerSettings.getBoolean("island_fly").ifPresent(builder::setIslandFly); playerSettings.getEnum("border_color", BorderColor.class).ifPresent(builder::setBorderColor); playerSettings.getString("language").map(PlayerLocales::getLocale).ifPresent(builder::setLocale); playerSettings.getBoolean("toggled_border").ifPresent(builder::setWorldBorderEnabled); }); } public static void deserializePersistentDataContainer(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("players_custom_data", customDataRow -> { DatabaseResult customData = new DatabaseResult(customDataRow); Optional uuid = customData.getUUID("player"); if (!uuid.isPresent()) { Log.warn("&cCannot load custom data for null players, skipping..."); return; } byte[] persistentData = customData.getBlob("data").orElse(new byte[0]); if (persistentData.length == 0) return; SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid.get(), "players_custom_data"); builder.setPersistentData(persistentData); }); } private static SuperiorPlayer.Builder lookupPlayer(DatabaseCache databaseCache, UUID uuid, String tableName) { DatabaseCache.Record playerRecord = databaseCache.computeIfAbsentInfo(uuid, SuperiorPlayer::newBuilder); playerRecord.recordTable(tableName); return playerRecord.get(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java ================================================ package com.bgsoftware.superiorskyblock.core.database.sql; import com.bgsoftware.common.databasebridge.DatabaseSessionFactory; import com.bgsoftware.common.databasebridge.logger.ILogger; import com.bgsoftware.common.databasebridge.session.IDatabaseSession; import com.bgsoftware.common.databasebridge.sql.query.Column; import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.common.databasebridge.sql.session.MariaDBDatabaseSession; import com.bgsoftware.common.databasebridge.sql.session.MySQLDatabaseSession; import com.bgsoftware.common.databasebridge.sql.session.SQLDatabaseSession; import com.bgsoftware.common.databasebridge.sql.session.SQLiteDatabaseSession; import com.bgsoftware.common.databasebridge.transaction.DatabaseTransactionsExecutor; import com.bgsoftware.common.databasebridge.transaction.IDatabaseTransaction; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import java.io.File; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Collection; import java.util.concurrent.CompletableFuture; public class DBSession { private static final ILogger LOGGER = new ILogger() { @Override public void error(String message, Throwable error) { Log.error(error, message); } @Override public boolean hasDebugEnabled() { return Log.isDebugged(Debug.DATABASE_QUERY); } @Override public void debug(String message) { if (hasDebugEnabled()) Log.debug(Debug.DATABASE_QUERY, message); } @Override public void info(String message) { Log.info(message); } }; private static SQLDatabaseSession globalSession = null; private DBSession() { } public static boolean isReady() { return globalSession != null; } public static void waitForConnection() { if (isReady()) globalSession.waitForConnection(); } public static boolean createConnection(SuperiorSkyblockPlugin plugin) { SQLDatabaseSession session = createSessionInternal(plugin, true); if (session.connect()) { globalSession = session; return true; } return false; } public static CompletableFuture execute(IDatabaseTransaction transaction) { return globalSession.execute(transaction); } public static CompletableFuture execute(IDatabaseTransaction... transactions) { return globalSession.execute(transactions); } public static CompletableFuture execute(Collection transactions) { return globalSession.execute(transactions); } public static void createTable(String tableName, Column... columns) { if (isReady()) globalSession.createTable(tableName, columns, QueryResult.EMPTY_VOID_QUERY_RESULT); } public static void createIndex(String indexName, String tableName, String... columns) { if (isReady()) globalSession.createIndex(indexName, tableName, columns, QueryResult.EMPTY_VOID_QUERY_RESULT); } public static void modifyColumnType(String tableName, String columnName, String newType) { if (isReady()) globalSession.modifyColumnType(tableName, columnName, newType, QueryResult.EMPTY_VOID_QUERY_RESULT); } public static void addColumn(String tableName, String columnName, String type) { if (isReady()) globalSession.addColumn(tableName, columnName, type, QueryResult.EMPTY_VOID_QUERY_RESULT); } public static void removePrimaryKey(String tableName, String columnName) { if (isReady()) globalSession.removePrimaryKey(tableName, columnName, QueryResult.EMPTY_VOID_QUERY_RESULT); } public static void select(String tableName, String filters, QueryResult queryResult) { if (isReady()) globalSession.select(tableName, filters, queryResult); } public static void setJournalMode(String jounralMode, QueryResult queryResult) { if (isReady()) globalSession.setJournalMode(jounralMode, queryResult); } public static void customQuery(String query, QueryResult queryResult) { if (isReady()) globalSession.customQuery(query, queryResult); } public static void close() { if (isReady()) { DatabaseTransactionsExecutor.stopActiveExecutors(); globalSession.close(); } } public static String getColumnFilter(DatabaseFilter filter) { StringBuilder columnIdentifier = new StringBuilder(); if (filter != null) { filter.forEach((column, value) -> { if (columnIdentifier.length() == 0) { columnIdentifier.append(String.format(" WHERE %s=?", column)); } else { columnIdentifier.append(String.format(" AND %s=?", column)); } }); } return columnIdentifier.toString(); } private static SQLDatabaseSession createSessionInternal(SuperiorSkyblockPlugin plugin, boolean logging) { SettingsManager.Database database = plugin.getSettings().getDatabase(); IDatabaseSession.Args args; switch (database.getType()) { case "MYSQL": args = new MySQLDatabaseSession.Args(database.getAddress(), database.getPort(), database.getDBName(), database.getUsername(), database.getPassword(), database.getPrefix(), database.hasSSL(), database.hasPublicKeyRetrieval(), database.getWaitTimeout(), database.getMaxLifetime(), "SuperiorSkyblock Database Thread", LOGGER); break; case "MARIADB": args = new MariaDBDatabaseSession.Args(database.getAddress(), database.getPort(), database.getDBName(), database.getUsername(), database.getPassword(), database.getPrefix(), database.hasSSL(), database.hasPublicKeyRetrieval(), database.getWaitTimeout(), database.getMaxLifetime(), "SuperiorSkyblock Database Thread", LOGGER); break; default: File databaseFile = new File(plugin.getDataFolder(), "datastore/database.db"); args = new SQLiteDatabaseSession.Args(databaseFile, "SuperiorSkyblock Database Thread", LOGGER); break; } SQLDatabaseSession session = (SQLDatabaseSession) DatabaseSessionFactory.createSession(args); if (logging) session.setLogging(true); return session; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/ResultSetMapBridge.java ================================================ package com.bgsoftware.superiorskyblock.core.database.sql; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; import java.util.Map; import java.util.Set; public class ResultSetMapBridge implements Map { private final ResultSet resultSet; public ResultSetMapBridge(ResultSet resultSet) { this.resultSet = resultSet; } @Override public int size() { return 0; } @Override public boolean isEmpty() { return size() == 0; } @Override public boolean containsKey(Object key) { try { get(key); return true; } catch (Exception ex) { return false; } } @Override public boolean containsValue(Object value) { throw new UnsupportedOperationException("This operation is not supported on this map."); } @Override public Object get(Object key) { return getSafe(key + ""); } public T get(Object key, T def) { try { return get(key + ""); } catch (SQLException ex) { return def; } } @Nullable @Override public Object put(String key, Object value) { throw new UnsupportedOperationException("This operation is not supported on this map."); } @Override public Object remove(Object key) { throw new UnsupportedOperationException("This operation is not supported on this map."); } @Override public void putAll(@NotNull Map m) { throw new UnsupportedOperationException("This operation is not supported on this map."); } @Override public void clear() { throw new UnsupportedOperationException("This operation is not supported on this map."); } @NotNull @Override public Set keySet() { throw new UnsupportedOperationException("This operation is not supported on this map."); } @NotNull @Override public Collection values() { throw new UnsupportedOperationException("This operation is not supported on this map."); } @NotNull @Override public Set> entrySet() { throw new UnsupportedOperationException("This operation is not supported on this map."); } private T get(String key) throws SQLException { // noinspection all return (T) resultSet.getObject(key); } private T getSafe(String key) { try { return get(key + ""); } catch (SQLException ex) { throw new RuntimeException(ex); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLDatabaseBridge.java ================================================ package com.bgsoftware.superiorskyblock.core.database.sql; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.common.databasebridge.sql.transaction.DeleteSQLDatabaseTransaction; import com.bgsoftware.common.databasebridge.sql.transaction.InsertSQLDatabaseTransaction; import com.bgsoftware.common.databasebridge.sql.transaction.UpdateSQLDatabaseTransaction; import com.bgsoftware.common.databasebridge.transaction.IDatabaseTransaction; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import java.sql.ResultSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.function.Consumer; public class SQLDatabaseBridge implements DatabaseBridge { private DatabaseBridgeMode databaseBridgeMode = DatabaseBridgeMode.IDLE; private List batchTransactions = null; public SQLDatabaseBridge() { } @Override public void loadAllObjects(String table, Consumer> resultConsumer) { DBSession.select(table, "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { try { resultConsumer.accept(new ResultSetMapBridge(resultSet)); } catch (Exception error) { Log.entering("ENTER", table); Log.error(error, "An unexpected error occurred while loading data from database:"); } } }).onFail(QueryResult.PRINT_ERROR)); } @Override public void batchOperations(boolean batchOperations) { if (batchOperations) { batchTransactions = new LinkedList<>(); } else if (batchTransactions != null) { DBSession.execute(batchTransactions); batchTransactions = null; } } @Override public void updateObject(String table, @Nullable DatabaseFilter filter, Pair[] columns) { if (databaseBridgeMode != DatabaseBridgeMode.SAVE_DATA) return; List filteredColumns = filter == null ? null : new LinkedList<>(); List columnNames = new LinkedList<>(); List values = new LinkedList<>(); for (Pair column : columns) { columnNames.add(column.getKey()); values.add(column.getValue()); } if (filter != null) { filter.forEach((column, value) -> { filteredColumns.add(column); values.add(value); }); } UpdateSQLDatabaseTransaction transaction = new UpdateSQLDatabaseTransaction(table, columnNames, filteredColumns); transaction.bindObjects(values); submitTransaction(transaction); } @Override public void insertObject(String table, Pair... columns) { if (databaseBridgeMode != DatabaseBridgeMode.SAVE_DATA) return; List columnNames = new LinkedList<>(); List values = new LinkedList<>(); for (Pair column : columns) { columnNames.add(column.getKey()); values.add(column.getValue()); } InsertSQLDatabaseTransaction transaction = new InsertSQLDatabaseTransaction(table, columnNames); transaction.bindObjects(values); submitTransaction(transaction); } @Override public void deleteObject(String table, @Nullable DatabaseFilter filter) { if (databaseBridgeMode != DatabaseBridgeMode.SAVE_DATA) return; List filteredColumns = filter == null ? null : new LinkedList<>(); List values = new LinkedList<>(); if (filter != null) { filter.forEach((column, value) -> { filteredColumns.add(column); values.add(value + ""); }); } DeleteSQLDatabaseTransaction transaction = new DeleteSQLDatabaseTransaction(table, filteredColumns); transaction.bindObjects(values); submitTransaction(transaction); } @Override public void loadObject(String table, DatabaseFilter filter, Consumer> resultConsumer) { MutableObject columnFilter = new MutableObject<>(DBSession.getColumnFilter(filter)); filter.forEach((column, value) -> { columnFilter.setValue(columnFilter.getValue().replaceFirst("\\?", value instanceof String ? String.format("'%s'", value) : value.toString())); }); DBSession.select(table, columnFilter.getValue(), new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { try { resultConsumer.accept(new ResultSetMapBridge(resultSet)); } catch (Exception error) { Log.entering("ENTER", table, columnFilter); Log.error(error, "An unexpected error occurred while loading data from database:"); } } }).onFail(QueryResult.PRINT_ERROR)); } @Override public void setDatabaseBridgeMode(DatabaseBridgeMode databaseBridgeMode) { this.databaseBridgeMode = databaseBridgeMode; } @Override public DatabaseBridgeMode getDatabaseBridgeMode() { return this.databaseBridgeMode; } private void submitTransaction(IDatabaseTransaction transaction) { if (batchTransactions != null) { batchTransactions.add(transaction); } else { DBSession.execute(transaction); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/engine/EnginesFactory.java ================================================ package com.bgsoftware.superiorskyblock.core.engine; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; public class EnginesFactory { private static IScriptEngine defaultEngine; private EnginesFactory() { } public static IScriptEngine createDefaultEngine() { if (defaultEngine == null) { try { ReflectMethod nashornEngineGetInstance = new ReflectMethod<>( new ClassInfo("com.bgsoftware.superiorskyblock.core.engine.OpenJdkNashornEngine", ClassInfo.PackageType.UNKNOWN), "getInstance", new Class[0] ); Class.forName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory"); defaultEngine = nashornEngineGetInstance.invoke(null); } catch (Throwable error) { defaultEngine = NashornEngine.getInstance(); } } return defaultEngine; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/engine/NashornEngine.java ================================================ package com.bgsoftware.superiorskyblock.core.engine; import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class NashornEngine implements IScriptEngine { private static final NashornEngine instance = new NashornEngine(); private final ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); private NashornEngine() { } public static NashornEngine getInstance() { return instance; } @Override public Object eval(String stringToEvaluate) throws ScriptException { return engine.eval(stringToEvaluate); } @Override public Object eval(String stringToEvaluate, Bindings bindings) throws ScriptException { return engine.eval(stringToEvaluate, bindings); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/engine/NashornEngineDownloader.java ================================================ package com.bgsoftware.superiorskyblock.core.engine; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.gson.Gson; import com.google.gson.JsonObject; import javax.net.ssl.HttpsURLConnection; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; public class NashornEngineDownloader { private static final Gson GSON = new Gson(); private static final String JENKINS_URL = "https://hub.bg-software.com/job/SuperiorSkyblock2%20-%20NashornEngine%20Module%20-%20Dev%20Builds/lastSuccessfulBuild/"; private static final String JENKINS_API_ENDPOINT = JENKINS_URL + "api/json"; private static final String JENKINS_ARTIFACTS_ENDPOINT = JENKINS_URL + "artifact/target/"; public static boolean downloadEngine(SuperiorSkyblockPlugin plugin) { try { Log.info("Seems like you are missing a nashorn engine. Attempting to download one remotely..."); deleteExistingModule(plugin); JsonObject apiResponse = readJenkinsJsonAPI(); JsonObject artifact = apiResponse.getAsJsonArray("artifacts").get(0).getAsJsonObject(); String fileName = artifact.get("fileName").getAsString(); File engineFile = downloadEngine(plugin, fileName); Log.info("Successfully downloaded the nashorn engine file, enabling it..."); PluginModule pluginModule = plugin.getModules().registerModule(engineFile); plugin.getModules().enableModule(pluginModule); return true; } catch (Exception error) { Log.error(error, "An unexpected error occurred while downloading nashorn engine:"); return false; } } private static void deleteExistingModule(SuperiorSkyblockPlugin plugin) { PluginModule nashornEngineModule = plugin.getModules().getModule("nashorn-engine"); if (nashornEngineModule == null) return; plugin.getModules().unregisterModule(nashornEngineModule); try { nashornEngineModule.getModuleFile().delete(); } catch (Exception ignored) { } } private static JsonObject readJenkinsJsonAPI() throws IOException { HttpsURLConnection conn = (HttpsURLConnection) new URL(JENKINS_API_ENDPOINT).openConnection(); conn.setRequestMethod("GET"); StringBuilder jsonContents = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { String line; while ((line = reader.readLine()) != null) jsonContents.append(line); } return GSON.fromJson(jsonContents.toString(), JsonObject.class); } private static File downloadEngine(SuperiorSkyblockPlugin plugin, String engineName) throws IOException { String downloadURL = JENKINS_ARTIFACTS_ENDPOINT + engineName; File engineFile = new File(plugin.getDataFolder(), "modules/" + engineName); try (InputStream inputStream = new URL(downloadURL).openStream()) { Files.copy(inputStream, Paths.get(engineFile.toURI())); } return engineFile; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/errors/ManagerLoadException.java ================================================ package com.bgsoftware.superiorskyblock.core.errors; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Bukkit; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Arrays; import java.util.List; @SuppressWarnings("all") public class ManagerLoadException extends Exception { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ErrorLevel errorLevel; public ManagerLoadException(String message, ErrorLevel errorLevel) { super(message == null ? "" : message); this.errorLevel = errorLevel; } public ManagerLoadException(Throwable cause, ErrorLevel errorLevel) { super(cause); this.errorLevel = errorLevel; } public ManagerLoadException(Throwable cause, String message, ErrorLevel errorLevel) { super(message, cause); this.errorLevel = errorLevel; } public static boolean handle(ManagerLoadException error) { error.printStackTrace(); if (error.getErrorLevel() == ErrorLevel.SERVER_SHUTDOWN) { Bukkit.shutdown(); return false; } return true; } public ErrorLevel getErrorLevel() { return errorLevel; } @Override public void printStackTrace() { if (getErrorLevel() == ErrorLevel.CONTINUE) { super.printStackTrace(); return; } StringWriter stackTrace = new StringWriter(); super.printStackTrace(new PrintWriter(stackTrace)); List messageLines = Arrays.asList(getMessage().split("\n")); Log.error("################################################"); Log.error("## ##"); Log.error("## An error occured while loading the plugin! ##"); Log.error("## ##"); Log.error("################################################"); if (!messageLines.isEmpty()) { Log.error(" "); messageLines.forEach(line -> Log.error(line)); } Log.error(" "); Log.error("Stack Trace:"); int linesCounter = 0; for (String stackTraceLine : stackTrace.toString().split("\n")) { if (linesCounter > messageLines.size()) { if (!messageLines.contains(stackTraceLine)) { Log.error(stackTraceLine); } } else { linesCounter++; } } Log.error(" "); Log.error("################################################"); } public enum ErrorLevel { SERVER_SHUTDOWN, CONTINUE } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/EventCallback.java ================================================ package com.bgsoftware.superiorskyblock.core.events; public interface EventCallback { void execute(E gameEvent); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/EventType.java ================================================ package com.bgsoftware.superiorskyblock.core.events; import com.bgsoftware.superiorskyblock.api.objects.Enumerable; public abstract class EventType implements Enumerable { private static int ordinalCounter = 0; private final int ordinal; protected EventType() { this.ordinal = ordinalCounter++; } @Override public int ordinal() { return this.ordinal; } public abstract E createEvent(Args args); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java ================================================ package com.bgsoftware.superiorskyblock.core.events; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class EventsDispatcher, P extends Enum

, E extends IEvent> { protected final EnumerateMap>> callbacks; protected final SuperiorSkyblockPlugin plugin; protected final Class

priorityClass; // This must be thread-safe, as it can be accessed from multiple threads. // We don't actually want it to be thread-safe, but per-thread captured events. // If we don't do that, weird behaviors can occur. For reference: // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2863 private final ThreadLocal> capturedEvents = new ThreadLocal<>(); protected EventsDispatcher(SuperiorSkyblockPlugin plugin, Class

priorityClass, Collection allTypes) { this.plugin = plugin; this.priorityClass = priorityClass; this.callbacks = new EnumerateMap<>(allTypes); } public void registerCallback(L listener, T type, P priority, boolean ignoreCancelled, EventCallback callback) { callbacks.computeIfAbsent(type, t -> new EnumMap<>(this.priorityClass)) .computeIfAbsent(priority, p -> new LinkedList<>()) .add(new RegisteredListener(listener, ignoreCancelled, callback)); } public void clearCallbacks() { this.callbacks.clear(); } public void startCaptureEvents() { this.capturedEvents.set(new LinkedList<>()); } public List stopCaptureEvents() { List capturedEvents = this.capturedEvents.get(); this.capturedEvents.remove(); return capturedEvents; } public void onGameEvent(E event, P priority) { if (event.isCancelled()) return; EnumMap> gameEventCallbacks = callbacks.get(event.getType()); if (gameEventCallbacks != null) { List priorityCallbacks = gameEventCallbacks.get(priority); if (priorityCallbacks != null) { for (RegisteredListener listener : priorityCallbacks) { if (listener.ignoreCancelled && event.isCancelled()) { continue; } try { listener.callback.execute(event); } catch (Throwable error) { Log.error(error, "Could not pass listener: " + listener.listener); } } } } List capturedEvents = this.capturedEvents.get(); if (capturedEvents != null && filterCapturedEvent(event)) capturedEvents.add(event); } protected boolean filterCapturedEvent(E event) { return true; } public Map> getCallbacks(T eventType) { Map> priorityListeners = callbacks.get(eventType); if (priorityListeners == null || priorityListeners.isEmpty()) return Collections.emptyMap(); Map> priorityCallbacks = new EnumMap<>(this.priorityClass); priorityListeners.forEach((eventPriority, listeners) -> { List callbacks = new LinkedList<>(); listeners.forEach(listener -> callbacks.add(listener.callback)); priorityCallbacks.put(eventPriority, callbacks); }); return priorityCallbacks; } protected class RegisteredListener { public final L listener; public final boolean ignoreCancelled; public final EventCallback callback; RegisteredListener(L listener, boolean ignoreCancelled, EventCallback callback) { this.listener = listener; this.ignoreCancelled = ignoreCancelled; this.callback = callback; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/IEvent.java ================================================ package com.bgsoftware.superiorskyblock.core.events; public interface IEvent { T getType(); boolean isCancelled(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/args/IEventArgs.java ================================================ package com.bgsoftware.superiorskyblock.core.events.args; public interface IEventArgs { } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java ================================================ package com.bgsoftware.superiorskyblock.core.events.args; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.util.List; import java.util.Locale; public class PluginEventArgs { private PluginEventArgs() { } public static class Empty extends PluginEventArgs { public static final Empty INSTANCE = new Empty(); private Empty() { } } public static class AttemptPlayerSendMessage extends PluginEventArgs { public SuperiorPlayer receiver; public String messageType; public Object[] args; } public static class BlockStack extends StackedBlockChangeCountArgs { } public static class BlockUnstack extends StackedBlockChangeCountArgs { } public static class IslandBan extends IslandDoActionArgs { public SuperiorPlayer targetPlayer; } public static class IslandBankDeposit extends IslandBankTransactionArgs { } public static class IslandBankWithdraw extends IslandBankTransactionArgs { } public static class IslandBiomeChange extends IslandDoActionArgs { public Biome biome; } public static class IslandChangeBankLimit extends IslandDoActionArgs { public BigDecimal bankLimit; } public static class IslandChangeBlockLimit extends IslandDoActionArgs { public Key block; public int blockLimit; } public static class IslandChangeBorderSize extends IslandDoActionArgs { public int borderSize; } public static class IslandChangeCoopLimit extends IslandDoActionArgs { public int coopLimit; } public static class IslandChangeCropGrowth extends IslandDoActionArgs { public double cropGrowth; } public static class IslandChangeDescription extends IslandDoActionArgs { public String description; } public static class IslandChangeDiscord extends IslandDoActionArgs { public String discord; } public static class IslandChangeEffectLevel extends IslandDoActionArgs { public PotionEffectType effectType; public int effectLevel; } public static class IslandChangeEntityLimit extends IslandDoActionArgs { public Key entity; public int entityLimit; } public static class IslandChangeGeneratorRate extends IslandDoActionArgs { public Key block; public Dimension dimension; public int generatorRate; } public static class IslandChangeLevelBonus extends IslandDoActionArgs { public IslandChangeLevelBonusEvent.Reason reason; public BigDecimal levelBonus; } public static class IslandChangeMembersLimit extends IslandDoActionArgs { public int membersLimit; } public static class IslandChangeMobDrops extends IslandDoActionArgs { public double mobDrops; } public static class IslandChangePaypal extends IslandDoActionArgs { public String paypal; } public static class IslandChangePlayerPrivilege extends IslandDoActionArgs { public SuperiorPlayer privilegedPlayer; public boolean privilegeEnabled; } public static class IslandChangeRoleLimit extends IslandDoActionArgs { public PlayerRole playerRole; public int roleLimit; } public static class IslandChangeSpawnerRates extends IslandDoActionArgs { public double spawnerRates; } public static class IslandChangeWarpCategoryIcon extends WarpCategoryDoActionArgs { public ItemStack icon; } public static class IslandChangeWarpCategorySlot extends WarpCategoryDoActionArgs { public int slot; public int maxSlot; } public static class IslandChangeWarpIcon extends IslandWarpDoActionArgs { public ItemStack icon; } public static class IslandChangeWarpLocation extends IslandWarpDoActionArgs { public Location location; } public static class IslandChangeWarpsLimit extends IslandDoActionArgs { public int warpsLimit; } public static class IslandChangeWorthBonus extends IslandDoActionArgs { public IslandChangeWorthBonusEvent.Reason reason; public BigDecimal worthBonus; } public static class IslandChangeRolePrivilege extends IslandDoActionArgs { public PlayerRole playerRole; } public static class IslandChat extends IslandDoActionArgs { public String message; } public static class IslandChunkReset extends PluginEventArgs { public Island island; public ChunkPosition chunkPosition; } public static class IslandClearFlags extends IslandDoActionArgs { } public static class IslandClearGeneratorRates extends IslandDoActionArgs { public Dimension dimension; } public static class IslandClearPlayerPrivileges extends IslandDoActionArgs { public SuperiorPlayer privilegedPlayer; } public static class IslandClearRatings extends IslandDoActionArgs { } public static class IslandClearRolesPrivileges extends IslandDoActionArgs { } public static class IslandClose extends IslandDoActionArgs { } public static class IslandCloseWarp extends IslandWarpDoActionArgs { } public static class IslandCoopPlayer extends IslandDoActionArgs { public SuperiorPlayer targetPlayer; } public static class IslandCreate extends IslandDoActionArgs { public String schematicName; public boolean canTeleport = true; } public static class IslandCreateWarpCategory extends IslandDoActionArgs { public String categoryName; } public static class IslandCreateWarp extends IslandDoActionArgs { public String warpName; public boolean openToPublic; public Location location; public WarpCategory warpCategory; } public static class IslandDeleteWarp extends IslandWarpDoActionArgs { } public static class IslandDisableFlag extends IslandDoActionArgs { public IslandFlag islandFlag; } public static class IslandDisband extends IslandDoActionArgs { } public static class IslandEnableFlag extends IslandDoActionArgs { public IslandFlag islandFlag; } public static class IslandEnter extends IslandDoActionArgs { public IslandEnterEvent.EnterCause enterCause; } public static class IslandEnterPortal extends IslandDoActionArgs { public PortalType portalType; public Dimension destination; public Schematic schematic; public boolean ignoreInvalidSchematic; } public static class IslandEnterProtected extends IslandEnter { } public static class IslandGenerateBlock extends PluginEventArgs { public Island island; public Location location; public Key block; public boolean placeBlock = true; } public static class IslandHomeTeleport extends IslandDoActionArgs { public Dimension dimension; } public static class IslandInvite extends IslandDoActionArgs { public SuperiorPlayer targetPlayer; } public static class IslandJoin extends IslandDoActionArgs { public IslandJoinEvent.Cause joinCause; } public static class IslandKick extends IslandDoActionArgs { public SuperiorPlayer targetPlayer; } public static class IslandLeave extends IslandDoActionArgs { public IslandLeaveEvent.LeaveCause leaveCause; public Location location; } public static class IslandLeaveProtected extends IslandLeave { } public static class IslandLockWorld extends IslandDoActionArgs { public Dimension dimension; } public static class IslandOpen extends IslandDoActionArgs { } public static class IslandOpenWarp extends IslandWarpDoActionArgs { } public static class IslandQuit extends IslandDoActionArgs { } public static class IslandRate extends IslandDoActionArgs { public SuperiorPlayer ratingPlayer; public Rating rating; } public static class IslandRemoveBlockLimit extends IslandDoActionArgs { public Key block; } public static class IslandRemoveEffect extends IslandDoActionArgs { public PotionEffectType effectType; } public static class IslandRemoveEntityLimit extends IslandDoActionArgs { public Key entity; } public static class IslandRemoveGeneratorRate extends IslandDoActionArgs { public Key block; public Dimension dimension; } public static class IslandRemoveRating extends IslandDoActionArgs { public SuperiorPlayer ratingPlayer; } public static class IslandRemoveRoleLimit extends IslandDoActionArgs { public PlayerRole playerRole; } public static class IslandRemoveVisitorHome extends IslandDoActionArgs { } public static class IslandRename extends IslandDoActionArgs { public String islandName; } public static class IslandRenameWarpCategory extends WarpCategoryDoActionArgs { public String categoryName; } public static class IslandRenameWarp extends IslandWarpDoActionArgs { public String warpName; } public static class IslandRestrictMove extends IslandDoActionArgs { public IslandRestrictMoveEvent.RestrictReason restrictReason; } public static class IslandSchematicPaste extends IslandDoActionArgs { public String schematicName; public Location location; } public static class IslandSetHome extends IslandDoActionArgs { public Location islandHome; public IslandSetHomeEvent.Reason reason; } public static class IslandSetVisitorHome extends IslandDoActionArgs { public Location islandVisitorHome; } public static class IslandTransfer extends IslandDoActionArgs { public SuperiorPlayer previousOwner; } public static class IslandUnban extends IslandDoActionArgs { public SuperiorPlayer unbannedPlayer; } public static class IslandUncoopPlayer extends IslandDoActionArgs { public SuperiorPlayer targetPlayer; public IslandUncoopPlayerEvent.UncoopReason uncoopReason; } public static class IslandUnlockWorld extends IslandDoActionArgs { public Dimension dimension; } public static class IslandUpgrade extends IslandDoActionArgs { public Upgrade upgrade; public UpgradeLevel nextLevel; public List commands; public IslandUpgradeEvent.Cause upgradeCause; public UpgradeCost upgradeCost; } public static class IslandVisitorHomeTeleport extends IslandDoActionArgs { public Dimension dimension; } public static class IslandWarpTeleport extends IslandWarpDoActionArgs { } public static class IslandWorldReset extends IslandDoActionArgs { public Dimension dimension; } public static class IslandWorthCalculated extends IslandDoActionArgs { public BigDecimal islandLevel; public BigDecimal islandWorth; } public static class IslandWorthUpdate extends PluginEventArgs { public Island island; public BigDecimal oldWorth; public BigDecimal oldLevel; public BigDecimal newWorth; public BigDecimal newLevel; } public static class MissionComplete extends MissionArgs { public List itemRewards; public List commandRewards; } public static class MissionReset extends MissionArgs { } public static class PlayerChangeBorderColor extends PlayerDoActionArgs { public BorderColor borderColor; } public static class PlayerChangeLanguage extends PlayerDoActionArgs { public Locale language; } public static class PlayerChangeName extends PlayerDoActionArgs { public String newName; } public static class PlayerChangeRole extends PlayerDoActionArgs { public PlayerRole newRole; } public static class PlayerCloseMenu extends PlayerDoActionArgs { public MenuView menuView; public MenuView newMenuView; } public static class PlayerOpenMenu extends PlayerDoActionArgs { public MenuView menuView; } public static class PlayerReplace extends PlayerDoActionArgs { public SuperiorPlayer newPlayer; } public static class PlayerToggleBlocksStacker extends PlayerDoActionArgs { } public static class PlayerToggleBorder extends PlayerDoActionArgs { } public static class PlayerToggleBypass extends PlayerDoActionArgs { } public static class PlayerToggleFly extends PlayerDoActionArgs { } public static class PlayerTogglePanel extends PlayerDoActionArgs { } public static class PlayerToggleSpy extends PlayerDoActionArgs { } public static class PlayerToggleTeamChat extends PlayerDoActionArgs { } public static class PluginInitialized extends PluginDoActionArgs { } public static class PluginInitialize extends PluginDoActionArgs { public IslandsContainer islandsContainer; public PlayersContainer playersContainer; } public static class PluginLoadData extends PluginDoActionArgs { } public static class PostIslandCreate extends IslandDoActionArgs { } public static class PreIslandCreate extends PluginEventArgs { public SuperiorPlayer superiorPlayer; public String islandName; } public static class SendMessage extends PluginEventArgs { public CommandSender receiver; public String messageType; public IMessageComponent messageComponent; public Object[] args; } private static class StackedBlockChangeCountArgs extends PluginEventArgs { public Block block; public Player player; public int originalCount; public int newCount; } private static class IslandBankTransactionArgs extends PluginEventArgs { public Island island; public SuperiorPlayer superiorPlayer; public BigDecimal amount; public String failureReason; } private static class IslandDoActionArgs extends PluginEventArgs { public Island island; public SuperiorPlayer superiorPlayer; } private static class WarpCategoryDoActionArgs extends IslandDoActionArgs { public WarpCategory warpCategory; } private static class IslandWarpDoActionArgs extends IslandDoActionArgs { public IslandWarp islandWarp; } private static class MissionArgs extends PluginEventArgs { public SuperiorPlayer superiorPlayer; public IMissionsHolder missionsHolder; public Mission mission; } private static class PlayerDoActionArgs extends PluginEventArgs { public SuperiorPlayer superiorPlayer; } private static class PluginDoActionArgs extends PluginEventArgs { public SuperiorSkyblock plugin; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEvent.java ================================================ package com.bgsoftware.superiorskyblock.core.events.plugin; import com.bgsoftware.superiorskyblock.core.events.IEvent; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; public class PluginEvent implements IEvent> { private final PluginEventType type; private final Args args; private boolean cancelled = false; public PluginEvent(PluginEventType type, Args args) { this.type = type; this.args = args; } @Override public PluginEventType getType() { return type; } @Override public boolean isCancelled() { return this.cancelled; } public Args getArgs() { return args; } public void setCancelled() { this.cancelled = true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventPriority.java ================================================ package com.bgsoftware.superiorskyblock.core.events.plugin; public enum PluginEventPriority { NORMAL } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java ================================================ package com.bgsoftware.superiorskyblock.core.events.plugin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.events.AttemptPlayerSendMessageEvent; import com.bgsoftware.superiorskyblock.api.events.BlockStackEvent; import com.bgsoftware.superiorskyblock.api.events.BlockUnstackEvent; import com.bgsoftware.superiorskyblock.api.events.IslandBanEvent; import com.bgsoftware.superiorskyblock.api.events.IslandBankDepositEvent; import com.bgsoftware.superiorskyblock.api.events.IslandBankWithdrawEvent; import com.bgsoftware.superiorskyblock.api.events.IslandBiomeChangeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeBankLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeBlockLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeBorderSizeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeCoopLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeCropGrowthEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeDescriptionEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeDiscordEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeEffectLevelEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeEntityLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeGeneratorRateEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeMembersLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeMobDropsEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangePaypalEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangePlayerPrivilegeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeRoleLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeRolePrivilegeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeSpawnerRatesEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpCategoryIconEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpCategorySlotEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpIconEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpLocationEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpsLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChatEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChunkResetEvent; import com.bgsoftware.superiorskyblock.api.events.IslandClearFlagsEvent; import com.bgsoftware.superiorskyblock.api.events.IslandClearGeneratorRatesEvent; import com.bgsoftware.superiorskyblock.api.events.IslandClearPlayerPrivilegesEvent; import com.bgsoftware.superiorskyblock.api.events.IslandClearRatingsEvent; import com.bgsoftware.superiorskyblock.api.events.IslandClearRolesPrivilegesEvent; import com.bgsoftware.superiorskyblock.api.events.IslandCloseEvent; import com.bgsoftware.superiorskyblock.api.events.IslandCloseWarpEvent; import com.bgsoftware.superiorskyblock.api.events.IslandCoopPlayerEvent; import com.bgsoftware.superiorskyblock.api.events.IslandCreateEvent; import com.bgsoftware.superiorskyblock.api.events.IslandCreateWarpCategoryEvent; import com.bgsoftware.superiorskyblock.api.events.IslandCreateWarpEvent; import com.bgsoftware.superiorskyblock.api.events.IslandDeleteWarpEvent; import com.bgsoftware.superiorskyblock.api.events.IslandDisableFlagEvent; import com.bgsoftware.superiorskyblock.api.events.IslandDisbandEvent; import com.bgsoftware.superiorskyblock.api.events.IslandEnableFlagEvent; import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; import com.bgsoftware.superiorskyblock.api.events.IslandEnterPortalEvent; import com.bgsoftware.superiorskyblock.api.events.IslandEnterProtectedEvent; import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; import com.bgsoftware.superiorskyblock.api.events.IslandHomeTeleportEvent; import com.bgsoftware.superiorskyblock.api.events.IslandInviteEvent; import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; import com.bgsoftware.superiorskyblock.api.events.IslandKickEvent; import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; import com.bgsoftware.superiorskyblock.api.events.IslandLeaveProtectedEvent; import com.bgsoftware.superiorskyblock.api.events.IslandLockWorldEvent; import com.bgsoftware.superiorskyblock.api.events.IslandOpenEvent; import com.bgsoftware.superiorskyblock.api.events.IslandOpenWarpEvent; import com.bgsoftware.superiorskyblock.api.events.IslandQuitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRateEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveBlockLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveEffectEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveEntityLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveGeneratorRateEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveRatingEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveRoleLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveVisitorHomeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRenameEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRenameWarpCategoryEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRenameWarpEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; import com.bgsoftware.superiorskyblock.api.events.IslandSchematicPasteEvent; import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandSetVisitorHomeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandTransferEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUnbanEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUnlockWorldEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandVisitorHomeTeleportEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWarpTeleportEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWorldResetEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWorthCalculatedEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWorthUpdateEvent; import com.bgsoftware.superiorskyblock.api.events.MissionCompleteEvent; import com.bgsoftware.superiorskyblock.api.events.MissionResetEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerChangeBorderColorEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerChangeLanguageEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerChangeNameEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerChangeRoleEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerCloseMenuEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerOpenMenuEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerReplaceEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBlocksStackerEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBorderEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBypassEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerToggleFlyEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerTogglePanelEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerToggleSpyEvent; import com.bgsoftware.superiorskyblock.api.events.PlayerToggleTeamChatEvent; import com.bgsoftware.superiorskyblock.api.events.PluginInitializeEvent; import com.bgsoftware.superiorskyblock.api.events.PluginInitializedEvent; import com.bgsoftware.superiorskyblock.api.events.PluginLoadDataEvent; import com.bgsoftware.superiorskyblock.api.events.PostIslandCreateEvent; import com.bgsoftware.superiorskyblock.api.events.PreIslandCreateEvent; import com.bgsoftware.superiorskyblock.api.events.SendMessageEvent; import com.bgsoftware.superiorskyblock.core.events.EventType; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.AttemptPlayerSendMessage; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockStack; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockUnstack; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.Empty; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBan; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankDeposit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankWithdraw; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBiomeChange; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBankLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBlockLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBorderSize; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCoopLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCropGrowth; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDescription; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDiscord; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEffectLevel; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEntityLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeGeneratorRate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeLevelBonus; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMembersLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMobDrops; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePaypal; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePlayerPrivilege; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRoleLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRolePrivilege; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeSpawnerRates; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategoryIcon; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategorySlot; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpIcon; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpLocation; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpsLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWorthBonus; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChat; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChunkReset; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearFlags; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearGeneratorRates; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearPlayerPrivileges; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRatings; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRolesPrivileges; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClose; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCloseWarp; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCoopPlayer; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarp; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarpCategory; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDeleteWarp; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisableFlag; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisband; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnableFlag; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnter; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterPortal; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterProtected; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandGenerateBlock; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandHomeTeleport; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandInvite; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandJoin; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandKick; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeave; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeaveProtected; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLockWorld; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpen; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpenWarp; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandQuit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveBlockLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEffect; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEntityLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveGeneratorRate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRating; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRoleLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveVisitorHome; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRename; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarp; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarpCategory; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRestrictMove; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSchematicPaste; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetHome; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetVisitorHome; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandTransfer; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnban; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUncoopPlayer; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnlockWorld; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUpgrade; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandVisitorHomeTeleport; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWarpTeleport; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorldReset; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthCalculated; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthUpdate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionComplete; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionReset; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeBorderColor; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeLanguage; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeName; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeRole; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerCloseMenu; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerOpenMenu; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerReplace; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBlocksStacker; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBorder; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBypass; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleFly; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerTogglePanel; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleSpy; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleTeamChat; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialize; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialized; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginLoadData; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PostIslandCreate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PreIslandCreate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.SendMessage; public abstract class PluginEventType extends EventType> { private static final List> ALL_TYPES = new LinkedList<>(); public static final PluginEventType SETTINGS_UPDATE_EVENT = new PluginEventType(null) { @Override public Event createBukkitEvent(Empty args) { return null; } }; public static final PluginEventType COMMANDS_UPDATE_EVENT = new PluginEventType(null) { @Override public Event createBukkitEvent(Empty args) { return null; } }; public static final PluginEventType SPAWN_UPDATE_EVENT = new PluginEventType(null) { @Override public Event createBukkitEvent(Empty args) { return null; } }; public static final PluginEventType WORLD_PROVIDER_UPDATE_EVENT = new PluginEventType(null) { @Override public Event createBukkitEvent(Empty args) { return null; } }; public static final PluginEventType ATTEMPT_PLAYER_SEND_MESSAGE_EVENT = new PluginEventType(AttemptPlayerSendMessageEvent.class) { @Override public Event createBukkitEvent(AttemptPlayerSendMessage args) { return new AttemptPlayerSendMessageEvent(args.receiver, args.messageType, args.args); } }; public static final PluginEventType BLOCK_STACK_EVENT = new PluginEventType(BlockStackEvent.class) { @Override public Event createBukkitEvent(BlockStack args) { return new BlockStackEvent(args.block, args.player, args.originalCount, args.newCount); } }; public static final PluginEventType BLOCK_UNSTACK_EVENT = new PluginEventType(BlockUnstackEvent.class) { @Override public Event createBukkitEvent(BlockUnstack args) { return new BlockUnstackEvent(args.block, args.player, args.originalCount, args.newCount); } }; public static final PluginEventType ISLAND_BAN_EVENT = new PluginEventType(IslandBanEvent.class) { @Override public Event createBukkitEvent(IslandBan args) { return new IslandBanEvent(args.superiorPlayer, args.targetPlayer, args.island); } }; public static final PluginEventType ISLAND_BANK_DEPOSIT_EVENT = new PluginEventType(IslandBankDepositEvent.class) { @Override public Event createBukkitEvent(IslandBankDeposit args) { return new IslandBankDepositEvent(args.superiorPlayer, args.island, args.amount); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().failureReason = ((IslandBankDepositEvent) bukkitEvent).getFailureReason(); } }; public static final PluginEventType ISLAND_BANK_WITHDRAW_EVENT = new PluginEventType(IslandBankWithdrawEvent.class) { @Override public Event createBukkitEvent(IslandBankWithdraw args) { return new IslandBankWithdrawEvent(args.superiorPlayer, args.island, args.amount); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().failureReason = ((IslandBankWithdrawEvent) bukkitEvent).getFailureReason(); } }; public static final PluginEventType ISLAND_BIOME_CHANGE_EVENT = new PluginEventType(IslandBiomeChangeEvent.class) { @Override public Event createBukkitEvent(IslandBiomeChange args) { return new IslandBiomeChangeEvent(args.superiorPlayer, args.island, args.biome); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().biome = ((IslandBiomeChangeEvent) bukkitEvent).getBiome(); } }; public static final PluginEventType ISLAND_CHANGE_BANK_LIMIT_EVENT = new PluginEventType(IslandChangeBankLimitEvent.class) { @Override public Event createBukkitEvent(IslandChangeBankLimit args) { return new IslandChangeBankLimitEvent(args.superiorPlayer, args.island, args.bankLimit); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().bankLimit = ((IslandChangeBankLimitEvent) bukkitEvent).getBankLimit(); } }; public static final PluginEventType ISLAND_CHANGE_BLOCK_LIMIT_EVENT = new PluginEventType(IslandChangeBlockLimitEvent.class) { @Override public Event createBukkitEvent(IslandChangeBlockLimit args) { return new IslandChangeBlockLimitEvent(args.superiorPlayer, args.island, args.block, args.blockLimit); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().blockLimit = ((IslandChangeBlockLimitEvent) bukkitEvent).getBlockLimit(); } }; public static final PluginEventType ISLAND_CHANGE_BORDER_SIZE_EVENT = new PluginEventType(IslandChangeBorderSizeEvent.class) { @Override public Event createBukkitEvent(IslandChangeBorderSize args) { return new IslandChangeBorderSizeEvent(args.superiorPlayer, args.island, args.borderSize); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().borderSize = ((IslandChangeBorderSizeEvent) bukkitEvent).getBorderSize(); } }; public static final PluginEventType ISLAND_CHANGE_COOP_LIMIT_EVENT = new PluginEventType(IslandChangeCoopLimitEvent.class) { @Override public Event createBukkitEvent(IslandChangeCoopLimit args) { return new IslandChangeCoopLimitEvent(args.superiorPlayer, args.island, args.coopLimit); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().coopLimit = ((IslandChangeCoopLimitEvent) bukkitEvent).getCoopLimit(); } }; public static final PluginEventType ISLAND_CHANGE_CROP_GROWTH_EVENT = new PluginEventType(IslandChangeCropGrowthEvent.class) { @Override public Event createBukkitEvent(IslandChangeCropGrowth args) { return new IslandChangeCropGrowthEvent(args.superiorPlayer, args.island, args.cropGrowth); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().cropGrowth = ((IslandChangeCropGrowthEvent) bukkitEvent).getCropGrowth(); } }; public static final PluginEventType ISLAND_CHANGE_DESCRIPTION_EVENT = new PluginEventType(IslandChangeDescriptionEvent.class) { @Override public Event createBukkitEvent(IslandChangeDescription args) { return new IslandChangeDescriptionEvent(args.island, args.superiorPlayer, args.description); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().description = ((IslandChangeDescriptionEvent) bukkitEvent).getDescription(); } }; public static final PluginEventType ISLAND_CHANGE_DISCORD_EVENT = new PluginEventType(IslandChangeDiscordEvent.class) { @Override public Event createBukkitEvent(IslandChangeDiscord args) { return new IslandChangeDiscordEvent(args.superiorPlayer, args.island, args.discord); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().discord = ((IslandChangeDiscordEvent) bukkitEvent).getDiscord(); } }; public static final PluginEventType ISLAND_CHANGE_EFFECT_LEVEL_EVENT = new PluginEventType(IslandChangeEffectLevelEvent.class) { @Override public Event createBukkitEvent(IslandChangeEffectLevel args) { return new IslandChangeEffectLevelEvent(args.superiorPlayer, args.island, args.effectType, args.effectLevel); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().effectLevel = ((IslandChangeEffectLevelEvent) bukkitEvent).getEffectLevel(); } }; public static final PluginEventType ISLAND_CHANGE_ENTITY_LIMIT_EVENT = new PluginEventType(IslandChangeEntityLimitEvent.class) { @Override public Event createBukkitEvent(IslandChangeEntityLimit args) { return new IslandChangeEntityLimitEvent(args.superiorPlayer, args.island, args.entity, args.entityLimit); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().entityLimit = ((IslandChangeEntityLimitEvent) bukkitEvent).getEntityLimit(); } }; public static final PluginEventType ISLAND_CHANGE_GENERATOR_RATE_EVENT = new PluginEventType(IslandChangeGeneratorRateEvent.class) { @Override public Event createBukkitEvent(IslandChangeGeneratorRate args) { return new IslandChangeGeneratorRateEvent(args.superiorPlayer, args.island, args.block, args.dimension, args.generatorRate); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().generatorRate = ((IslandChangeGeneratorRateEvent) bukkitEvent).getGeneratorRate(); } }; public static final PluginEventType ISLAND_CHANGE_LEVEL_BONUS_EVENT = new PluginEventType(IslandChangeLevelBonusEvent.class) { @Override public Event createBukkitEvent(IslandChangeLevelBonus args) { return new IslandChangeLevelBonusEvent(args.superiorPlayer, args.island, args.reason, args.levelBonus); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().levelBonus = ((IslandChangeLevelBonusEvent) bukkitEvent).getLevelBonus(); } }; public static final PluginEventType ISLAND_CHANGE_MEMBERS_LIMIT_EVENT = new PluginEventType(IslandChangeMembersLimitEvent.class) { @Override public Event createBukkitEvent(IslandChangeMembersLimit args) { return new IslandChangeMembersLimitEvent(args.superiorPlayer, args.island, args.membersLimit); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().membersLimit = ((IslandChangeMembersLimitEvent) bukkitEvent).getMembersLimit(); } }; public static final PluginEventType ISLAND_CHANGE_MOB_DROPS_EVENT = new PluginEventType(IslandChangeMobDropsEvent.class) { @Override public Event createBukkitEvent(IslandChangeMobDrops args) { return new IslandChangeMobDropsEvent(args.superiorPlayer, args.island, args.mobDrops); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().mobDrops = ((IslandChangeMobDropsEvent) bukkitEvent).getMobDrops(); } }; public static final PluginEventType ISLAND_CHANGE_PAYPAL_EVENT = new PluginEventType(IslandChangePaypalEvent.class) { @Override public Event createBukkitEvent(IslandChangePaypal args) { return new IslandChangePaypalEvent(args.superiorPlayer, args.island, args.paypal); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().paypal = ((IslandChangePaypalEvent) bukkitEvent).getPaypal(); } }; public static final PluginEventType ISLAND_CHANGE_PLAYER_PRIVILEGE_EVENT = new PluginEventType(IslandChangePlayerPrivilegeEvent.class) { @Override public Event createBukkitEvent(IslandChangePlayerPrivilege args) { return new IslandChangePlayerPrivilegeEvent(args.island, args.superiorPlayer, args.privilegedPlayer, args.privilegeEnabled); } }; public static final PluginEventType ISLAND_CHANGE_ROLE_LIMIT_EVENT = new PluginEventType(IslandChangeRoleLimitEvent.class) { @Override public Event createBukkitEvent(IslandChangeRoleLimit args) { return new IslandChangeRoleLimitEvent(args.superiorPlayer, args.island, args.playerRole, args.roleLimit); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().roleLimit = ((IslandChangeRoleLimitEvent) bukkitEvent).getRoleLimit(); } }; public static final PluginEventType ISLAND_CHANGE_SPAWNER_RATES_EVENT = new PluginEventType(IslandChangeSpawnerRatesEvent.class) { @Override public Event createBukkitEvent(IslandChangeSpawnerRates args) { return new IslandChangeSpawnerRatesEvent(args.superiorPlayer, args.island, args.spawnerRates); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().spawnerRates = ((IslandChangeSpawnerRatesEvent) bukkitEvent).getSpawnerRates(); } }; public static final PluginEventType ISLAND_CHANGE_WARP_CATEGORY_ICON_EVENT = new PluginEventType(IslandChangeWarpIconEvent.class) { @Override public Event createBukkitEvent(IslandChangeWarpCategoryIcon args) { return new IslandChangeWarpCategoryIconEvent(args.superiorPlayer, args.island, args.warpCategory, args.icon); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().icon = ((IslandChangeWarpCategoryIconEvent) bukkitEvent).getIcon(); } }; public static final PluginEventType ISLAND_CHANGE_WARP_CATEGORY_SLOT_EVENT = new PluginEventType(IslandChangeWarpCategorySlotEvent.class) { @Override public Event createBukkitEvent(IslandChangeWarpCategorySlot args) { return new IslandChangeWarpCategorySlotEvent(args.superiorPlayer, args.island, args.warpCategory, args.slot, args.maxSlot); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().slot = ((IslandChangeWarpCategorySlotEvent) bukkitEvent).getSlot(); } }; public static final PluginEventType ISLAND_CHANGE_WARP_ICON_EVENT = new PluginEventType(IslandChangeWarpIconEvent.class) { @Override public Event createBukkitEvent(IslandChangeWarpIcon args) { return new IslandChangeWarpIconEvent(args.superiorPlayer, args.island, args.islandWarp, args.icon); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().icon = ((IslandChangeWarpIconEvent) bukkitEvent).getIcon(); } }; public static final PluginEventType ISLAND_CHANGE_WARP_LOCATION_EVENT = new PluginEventType(IslandChangeWarpLocationEvent.class) { @Override public Event createBukkitEvent(IslandChangeWarpLocation args) { return new IslandChangeWarpLocationEvent(args.superiorPlayer, args.island, args.islandWarp, args.location); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().location = ((IslandChangeWarpLocationEvent) bukkitEvent).getLocation(); } }; public static final PluginEventType ISLAND_CHANGE_WARPS_LIMIT_EVENT = new PluginEventType(IslandChangeWarpsLimitEvent.class) { @Override public Event createBukkitEvent(IslandChangeWarpsLimit args) { return new IslandChangeWarpsLimitEvent(args.superiorPlayer, args.island, args.warpsLimit); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().warpsLimit = ((IslandChangeWarpsLimitEvent) bukkitEvent).getWarpsLimit(); } }; public static final PluginEventType ISLAND_CHANGE_WORTH_BONUS_EVENT = new PluginEventType(IslandChangeWorthBonusEvent.class) { @Override public Event createBukkitEvent(IslandChangeWorthBonus args) { return new IslandChangeWorthBonusEvent(args.superiorPlayer, args.island, args.reason, args.worthBonus); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().worthBonus = ((IslandChangeWorthBonusEvent) bukkitEvent).getWorthBonus(); } }; public static final PluginEventType ISLAND_CHANGE_ROLE_PRIVILEGE_EVENT = new PluginEventType(IslandChangeRolePrivilegeEvent.class) { @Override public Event createBukkitEvent(IslandChangeRolePrivilege args) { return new IslandChangeRolePrivilegeEvent(args.island, args.superiorPlayer, args.playerRole); } }; public static final PluginEventType ISLAND_CHAT_EVENT = new PluginEventType(IslandChatEvent.class) { @Override public Event createBukkitEvent(IslandChat args) { return new IslandChatEvent(args.island, args.superiorPlayer, args.message); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().message = ((IslandChatEvent) bukkitEvent).getMessage(); } }; public static final PluginEventType ISLAND_CHUNK_RESET_EVENT = new PluginEventType(IslandChunkResetEvent.class) { @Override public Event createBukkitEvent(IslandChunkReset args) { return new IslandChunkResetEvent(args.island, args.chunkPosition.getWorld(), args.chunkPosition.getX(), args.chunkPosition.getZ()); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { // Do nothing } }; public static final PluginEventType ISLAND_CLEAR_GENERATOR_RATES_EVENT = new PluginEventType(IslandClearGeneratorRatesEvent.class) { @Override public Event createBukkitEvent(IslandClearGeneratorRates args) { return new IslandClearGeneratorRatesEvent(args.superiorPlayer, args.island, args.dimension); } }; public static final PluginEventType ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT = new PluginEventType(IslandClearPlayerPrivilegesEvent.class) { @Override public Event createBukkitEvent(IslandClearPlayerPrivileges args) { return new IslandClearPlayerPrivilegesEvent(args.island, args.superiorPlayer, args.privilegedPlayer); } }; public static final PluginEventType ISLAND_CLEAR_RATINGS_EVENT = new PluginEventType(IslandClearRatingsEvent.class) { @Override public Event createBukkitEvent(IslandClearRatings args) { return new IslandClearRatingsEvent(args.superiorPlayer, args.island); } }; public static final PluginEventType ISLAND_CLEAR_ROLES_PRIVILEGES_EVENT = new PluginEventType(IslandClearRolesPrivilegesEvent.class) { @Override public Event createBukkitEvent(IslandClearRolesPrivileges args) { return new IslandClearRolesPrivilegesEvent(args.island, args.superiorPlayer); } }; public static final PluginEventType ISLAND_CLOSE_EVENT = new PluginEventType(IslandCloseEvent.class) { @Override public Event createBukkitEvent(IslandClose args) { return new IslandCloseEvent(args.superiorPlayer, args.island); } }; public static final PluginEventType ISLAND_CLOSE_WARP_EVENT = new PluginEventType(IslandCloseWarpEvent.class) { @Override public Event createBukkitEvent(IslandCloseWarp args) { return new IslandCloseWarpEvent(args.superiorPlayer, args.island, args.islandWarp); } }; public static final PluginEventType ISLAND_COOP_PLAYER_EVENT = new PluginEventType(IslandCoopPlayerEvent.class) { @Override public Event createBukkitEvent(IslandCoopPlayer args) { return new IslandCoopPlayerEvent(args.island, args.superiorPlayer, args.targetPlayer); } }; public static final PluginEventType ISLAND_CREATE_EVENT = new PluginEventType(IslandCreateEvent.class) { @Override public Event createBukkitEvent(IslandCreate args) { return new IslandCreateEvent(args.superiorPlayer, args.island, args.schematicName, args.canTeleport); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().canTeleport = ((IslandCreateEvent) bukkitEvent).canTeleport(); } }; public static final PluginEventType ISLAND_CREATE_WARP_CATEGORY_EVENT = new PluginEventType(IslandCreateWarpCategoryEvent.class) { @Override public Event createBukkitEvent(IslandCreateWarpCategory args) { return new IslandCreateWarpCategoryEvent(args.superiorPlayer, args.island, args.categoryName); } }; public static final PluginEventType ISLAND_CREATE_WARP_EVENT = new PluginEventType(IslandCreateWarpEvent.class) { @Override public Event createBukkitEvent(IslandCreateWarp args) { return new IslandCreateWarpEvent(args.superiorPlayer, args.island, args.warpName, args.location, args.openToPublic, args.warpCategory); } }; public static final PluginEventType ISLAND_DELETE_WARP_EVENT = new PluginEventType(IslandDeleteWarpEvent.class) { @Override public Event createBukkitEvent(IslandDeleteWarp args) { return new IslandDeleteWarpEvent(args.superiorPlayer, args.island, args.islandWarp); } }; public static final PluginEventType ISLAND_DISABLE_FLAG_EVENT = new PluginEventType(IslandDisableFlagEvent.class) { @Override public Event createBukkitEvent(IslandDisableFlag args) { return new IslandDisableFlagEvent(args.superiorPlayer, args.island, args.islandFlag); } }; public static final PluginEventType ISLAND_DISBAND_EVENT = new PluginEventType(IslandDisbandEvent.class) { @Override public Event createBukkitEvent(IslandDisband args) { return new IslandDisbandEvent(args.superiorPlayer, args.island); } }; public static final PluginEventType ISLAND_ENABLE_FLAG_EVENT = new PluginEventType(IslandEnableFlagEvent.class) { @Override public Event createBukkitEvent(IslandEnableFlag args) { return new IslandEnableFlagEvent(args.superiorPlayer, args.island, args.islandFlag); } }; public static final PluginEventType ISLAND_CLEAR_FLAGS_EVENT = new PluginEventType(IslandClearFlagsEvent.class) { @Override public Event createBukkitEvent(IslandClearFlags args) { return new IslandClearFlagsEvent(args.island, args.superiorPlayer); } }; public static final PluginEventType ISLAND_ENTER_EVENT = new PluginEventType(IslandEnterEvent.class) { @Override public Event createBukkitEvent(IslandEnter args) { return new IslandEnterEvent(args.superiorPlayer, args.island, args.enterCause); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); IslandEnterEvent islandEnterEvent = (IslandEnterEvent) bukkitEvent; if (islandEnterEvent.isCancelled() && islandEnterEvent.getCancelTeleport() != null) pluginEvent.getArgs().superiorPlayer.teleport(islandEnterEvent.getCancelTeleport()); } }; public static final PluginEventType ISLAND_ENTER_PORTAL_EVENT = new PluginEventType(IslandEnterPortalEvent.class) { @Override public Event createBukkitEvent(IslandEnterPortal args) { return new IslandEnterPortalEvent(args.island, args.superiorPlayer, args.portalType, args.destination, args.schematic, args.ignoreInvalidSchematic); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().destination = ((IslandEnterPortalEvent) bukkitEvent).getDestinationDimension(); pluginEvent.getArgs().schematic = ((IslandEnterPortalEvent) bukkitEvent).getSchematic(); pluginEvent.getArgs().ignoreInvalidSchematic = ((IslandEnterPortalEvent) bukkitEvent).isIgnoreInvalidSchematic(); } }; public static final PluginEventType ISLAND_ENTER_PROTECTED_EVENT = new PluginEventType(IslandEnterProtectedEvent.class) { @Override public Event createBukkitEvent(IslandEnterProtected args) { return new IslandEnterProtectedEvent(args.superiorPlayer, args.island, args.enterCause); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); IslandEnterProtectedEvent islandEnterProtectedEvent = (IslandEnterProtectedEvent) bukkitEvent; if (islandEnterProtectedEvent.isCancelled() && islandEnterProtectedEvent.getCancelTeleport() != null) pluginEvent.getArgs().superiorPlayer.teleport(islandEnterProtectedEvent.getCancelTeleport()); } }; public static final PluginEventType ISLAND_GENERATE_BLOCK_EVENT = new PluginEventType(IslandGenerateBlockEvent.class) { @Override public Event createBukkitEvent(IslandGenerateBlock args) { return new IslandGenerateBlockEvent(args.island, args.location, args.block); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().block = ((IslandGenerateBlockEvent) bukkitEvent).getBlock(); pluginEvent.getArgs().placeBlock = ((IslandGenerateBlockEvent) bukkitEvent).isPlaceBlock(); } }; public static final PluginEventType ISLAND_HOME_TELEPORT_EVENT = new PluginEventType(IslandHomeTeleportEvent.class) { @Override public Event createBukkitEvent(IslandHomeTeleport args) { return new IslandHomeTeleportEvent(args.island, args.superiorPlayer, args.dimension); } }; public static final PluginEventType ISLAND_INVITE_EVENT = new PluginEventType(IslandInviteEvent.class) { @Override public Event createBukkitEvent(IslandInvite args) { return new IslandInviteEvent(args.superiorPlayer, args.targetPlayer, args.island); } }; public static final PluginEventType ISLAND_JOIN_EVENT = new PluginEventType(IslandJoinEvent.class) { @Override public Event createBukkitEvent(IslandJoin args) { return new IslandJoinEvent(args.superiorPlayer, args.island, args.joinCause); } }; public static final PluginEventType ISLAND_KICK_EVENT = new PluginEventType(IslandKickEvent.class) { @Override public Event createBukkitEvent(IslandKick args) { return new IslandKickEvent(args.superiorPlayer, args.targetPlayer, args.island); } }; public static final PluginEventType ISLAND_LEAVE_EVENT = new PluginEventType(IslandLeaveEvent.class) { @Override public Event createBukkitEvent(IslandLeave args) { return new IslandLeaveEvent(args.superiorPlayer, args.island, args.leaveCause, args.location); } }; public static final PluginEventType ISLAND_LEAVE_PROTECTED_EVENT = new PluginEventType(IslandLeaveProtectedEvent.class) { @Override public Event createBukkitEvent(IslandLeaveProtected args) { return new IslandLeaveEvent(args.superiorPlayer, args.island, args.leaveCause, args.location); } }; public static final PluginEventType ISLAND_LOCK_WORLD_EVENT = new PluginEventType(IslandLockWorldEvent.class) { @Override public Event createBukkitEvent(IslandLockWorld args) { return new IslandLockWorldEvent(args.island, args.dimension); } }; public static final PluginEventType ISLAND_OPEN_EVENT = new PluginEventType(IslandOpenEvent.class) { @Override public Event createBukkitEvent(IslandOpen args) { return new IslandOpenEvent(args.superiorPlayer, args.island); } }; public static final PluginEventType ISLAND_OPEN_WARP_EVENT = new PluginEventType(IslandOpenWarpEvent.class) { @Override public Event createBukkitEvent(IslandOpenWarp args) { return new IslandOpenWarpEvent(args.superiorPlayer, args.island, args.islandWarp); } }; public static final PluginEventType ISLAND_QUIT_EVENT = new PluginEventType(IslandQuitEvent.class) { @Override public Event createBukkitEvent(IslandQuit args) { return new IslandQuitEvent(args.superiorPlayer, args.island); } }; public static final PluginEventType ISLAND_RATE_EVENT = new PluginEventType(IslandRateEvent.class) { @Override public Event createBukkitEvent(IslandRate args) { return new IslandRateEvent(args.superiorPlayer, args.ratingPlayer, args.island, args.rating); } }; public static final PluginEventType ISLAND_REMOVE_BLOCK_LIMIT_EVENT = new PluginEventType(IslandRemoveBlockLimitEvent.class) { @Override public Event createBukkitEvent(IslandRemoveBlockLimit args) { return new IslandRemoveBlockLimitEvent(args.superiorPlayer, args.island, args.block); } }; public static final PluginEventType ISLAND_REMOVE_EFFECT_EVENT = new PluginEventType(IslandRemoveEffectEvent.class) { @Override public Event createBukkitEvent(IslandRemoveEffect args) { return new IslandRemoveEffectEvent(args.superiorPlayer, args.island, args.effectType); } }; public static final PluginEventType ISLAND_REMOVE_ENTITY_LIMIT_EVENT = new PluginEventType(IslandRemoveEntityLimitEvent.class) { @Override public Event createBukkitEvent(IslandRemoveEntityLimit args) { return new IslandRemoveEntityLimitEvent(args.superiorPlayer, args.island, args.entity); } }; public static final PluginEventType ISLAND_REMOVE_GENERATOR_RATE_EVENT = new PluginEventType(IslandRemoveGeneratorRateEvent.class) { @Override public Event createBukkitEvent(IslandRemoveGeneratorRate args) { return new IslandRemoveGeneratorRateEvent(args.superiorPlayer, args.island, args.block, args.dimension); } }; public static final PluginEventType ISLAND_REMOVE_RATING_EVENT = new PluginEventType(IslandRemoveRatingEvent.class) { @Override public Event createBukkitEvent(IslandRemoveRating args) { return new IslandRemoveRatingEvent(args.superiorPlayer, args.ratingPlayer, args.island); } }; public static final PluginEventType ISLAND_REMOVE_ROLE_LIMIT_EVENT = new PluginEventType(IslandRemoveRoleLimitEvent.class) { @Override public Event createBukkitEvent(IslandRemoveRoleLimit args) { return new IslandRemoveRoleLimitEvent(args.superiorPlayer, args.island, args.playerRole); } }; public static final PluginEventType ISLAND_REMOVE_VISITOR_HOME_EVENT = new PluginEventType(IslandRemoveVisitorHomeEvent.class) { @Override public Event createBukkitEvent(IslandRemoveVisitorHome args) { return new IslandRemoveVisitorHomeEvent(args.superiorPlayer, args.island); } }; public static final PluginEventType ISLAND_RENAME_EVENT = new PluginEventType(IslandRenameEvent.class) { @Override public Event createBukkitEvent(IslandRename args) { return new IslandRenameEvent(args.island, args.superiorPlayer, args.islandName); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().islandName = ((IslandRenameEvent) bukkitEvent).getIslandName(); } }; public static final PluginEventType ISLAND_RENAME_WARP_CATEGORY_EVENT = new PluginEventType(IslandRenameWarpCategoryEvent.class) { @Override public Event createBukkitEvent(IslandRenameWarpCategory args) { return new IslandRenameWarpCategoryEvent(args.superiorPlayer, args.island, args.warpCategory, args.categoryName); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().categoryName = ((IslandRenameWarpCategoryEvent) bukkitEvent).getCategoryName(); } }; public static final PluginEventType ISLAND_RENAME_WARP_EVENT = new PluginEventType(IslandRenameWarpEvent.class) { @Override public Event createBukkitEvent(IslandRenameWarp args) { return new IslandRenameWarpEvent(args.superiorPlayer, args.island, args.islandWarp, args.warpName); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().warpName = ((IslandRenameWarpEvent) bukkitEvent).getWarpName(); } }; public static final PluginEventType ISLAND_RESTRICT_MOVE_EVENT = new PluginEventType(IslandRestrictMoveEvent.class) { @Override public Event createBukkitEvent(IslandRestrictMove args) { return new IslandRestrictMoveEvent(args.superiorPlayer, args.restrictReason); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { // Do nothing } }; public static final PluginEventType ISLAND_SCHEMATIC_PASTE_EVENT = new PluginEventType(IslandSchematicPasteEvent.class) { @Override public Event createBukkitEvent(IslandSchematicPaste args) { return new IslandSchematicPasteEvent(args.island, args.schematicName, args.location); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { // Do nothing } }; public static final PluginEventType ISLAND_SET_HOME_EVENT = new PluginEventType(IslandSetHomeEvent.class) { @Override public Event createBukkitEvent(IslandSetHome args) { return new IslandSetHomeEvent(args.island, args.islandHome, args.reason, args.superiorPlayer); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().islandHome = ((IslandSetHomeEvent) bukkitEvent).getIslandHome(); } }; public static final PluginEventType ISLAND_SET_VISITOR_HOME_EVENT = new PluginEventType(IslandSetVisitorHomeEvent.class) { @Override public Event createBukkitEvent(IslandSetVisitorHome args) { return new IslandSetVisitorHomeEvent(args.superiorPlayer, args.island, args.islandVisitorHome); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().islandVisitorHome = ((IslandSetVisitorHomeEvent) bukkitEvent).getIslandVisitorHome(); } }; public static final PluginEventType ISLAND_TRANSFER_EVENT = new PluginEventType(IslandTransferEvent.class) { @Override public Event createBukkitEvent(IslandTransfer args) { return new IslandTransferEvent(args.island, args.previousOwner, args.superiorPlayer); } }; public static final PluginEventType ISLAND_UNBAN_EVENT = new PluginEventType(IslandUnbanEvent.class) { @Override public Event createBukkitEvent(IslandUnban args) { return new IslandUnbanEvent(args.superiorPlayer, args.unbannedPlayer, args.island); } }; public static final PluginEventType ISLAND_UNCOOP_PLAYER_EVENT = new PluginEventType(IslandUncoopPlayerEvent.class) { @Override public Event createBukkitEvent(IslandUncoopPlayer args) { return new IslandUncoopPlayerEvent(args.island, args.superiorPlayer, args.targetPlayer, args.uncoopReason); } }; public static final PluginEventType ISLAND_UNLOCK_WORLD_EVENT = new PluginEventType(IslandUnlockWorldEvent.class) { @Override public Event createBukkitEvent(IslandUnlockWorld args) { return new IslandUnlockWorldEvent(args.island, args.dimension); } }; public static final PluginEventType ISLAND_UPGRADE_EVENT = new PluginEventType(IslandUpgradeEvent.class) { @Override public Event createBukkitEvent(IslandUpgrade args) { return new IslandUpgradeEvent(args.superiorPlayer, args.island, args.upgrade, args.nextLevel, args.commands, args.upgradeCause, args.upgradeCost); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().commands = ((IslandUpgradeEvent) bukkitEvent).getCommands(); pluginEvent.getArgs().upgradeCost = ((IslandUpgradeEvent) bukkitEvent).getUpgradeCost(); } }; public static final PluginEventType ISLAND_VISITOR_HOME_TELEPORT_EVENT = new PluginEventType(IslandVisitorHomeTeleportEvent.class) { @Override public Event createBukkitEvent(IslandVisitorHomeTeleport args) { return new IslandVisitorHomeTeleportEvent(args.island, args.superiorPlayer, args.dimension); } }; public static final PluginEventType ISLAND_WARP_TELEPORT_EVENT = new PluginEventType(IslandWarpTeleportEvent.class) { @Override public Event createBukkitEvent(IslandWarpTeleport args) { return new IslandWarpTeleportEvent(args.island, args.superiorPlayer, args.islandWarp); } }; public static final PluginEventType ISLAND_WORLD_RESET_EVENT = new PluginEventType(IslandWorldResetEvent.class) { @Override public Event createBukkitEvent(IslandWorldReset args) { return new IslandWorldResetEvent(args.superiorPlayer, args.island, args.dimension); } }; public static final PluginEventType ISLAND_WORTH_CALCULATED_EVENT = new PluginEventType(IslandWorthCalculatedEvent.class) { @Override public Event createBukkitEvent(IslandWorthCalculated args) { return new IslandWorthCalculatedEvent(args.island, args.superiorPlayer, args.islandLevel, args.islandWorth); } }; public static final PluginEventType ISLAND_WORTH_UPDATE_EVENT = new PluginEventType(IslandWorthUpdateEvent.class) { @Override public Event createBukkitEvent(IslandWorthUpdate args) { return new IslandWorthUpdateEvent(args.island, args.oldWorth, args.oldLevel, args.newWorth, args.newLevel); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { // Do nothing } }; public static final PluginEventType MISSION_COMPLETE_EVENT = new PluginEventType(MissionCompleteEvent.class) { @Override public Event createBukkitEvent(MissionComplete args) { return new MissionCompleteEvent(args.superiorPlayer, args.missionsHolder, args.mission, args.itemRewards, args.commandRewards); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().itemRewards = ((MissionCompleteEvent) bukkitEvent).getItemRewards(); pluginEvent.getArgs().commandRewards = ((MissionCompleteEvent) bukkitEvent).getCommandRewards(); } }; public static final PluginEventType MISSION_RESET_EVENT = new PluginEventType(MissionResetEvent.class) { @Override public Event createBukkitEvent(MissionReset args) { return new MissionResetEvent(args.superiorPlayer, args.missionsHolder, args.mission); } }; public static final PluginEventType PLAYER_CHANGE_BORDER_COLOR_EVENT = new PluginEventType(PlayerChangeBorderColorEvent.class) { @Override public Event createBukkitEvent(PlayerChangeBorderColor args) { return new PlayerChangeBorderColorEvent(args.superiorPlayer, args.borderColor); } }; public static final PluginEventType PLAYER_CHANGE_LANGUAGE_EVENT = new PluginEventType(PlayerChangeLanguageEvent.class) { @Override public Event createBukkitEvent(PlayerChangeLanguage args) { return new PlayerChangeLanguageEvent(args.superiorPlayer, args.language); } }; public static final PluginEventType PLAYER_CHANGE_NAME_EVENT = new PluginEventType(PlayerChangeNameEvent.class) { @Override public Event createBukkitEvent(PlayerChangeName args) { return new PlayerChangeNameEvent(args.superiorPlayer, args.newName); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { // Do nothing } }; public static final PluginEventType PLAYER_CHANGE_ROLE_EVENT = new PluginEventType(PlayerChangeRoleEvent.class) { @Override public Event createBukkitEvent(PlayerChangeRole args) { return new PlayerChangeRoleEvent(args.superiorPlayer, args.newRole); } }; public static final PluginEventType PLAYER_CLOSE_MENU_EVENT = new PluginEventType(PlayerCloseMenuEvent.class) { @Override public Event createBukkitEvent(PlayerCloseMenu args) { return new PlayerCloseMenuEvent(args.superiorPlayer, args.menuView, args.newMenuView); } }; public static final PluginEventType PLAYER_OPEN_MENU_EVENT = new PluginEventType(PlayerOpenMenuEvent.class) { @Override public Event createBukkitEvent(PlayerOpenMenu args) { return new PlayerOpenMenuEvent(args.superiorPlayer, args.menuView); } }; public static final PluginEventType PLAYER_REPLACE_EVENT = new PluginEventType(PlayerReplaceEvent.class) { @Override public Event createBukkitEvent(PlayerReplace args) { return new PlayerReplaceEvent(args.superiorPlayer, args.newPlayer); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { // Do nothing } }; public static final PluginEventType PLAYER_TOGGLE_BLOCKS_STACKER_EVENT = new PluginEventType(PlayerToggleBlocksStackerEvent.class) { @Override public Event createBukkitEvent(PlayerToggleBlocksStacker args) { return new PlayerToggleBlocksStackerEvent(args.superiorPlayer); } }; public static final PluginEventType PLAYER_TOGGLE_BORDER_EVENT = new PluginEventType(PlayerToggleBorderEvent.class) { @Override public Event createBukkitEvent(PlayerToggleBorder args) { return new PlayerToggleBorderEvent(args.superiorPlayer); } }; public static final PluginEventType PLAYER_TOGGLE_BYPASS_EVENT = new PluginEventType(PlayerToggleBypassEvent.class) { @Override public Event createBukkitEvent(PlayerToggleBypass args) { return new PlayerToggleBypassEvent(args.superiorPlayer); } }; public static final PluginEventType PLAYER_TOGGLE_FLY_EVENT = new PluginEventType(PlayerToggleFlyEvent.class) { @Override public Event createBukkitEvent(PlayerToggleFly args) { return new PlayerToggleFlyEvent(args.superiorPlayer); } }; public static final PluginEventType PLAYER_TOGGLE_PANEL_EVENT = new PluginEventType(PlayerTogglePanelEvent.class) { @Override public Event createBukkitEvent(PlayerTogglePanel args) { return new PlayerTogglePanelEvent(args.superiorPlayer); } }; public static final PluginEventType PLAYER_TOGGLE_SPY_EVENT = new PluginEventType(PlayerToggleSpyEvent.class) { @Override public Event createBukkitEvent(PlayerToggleSpy args) { return new PlayerToggleSpyEvent(args.superiorPlayer); } }; public static final PluginEventType PLAYER_TOGGLE_TEAM_CHAT_EVENT = new PluginEventType(PlayerToggleTeamChatEvent.class) { @Override public Event createBukkitEvent(PlayerToggleTeamChat args) { return new PlayerToggleTeamChatEvent(args.superiorPlayer); } }; public static final PluginEventType PLUGIN_INITIALIZED_EVENT = new PluginEventType(PluginInitializedEvent.class) { @Override public Event createBukkitEvent(PluginInitialized args) { return new PluginInitializedEvent(args.plugin); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { // Do nothing } }; public static final PluginEventType PLUGIN_INITIALIZE_EVENT = new PluginEventType(PluginInitializeEvent.class) { @Override public Event createBukkitEvent(PluginInitialize args) { return new PluginInitializeEvent(args.plugin); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { pluginEvent.getArgs().islandsContainer = ((PluginInitializeEvent) bukkitEvent).getIslandsContainer(); pluginEvent.getArgs().playersContainer = ((PluginInitializeEvent) bukkitEvent).getPlayersContainer(); } }; public static final PluginEventType PLUGIN_LOAD_DATA_EVENT = new PluginEventType(null) { @Override public Event createBukkitEvent(PluginLoadData args) { return new PluginLoadDataEvent(args.plugin); } }; public static final PluginEventType POST_ISLAND_CREATE_EVENT = new PluginEventType(PostIslandCreateEvent.class) { @Override public Event createBukkitEvent(PostIslandCreate args) { return new PostIslandCreateEvent(args.superiorPlayer, args.island); } }; public static final PluginEventType PRE_ISLAND_CREATE_EVENT = new PluginEventType(PreIslandCreateEvent.class) { @Override public Event createBukkitEvent(PreIslandCreate args) { return new PreIslandCreateEvent(args.superiorPlayer, args.islandName); } }; public static final PluginEventType SEND_MESSAGE_EVENT = new PluginEventType(SendMessageEvent.class) { @Override public Event createBukkitEvent(SendMessage args) { return new SendMessageEvent(args.receiver, args.messageType, args.messageComponent, args.args); } @Override public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); pluginEvent.getArgs().messageComponent = ((SendMessageEvent) bukkitEvent).getMessageComponent(); } }; private final String bukkitEventName; private PluginEventType(@Nullable Class bukkitEventClass) { this.bukkitEventName = bukkitEventClass == null ? null : bukkitEventClass.getSimpleName().toLowerCase(Locale.ENGLISH); ALL_TYPES.add(this); } @Override public PluginEvent createEvent(Args args) { return new PluginEvent<>(this, args); } @Nullable public String getBukkitEventName() { return bukkitEventName; } @Nullable public abstract Event createBukkitEvent(Args args); public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { if (bukkitEvent instanceof Cancellable && ((Cancellable) bukkitEvent).isCancelled()) pluginEvent.setCancelled(); } public static Collection> values() { return Collections.unmodifiableList(ALL_TYPES); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java ================================================ package com.bgsoftware.superiorskyblock.core.events.plugin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.commands.CommandsMap; import com.bgsoftware.superiorskyblock.commands.player.CmdAdmin; import com.bgsoftware.superiorskyblock.commands.player.CmdHelp; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.events.EventCallback; import com.bgsoftware.superiorskyblock.core.events.EventsDispatcher; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.external.worlds.WorldsProvider_Default; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; import com.bgsoftware.superiorskyblock.world.Dimensions; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import java.util.EnumMap; import java.util.List; public class PluginEventsDispatcher extends EventsDispatcher< Void, PluginEventType, PluginEventPriority, PluginEvent> { public PluginEventsDispatcher(SuperiorSkyblockPlugin plugin) { super(plugin, PluginEventPriority.class, PluginEventType.values()); } public void registerDefaultListeners() { SIsland.registerListeners(this); CommandsMap.registerListeners(this); SpawnIsland.registerListeners(this); RegionManagerServiceImpl.registerListeners(this); CmdHelp.registerListeners(this); CmdAdmin.registerListeners(this); Message.registerListeners(this); SSuperiorPlayer.registerListeners(this); WorldsProvider_Default.registerListeners(this); IslandPrivileges.registerListeners(this); Dimensions.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { registerCallback(type, unused -> callback.run()); } public void registerCallback(PluginEventType type, EventCallback> callback) { registerCallback(null, type, PluginEventPriority.NORMAL, true, callback); } public PluginEvent fireEvent(PluginEventType type, Args args) { PluginEvent event = type.createEvent(args); EnumMap> gameEventCallbacks = callbacks.get(type); if (gameEventCallbacks != null) { gameEventCallbacks.forEach((priority, priorityCallbacks) -> { for (RegisteredListener listener : priorityCallbacks) { if (listener.ignoreCancelled && event.isCancelled()) { continue; } try { listener.callback.execute(event); } catch (Throwable error) { Log.error(error, "Could not pass listener: " + listener.listener); } } }); } String bukkitEventName = type.getBukkitEventName(); boolean fireEventDebug = !Text.isBlank(bukkitEventName); if (!fireEventDebug || !plugin.getSettings().getDisabledEvents().contains(bukkitEventName)) { if (fireEventDebug) Log.debug(Debug.FIRE_EVENT, bukkitEventName); Event bukkitEvent = type.createBukkitEvent(event.getArgs()); if (bukkitEvent != null) { Bukkit.getPluginManager().callEvent(bukkitEvent); if (fireEventDebug && bukkitEvent instanceof Cancellable) { Log.debugResult(Debug.FIRE_EVENT, "Cancelled:", ((Cancellable) bukkitEvent).isCancelled()); } type.applyBukkitToPluginEvent(bukkitEvent, event); } } return event; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java ================================================ package com.bgsoftware.superiorskyblock.core.events.plugin; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.util.Collections; import java.util.List; import java.util.Locale; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.*; import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.*; public class PluginEventsFactory { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public static void callSettingsUpdateEvent() { fireEvent(SETTINGS_UPDATE_EVENT, Empty.INSTANCE); } public static void callCommandsUpdateEvent() { fireEvent(COMMANDS_UPDATE_EVENT, Empty.INSTANCE); } public static void callSpawnUpdateEvent() { fireEvent(SPAWN_UPDATE_EVENT, Empty.INSTANCE); } public static void callWorldsProviderUpdateEvent() { fireEvent(WORLD_PROVIDER_UPDATE_EVENT, Empty.INSTANCE); } public static boolean callAttemptPlayerSendMessageEvent(SuperiorPlayer receiver, String messageType, Object... args) { AttemptPlayerSendMessage attemptPlayerSendMessage = new AttemptPlayerSendMessage(); attemptPlayerSendMessage.receiver = receiver; attemptPlayerSendMessage.messageType = messageType; attemptPlayerSendMessage.args = args; return !fireEvent(ATTEMPT_PLAYER_SEND_MESSAGE_EVENT, attemptPlayerSendMessage).isCancelled(); } public static boolean callBlockStackEvent(Block block, Player player, int originalCount, int newCount) { BlockStack blockStack = new BlockStack(); blockStack.block = block; blockStack.player = player; blockStack.originalCount = originalCount; blockStack.newCount = newCount; return !fireEvent(BLOCK_STACK_EVENT, blockStack).isCancelled(); } public static boolean callBlockUnstackEvent(Block block, Player player, int originalCount, int newCount) { BlockUnstack blockUnstack = new BlockUnstack(); blockUnstack.block = block; blockUnstack.player = player; blockUnstack.originalCount = originalCount; blockUnstack.newCount = newCount; return !fireEvent(BLOCK_UNSTACK_EVENT, blockUnstack).isCancelled(); } public static boolean callIslandBanEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { IslandBan islandBan = new IslandBan(); islandBan.island = island; islandBan.superiorPlayer = superiorPlayer; islandBan.targetPlayer = targetPlayer; return !fireEvent(ISLAND_BAN_EVENT, islandBan).isCancelled(); } public static PluginEvent callIslandBankDepositEvent(Island island, CommandSender commandSender, BigDecimal amount) { return callIslandBankDepositEvent(island, commandSenderToSuperiorPlayer(commandSender), amount); } public static PluginEvent callIslandBankDepositEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal amount) { IslandBankDeposit islandBankDeposit = new IslandBankDeposit(); islandBankDeposit.island = island; islandBankDeposit.superiorPlayer = superiorPlayer; islandBankDeposit.amount = amount; return fireEvent(ISLAND_BANK_DEPOSIT_EVENT, islandBankDeposit); } public static PluginEvent callIslandBankWithdrawEvent(Island island, CommandSender commandSender, BigDecimal amount) { return callIslandBankWithdrawEvent(island, commandSenderToSuperiorPlayer(commandSender), amount); } public static PluginEvent callIslandBankWithdrawEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal amount) { IslandBankWithdraw islandBankWithdraw = new IslandBankWithdraw(); islandBankWithdraw.island = island; islandBankWithdraw.superiorPlayer = superiorPlayer; islandBankWithdraw.amount = amount; return fireEvent(ISLAND_BANK_WITHDRAW_EVENT, islandBankWithdraw); } public static PluginEvent callIslandBiomeChangeEvent(Island island, SuperiorPlayer superiorPlayer, Biome biome) { IslandBiomeChange islandBiomeChange = new IslandBiomeChange(); islandBiomeChange.island = island; islandBiomeChange.superiorPlayer = superiorPlayer; islandBiomeChange.biome = biome; return fireEvent(ISLAND_BIOME_CHANGE_EVENT, islandBiomeChange); } public static PluginEvent callIslandChangeBankLimitEvent(Island island, CommandSender commandSender, BigDecimal bankLimit) { return callIslandChangeBankLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), bankLimit); } public static PluginEvent callIslandChangeBankLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal bankLimit) { IslandChangeBankLimit islandChangeBankLimit = new IslandChangeBankLimit(); islandChangeBankLimit.island = island; islandChangeBankLimit.superiorPlayer = superiorPlayer; islandChangeBankLimit.bankLimit = bankLimit; return fireEvent(ISLAND_CHANGE_BANK_LIMIT_EVENT, islandChangeBankLimit); } public static PluginEvent callIslandChangeBlockLimitEvent(Island island, CommandSender commandSender, Key block, int blockLimit) { return callIslandChangeBlockLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), block, blockLimit); } public static PluginEvent callIslandChangeBlockLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block, int blockLimit) { IslandChangeBlockLimit islandChangeBlockLimit = new IslandChangeBlockLimit(); islandChangeBlockLimit.island = island; islandChangeBlockLimit.superiorPlayer = superiorPlayer; islandChangeBlockLimit.block = block; islandChangeBlockLimit.blockLimit = blockLimit; return fireEvent(ISLAND_CHANGE_BLOCK_LIMIT_EVENT, islandChangeBlockLimit); } public static PluginEvent callIslandChangeBorderSizeEvent(Island island, CommandSender commandSender, int borderSize) { return callIslandChangeBorderSizeEvent(island, commandSenderToSuperiorPlayer(commandSender), borderSize); } public static PluginEvent callIslandChangeBorderSizeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int borderSize) { IslandChangeBorderSize islandChangeBorderSize = new IslandChangeBorderSize(); islandChangeBorderSize.island = island; islandChangeBorderSize.superiorPlayer = superiorPlayer; islandChangeBorderSize.borderSize = borderSize; return fireEvent(ISLAND_CHANGE_BORDER_SIZE_EVENT, islandChangeBorderSize); } public static PluginEvent callIslandChangeCoopLimitEvent(Island island, CommandSender commandSender, int coopLimit) { return callIslandChangeCoopLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), coopLimit); } public static PluginEvent callIslandChangeCoopLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int coopLimit) { IslandChangeCoopLimit islandChangeCoopLimit = new IslandChangeCoopLimit(); islandChangeCoopLimit.island = island; islandChangeCoopLimit.superiorPlayer = superiorPlayer; islandChangeCoopLimit.coopLimit = coopLimit; return fireEvent(ISLAND_CHANGE_COOP_LIMIT_EVENT, islandChangeCoopLimit); } public static PluginEvent callIslandChangeCropGrowthEvent(Island island, CommandSender commandSender, double cropGrowth) { return callIslandChangeCropGrowthEvent(island, commandSenderToSuperiorPlayer(commandSender), cropGrowth); } public static PluginEvent callIslandChangeCropGrowthEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double cropGrowth) { IslandChangeCropGrowth islandChangeCropGrowth = new IslandChangeCropGrowth(); islandChangeCropGrowth.island = island; islandChangeCropGrowth.superiorPlayer = superiorPlayer; islandChangeCropGrowth.cropGrowth = cropGrowth; return fireEvent(ISLAND_CHANGE_CROP_GROWTH_EVENT, islandChangeCropGrowth); } public static PluginEvent callIslandChangeDescriptionEvent(Island island, SuperiorPlayer superiorPlayer, String description) { IslandChangeDescription islandChangeDescription = new IslandChangeDescription(); islandChangeDescription.island = island; islandChangeDescription.superiorPlayer = superiorPlayer; islandChangeDescription.description = description; return fireEvent(ISLAND_CHANGE_DESCRIPTION_EVENT, islandChangeDescription); } public static PluginEvent callIslandChangeDiscordEvent(Island island, SuperiorPlayer superiorPlayer, String discord) { IslandChangeDiscord islandChangeDiscord = new IslandChangeDiscord(); islandChangeDiscord.island = island; islandChangeDiscord.superiorPlayer = superiorPlayer; islandChangeDiscord.discord = discord; return fireEvent(ISLAND_CHANGE_DISCORD_EVENT, islandChangeDiscord); } public static PluginEvent callIslandChangeEffectLevelEvent(Island island, CommandSender commandSender, PotionEffectType effectType, int effectLevel) { return callIslandChangeEffectLevelEvent(island, commandSenderToSuperiorPlayer(commandSender), effectType, effectLevel); } public static PluginEvent callIslandChangeEffectLevelEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PotionEffectType effectType, int effectLevel) { IslandChangeEffectLevel islandChangeEffectLevel = new IslandChangeEffectLevel(); islandChangeEffectLevel.island = island; islandChangeEffectLevel.superiorPlayer = superiorPlayer; islandChangeEffectLevel.effectType = effectType; islandChangeEffectLevel.effectLevel = effectLevel; return fireEvent(ISLAND_CHANGE_EFFECT_LEVEL_EVENT, islandChangeEffectLevel); } public static PluginEvent callIslandChangeEntityLimitEvent(Island island, CommandSender commandSender, Key entity, int entityLimit) { return callIslandChangeEntityLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), entity, entityLimit); } public static PluginEvent callIslandChangeEntityLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key entity, int entityLimit) { IslandChangeEntityLimit islandChangeEntityLimit = new IslandChangeEntityLimit(); islandChangeEntityLimit.island = island; islandChangeEntityLimit.superiorPlayer = superiorPlayer; islandChangeEntityLimit.entity = entity; islandChangeEntityLimit.entityLimit = entityLimit; return fireEvent(ISLAND_CHANGE_ENTITY_LIMIT_EVENT, islandChangeEntityLimit); } public static PluginEvent callIslandChangeGeneratorRateEvent(Island island, CommandSender commandSender, Key block, Dimension dimension, int generatorRate) { return callIslandChangeGeneratorRateEvent(island, commandSenderToSuperiorPlayer(commandSender), block, dimension, generatorRate); } public static PluginEvent callIslandChangeGeneratorRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block, Dimension dimension, int generatorRate) { IslandChangeGeneratorRate islandChangeGeneratorRate = new IslandChangeGeneratorRate(); islandChangeGeneratorRate.island = island; islandChangeGeneratorRate.superiorPlayer = superiorPlayer; islandChangeGeneratorRate.block = block; islandChangeGeneratorRate.dimension = dimension; islandChangeGeneratorRate.generatorRate = generatorRate; return fireEvent(ISLAND_CHANGE_GENERATOR_RATE_EVENT, islandChangeGeneratorRate); } public static PluginEvent callIslandChangeLevelBonusEvent(Island island, CommandSender commandSender, IslandChangeLevelBonusEvent.Reason reason, BigDecimal levelBonus) { return callIslandChangeLevelBonusEvent(island, commandSenderToSuperiorPlayer(commandSender), reason, levelBonus); } public static PluginEvent callIslandChangeLevelBonusEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandChangeLevelBonusEvent.Reason reason, BigDecimal levelBonus) { IslandChangeLevelBonus islandChangeLevelBonus = new IslandChangeLevelBonus(); islandChangeLevelBonus.island = island; islandChangeLevelBonus.superiorPlayer = superiorPlayer; islandChangeLevelBonus.reason = reason; islandChangeLevelBonus.levelBonus = levelBonus; return fireEvent(ISLAND_CHANGE_LEVEL_BONUS_EVENT, islandChangeLevelBonus); } public static PluginEvent callIslandChangeMembersLimitEvent(Island island, CommandSender commandSender, int membersLimit) { return callIslandChangeMembersLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), membersLimit); } public static PluginEvent callIslandChangeMembersLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int membersLimit) { IslandChangeMembersLimit islandChangeMembersLimit = new IslandChangeMembersLimit(); islandChangeMembersLimit.island = island; islandChangeMembersLimit.superiorPlayer = superiorPlayer; islandChangeMembersLimit.membersLimit = membersLimit; return fireEvent(ISLAND_CHANGE_MEMBERS_LIMIT_EVENT, islandChangeMembersLimit); } public static PluginEvent callIslandChangeMobDropsEvent(Island island, CommandSender commandSender, double mobDrops) { return callIslandChangeMobDropsEvent(island, commandSenderToSuperiorPlayer(commandSender), mobDrops); } public static PluginEvent callIslandChangeMobDropsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double mobDrops) { IslandChangeMobDrops islandChangeMobDrops = new IslandChangeMobDrops(); islandChangeMobDrops.island = island; islandChangeMobDrops.superiorPlayer = superiorPlayer; islandChangeMobDrops.mobDrops = mobDrops; return fireEvent(ISLAND_CHANGE_MOB_DROPS_EVENT, islandChangeMobDrops); } public static PluginEvent callIslandChangePaypalEvent(Island island, SuperiorPlayer superiorPlayer, String paypal) { IslandChangePaypal islandChangePaypal = new IslandChangePaypal(); islandChangePaypal.island = island; islandChangePaypal.superiorPlayer = superiorPlayer; islandChangePaypal.paypal = paypal; return fireEvent(ISLAND_CHANGE_PAYPAL_EVENT, islandChangePaypal); } public static boolean callIslandChangePlayerPrivilegeEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer privilegedPlayer, boolean privilegeEnabled) { IslandChangePlayerPrivilege islandChangePlayerPrivilege = new IslandChangePlayerPrivilege(); islandChangePlayerPrivilege.island = island; islandChangePlayerPrivilege.superiorPlayer = superiorPlayer; islandChangePlayerPrivilege.privilegedPlayer = privilegedPlayer; islandChangePlayerPrivilege.privilegeEnabled = privilegeEnabled; return !fireEvent(ISLAND_CHANGE_PLAYER_PRIVILEGE_EVENT, islandChangePlayerPrivilege).isCancelled(); } public static PluginEvent callIslandChangeRoleLimitEvent(Island island, CommandSender commandSender, PlayerRole playerRole, int roleLimit) { return callIslandChangeRoleLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole, roleLimit); } public static PluginEvent callIslandChangeRoleLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole, int roleLimit) { IslandChangeRoleLimit islandChangeRoleLimit = new IslandChangeRoleLimit(); islandChangeRoleLimit.island = island; islandChangeRoleLimit.superiorPlayer = superiorPlayer; islandChangeRoleLimit.playerRole = playerRole; islandChangeRoleLimit.roleLimit = roleLimit; return fireEvent(ISLAND_CHANGE_ROLE_LIMIT_EVENT, islandChangeRoleLimit); } public static PluginEvent callIslandChangeSpawnerRatesEvent(Island island, CommandSender commandSender, double spawnerRates) { return callIslandChangeSpawnerRatesEvent(island, commandSenderToSuperiorPlayer(commandSender), spawnerRates); } public static PluginEvent callIslandChangeSpawnerRatesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double spawnerRates) { IslandChangeSpawnerRates islandChangeSpawnerRates = new IslandChangeSpawnerRates(); islandChangeSpawnerRates.island = island; islandChangeSpawnerRates.superiorPlayer = superiorPlayer; islandChangeSpawnerRates.spawnerRates = spawnerRates; return fireEvent(ISLAND_CHANGE_SPAWNER_RATES_EVENT, islandChangeSpawnerRates); } public static PluginEvent callIslandChangeWarpCategoryIconEvent(Island island, SuperiorPlayer superiorPlayer, WarpCategory warpCategory, @Nullable ItemStack icon) { IslandChangeWarpCategoryIcon islandChangeWarpCategoryIcon = new IslandChangeWarpCategoryIcon(); islandChangeWarpCategoryIcon.island = island; islandChangeWarpCategoryIcon.superiorPlayer = superiorPlayer; islandChangeWarpCategoryIcon.warpCategory = warpCategory; islandChangeWarpCategoryIcon.icon = icon; return fireEvent(ISLAND_CHANGE_WARP_CATEGORY_ICON_EVENT, islandChangeWarpCategoryIcon); } public static PluginEvent callIslandChangeWarpCategorySlotEvent(Island island, SuperiorPlayer superiorPlayer, WarpCategory warpCategory, int slot, int maxSlot) { IslandChangeWarpCategorySlot islandChangeWarpCategorySlot = new IslandChangeWarpCategorySlot(); islandChangeWarpCategorySlot.island = island; islandChangeWarpCategorySlot.superiorPlayer = superiorPlayer; islandChangeWarpCategorySlot.warpCategory = warpCategory; islandChangeWarpCategorySlot.slot = slot; islandChangeWarpCategorySlot.maxSlot = maxSlot; return fireEvent(ISLAND_CHANGE_WARP_CATEGORY_SLOT_EVENT, islandChangeWarpCategorySlot); } public static PluginEvent callIslandChangeWarpIconEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp, @Nullable ItemStack icon) { IslandChangeWarpIcon islandChangeWarpIcon = new IslandChangeWarpIcon(); islandChangeWarpIcon.island = island; islandChangeWarpIcon.superiorPlayer = superiorPlayer; islandChangeWarpIcon.islandWarp = islandWarp; islandChangeWarpIcon.icon = icon; return fireEvent(ISLAND_CHANGE_WARP_ICON_EVENT, islandChangeWarpIcon); } public static PluginEvent callIslandChangeWarpLocationEvent(Island island, Player player, IslandWarp islandWarp, Location location) { return callIslandChangeWarpLocationEvent(island, commandSenderToSuperiorPlayer(player), islandWarp, location); } public static PluginEvent callIslandChangeWarpLocationEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp, Location location) { IslandChangeWarpLocation islandChangeWarpLocation = new IslandChangeWarpLocation(); islandChangeWarpLocation.island = island; islandChangeWarpLocation.superiorPlayer = superiorPlayer; islandChangeWarpLocation.islandWarp = islandWarp; islandChangeWarpLocation.location = location; return fireEvent(ISLAND_CHANGE_WARP_LOCATION_EVENT, islandChangeWarpLocation); } public static PluginEvent callIslandChangeWarpsLimitEvent(Island island, CommandSender commandSender, int warpsLimit) { return callIslandChangeWarpsLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), warpsLimit); } public static PluginEvent callIslandChangeWarpsLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int warpsLimit) { IslandChangeWarpsLimit islandChangeWarpsLimit = new IslandChangeWarpsLimit(); islandChangeWarpsLimit.island = island; islandChangeWarpsLimit.superiorPlayer = superiorPlayer; islandChangeWarpsLimit.warpsLimit = warpsLimit; return fireEvent(ISLAND_CHANGE_WARPS_LIMIT_EVENT, islandChangeWarpsLimit); } public static PluginEvent callIslandChangeWorthBonusEvent(Island island, CommandSender commandSender, IslandChangeWorthBonusEvent.Reason reason, BigDecimal worthBonus) { return callIslandChangeWorthBonusEvent(island, commandSenderToSuperiorPlayer(commandSender), reason, worthBonus); } public static PluginEvent callIslandChangeWorthBonusEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandChangeWorthBonusEvent.Reason reason, BigDecimal worthBonus) { IslandChangeWorthBonus islandChangeWorthBonus = new IslandChangeWorthBonus(); islandChangeWorthBonus.island = island; islandChangeWorthBonus.superiorPlayer = superiorPlayer; islandChangeWorthBonus.reason = reason; islandChangeWorthBonus.worthBonus = worthBonus; return fireEvent(ISLAND_CHANGE_WORTH_BONUS_EVENT, islandChangeWorthBonus); } public static boolean callIslandChangeRolePrivilegeEvent(Island island, CommandSender commandSender, PlayerRole playerRole) { return callIslandChangeRolePrivilegeEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole); } public static boolean callIslandChangeRolePrivilegeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) { IslandChangeRolePrivilege islandChangeRolePrivilege = new IslandChangeRolePrivilege(); islandChangeRolePrivilege.island = island; islandChangeRolePrivilege.superiorPlayer = superiorPlayer; islandChangeRolePrivilege.playerRole = playerRole; return !fireEvent(ISLAND_CHANGE_ROLE_PRIVILEGE_EVENT, islandChangeRolePrivilege).isCancelled(); } public static PluginEvent callIslandChatEvent(Island island, SuperiorPlayer superiorPlayer, String message) { IslandChat islandChat = new IslandChat(); islandChat.island = island; islandChat.superiorPlayer = superiorPlayer; islandChat.message = message; return fireEvent(ISLAND_CHAT_EVENT, islandChat); } public static void callIslandChunkResetEvent(Island island, ChunkPosition chunkPosition) { IslandChunkReset islandChunkReset = new IslandChunkReset(); islandChunkReset.island = island; islandChunkReset.chunkPosition = chunkPosition; fireEvent(ISLAND_CHUNK_RESET_EVENT, islandChunkReset); } public static boolean callIslandClearFlagsEvent(Island island, CommandSender commandSender) { return callIslandClearFlagsEvent(island, commandSenderToSuperiorPlayer(commandSender)); } public static boolean callIslandClearFlagsEvent(Island island, SuperiorPlayer superiorPlayer) { IslandClearFlags islandClearFlags = new IslandClearFlags(); islandClearFlags.island = island; islandClearFlags.superiorPlayer = superiorPlayer; return !fireEvent(ISLAND_CLEAR_FLAGS_EVENT, islandClearFlags).isCancelled(); } public static boolean callIslandClearGeneratorRatesEvent(Island island, CommandSender commandSender, Dimension dimension) { return callIslandClearGeneratorRatesEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); } public static boolean callIslandClearGeneratorRatesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) { IslandClearGeneratorRates islandClearGeneratorRates = new IslandClearGeneratorRates(); islandClearGeneratorRates.island = island; islandClearGeneratorRates.superiorPlayer = superiorPlayer; islandClearGeneratorRates.dimension = dimension; return !fireEvent(ISLAND_CLEAR_GENERATOR_RATES_EVENT, islandClearGeneratorRates).isCancelled(); } public static boolean callIslandClearPlayerPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer privilegedPlayer) { IslandClearPlayerPrivileges islandClearPlayerPrivileges = new IslandClearPlayerPrivileges(); islandClearPlayerPrivileges.island = island; islandClearPlayerPrivileges.superiorPlayer = superiorPlayer; islandClearPlayerPrivileges.privilegedPlayer = privilegedPlayer; return !fireEvent(ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT, islandClearPlayerPrivileges).isCancelled(); } public static boolean callIslandClearRatingsEvent(Island island, CommandSender commandSender) { return callIslandClearRatingsEvent(island, commandSenderToSuperiorPlayer(commandSender)); } public static boolean callIslandClearRatingsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { IslandClearRatings islandClearRatings = new IslandClearRatings(); islandClearRatings.island = island; islandClearRatings.superiorPlayer = superiorPlayer; return !fireEvent(ISLAND_CLEAR_RATINGS_EVENT, islandClearRatings).isCancelled(); } public static boolean callIslandClearRolesPrivilegesEvent(Island island, CommandSender commandSender) { return callIslandClearRolesPrivilegesEvent(island, commandSenderToSuperiorPlayer(commandSender)); } public static boolean callIslandClearRolesPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer) { IslandClearRolesPrivileges islandClearRolesPrivileges = new IslandClearRolesPrivileges(); islandClearRolesPrivileges.island = island; islandClearRolesPrivileges.superiorPlayer = superiorPlayer; return !fireEvent(ISLAND_CLEAR_ROLES_PRIVILEGES_EVENT, islandClearRolesPrivileges).isCancelled(); } public static boolean callIslandCloseEvent(Island island, CommandSender commandSender) { return callIslandCloseEvent(island, commandSenderToSuperiorPlayer(commandSender)); } public static boolean callIslandCloseEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { IslandClose islandClose = new IslandClose(); islandClose.island = island; islandClose.superiorPlayer = superiorPlayer; return !fireEvent(ISLAND_CLOSE_EVENT, islandClose).isCancelled(); } public static boolean callIslandCloseWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { IslandCloseWarp islandCloseWarp = new IslandCloseWarp(); islandCloseWarp.island = island; islandCloseWarp.superiorPlayer = superiorPlayer; islandCloseWarp.islandWarp = islandWarp; return !fireEvent(ISLAND_CLOSE_WARP_EVENT, islandCloseWarp).isCancelled(); } public static boolean callIslandCoopPlayerEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { IslandCoopPlayer islandCoopPlayer = new IslandCoopPlayer(); islandCoopPlayer.island = island; islandCoopPlayer.superiorPlayer = superiorPlayer; islandCoopPlayer.targetPlayer = targetPlayer; return !fireEvent(ISLAND_COOP_PLAYER_EVENT, islandCoopPlayer).isCancelled(); } public static PluginEvent callIslandCreateEvent(Island island, SuperiorPlayer superiorPlayer, String schematicName, boolean canTeleport) { IslandCreate islandCreate = new IslandCreate(); islandCreate.island = island; islandCreate.superiorPlayer = superiorPlayer; islandCreate.schematicName = schematicName; islandCreate.canTeleport = canTeleport; return fireEvent(ISLAND_CREATE_EVENT, islandCreate); } public static boolean callIslandCreateWarpCategoryEvent(Island island, SuperiorPlayer superiorPlayer, String categoryName) { IslandCreateWarpCategory islandCreateWarpCategory = new IslandCreateWarpCategory(); islandCreateWarpCategory.island = island; islandCreateWarpCategory.superiorPlayer = superiorPlayer; islandCreateWarpCategory.categoryName = categoryName; return !fireEvent(ISLAND_CREATE_WARP_CATEGORY_EVENT, islandCreateWarpCategory).isCancelled(); } public static boolean callIslandCreateWarpEvent(Island island, SuperiorPlayer superiorPlayer, String warpName, Location location, @Nullable WarpCategory warpCategory) { return callIslandCreateWarpEvent(island, superiorPlayer, warpName, location, plugin.getSettings().isPublicWarps(), warpCategory); } public static boolean callIslandCreateWarpEvent(Island island, SuperiorPlayer superiorPlayer, String warpName, Location location, boolean openToPublic, @Nullable WarpCategory warpCategory) { IslandCreateWarp islandCreateWarp = new IslandCreateWarp(); islandCreateWarp.island = island; islandCreateWarp.superiorPlayer = superiorPlayer; islandCreateWarp.warpName = warpName; islandCreateWarp.location = location; islandCreateWarp.openToPublic = openToPublic; islandCreateWarp.warpCategory = warpCategory; return !fireEvent(ISLAND_CREATE_WARP_EVENT, islandCreateWarp).isCancelled(); } public static boolean callIslandDeleteWarpEvent(Island island, CommandSender commandSender, IslandWarp islandWarp) { return callIslandDeleteWarpEvent(island, commandSenderToSuperiorPlayer(commandSender), islandWarp); } public static boolean callIslandDeleteWarpEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { IslandDeleteWarp islandDeleteWarp = new IslandDeleteWarp(); islandDeleteWarp.island = island; islandDeleteWarp.superiorPlayer = superiorPlayer; islandDeleteWarp.islandWarp = islandWarp; return !fireEvent(ISLAND_DELETE_WARP_EVENT, islandDeleteWarp).isCancelled(); } public static boolean callIslandDisableFlagEvent(Island island, CommandSender commandSender, IslandFlag islandFlag) { return callIslandDisableFlagEvent(island, commandSenderToSuperiorPlayer(commandSender), islandFlag); } public static boolean callIslandDisableFlagEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandFlag islandFlag) { IslandDisableFlag islandDisableFlag = new IslandDisableFlag(); islandDisableFlag.island = island; islandDisableFlag.superiorPlayer = superiorPlayer; islandDisableFlag.islandFlag = islandFlag; return !fireEvent(ISLAND_DISABLE_FLAG_EVENT, islandDisableFlag).isCancelled(); } public static boolean callIslandDisbandEvent(Island island, SuperiorPlayer superiorPlayer) { IslandDisband islandDisband = new IslandDisband(); islandDisband.island = island; islandDisband.superiorPlayer = superiorPlayer; return !fireEvent(ISLAND_DISBAND_EVENT, islandDisband).isCancelled(); } public static boolean callIslandEnableFlagEvent(Island island, CommandSender commandSender, IslandFlag islandFlag) { return callIslandEnableFlagEvent(island, commandSenderToSuperiorPlayer(commandSender), islandFlag); } public static boolean callIslandEnableFlagEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandFlag islandFlag) { IslandEnableFlag islandEnableFlag = new IslandEnableFlag(); islandEnableFlag.island = island; islandEnableFlag.superiorPlayer = superiorPlayer; islandEnableFlag.islandFlag = islandFlag; return !fireEvent(ISLAND_ENABLE_FLAG_EVENT, islandEnableFlag).isCancelled(); } public static boolean callIslandEnterEvent(Island island, SuperiorPlayer superiorPlayer, IslandEnterEvent.EnterCause enterCause) { IslandEnter islandEnter = new IslandEnter(); islandEnter.island = island; islandEnter.superiorPlayer = superiorPlayer; islandEnter.enterCause = enterCause; return !fireEvent(ISLAND_ENTER_EVENT, islandEnter).isCancelled(); } public static PluginEvent callIslandEnterPortalEvent(Island island, SuperiorPlayer superiorPlayer, PortalType portalType, Dimension destination, @Nullable Schematic schematic, boolean ignoreInvalidSchematic) { IslandEnterPortal islandEnterPortal = new IslandEnterPortal(); islandEnterPortal.island = island; islandEnterPortal.superiorPlayer = superiorPlayer; islandEnterPortal.portalType = portalType; islandEnterPortal.destination = destination; islandEnterPortal.schematic = schematic; islandEnterPortal.ignoreInvalidSchematic = ignoreInvalidSchematic; return fireEvent(ISLAND_ENTER_PORTAL_EVENT, islandEnterPortal); } public static boolean callIslandEnterProtectedEvent(Island island, SuperiorPlayer superiorPlayer, IslandEnterEvent.EnterCause enterCause) { IslandEnterProtected islandEnterProtected = new IslandEnterProtected(); islandEnterProtected.island = island; islandEnterProtected.superiorPlayer = superiorPlayer; islandEnterProtected.enterCause = enterCause; return !fireEvent(ISLAND_ENTER_PROTECTED_EVENT, islandEnterProtected).isCancelled(); } public static PluginEvent callIslandGenerateBlockEvent(Island island, Location location, Key block) { IslandGenerateBlock islandGenerateBlock = new IslandGenerateBlock(); islandGenerateBlock.island = island; islandGenerateBlock.location = location; islandGenerateBlock.block = block; return fireEvent(ISLAND_GENERATE_BLOCK_EVENT, islandGenerateBlock); } public static boolean callIslandHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) { IslandHomeTeleport islandHomeTeleport = new IslandHomeTeleport(); islandHomeTeleport.island = island; islandHomeTeleport.superiorPlayer = superiorPlayer; islandHomeTeleport.dimension = dimension; return !fireEvent(ISLAND_HOME_TELEPORT_EVENT, islandHomeTeleport).isCancelled(); } public static boolean callIslandInviteEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { IslandInvite islandInvite = new IslandInvite(); islandInvite.island = island; islandInvite.superiorPlayer = superiorPlayer; islandInvite.targetPlayer = targetPlayer; return !fireEvent(ISLAND_INVITE_EVENT, islandInvite).isCancelled(); } public static boolean callIslandJoinEvent(Island island, SuperiorPlayer superiorPlayer, IslandJoinEvent.Cause joinCause) { IslandJoin islandJoin = new IslandJoin(); islandJoin.island = island; islandJoin.superiorPlayer = superiorPlayer; islandJoin.joinCause = joinCause; return !fireEvent(ISLAND_JOIN_EVENT, islandJoin).isCancelled(); } public static boolean callIslandKickEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { IslandKick islandKick = new IslandKick(); islandKick.island = island; islandKick.superiorPlayer = superiorPlayer; islandKick.targetPlayer = targetPlayer; return !fireEvent(ISLAND_KICK_EVENT, islandKick).isCancelled(); } public static boolean callIslandLeaveEvent(Island island, SuperiorPlayer superiorPlayer, IslandLeaveEvent.LeaveCause leaveCause, Location location) { IslandLeave islandLeave = new IslandLeave(); islandLeave.island = island; islandLeave.superiorPlayer = superiorPlayer; islandLeave.leaveCause = leaveCause; islandLeave.location = location; return !fireEvent(ISLAND_LEAVE_EVENT, islandLeave).isCancelled(); } public static boolean callIslandLeaveProtectedEvent(Island island, SuperiorPlayer superiorPlayer, IslandLeaveEvent.LeaveCause leaveCause, Location location) { IslandLeaveProtected islandLeaveProtected = new IslandLeaveProtected(); islandLeaveProtected.island = island; islandLeaveProtected.superiorPlayer = superiorPlayer; islandLeaveProtected.leaveCause = leaveCause; islandLeaveProtected.location = location; return !fireEvent(ISLAND_LEAVE_PROTECTED_EVENT, islandLeaveProtected).isCancelled(); } public static boolean callIslandLockWorldEvent(Island island, CommandSender commandSender, Dimension dimension) { return callIslandLockWorldEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); } public static boolean callIslandLockWorldEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) { IslandLockWorld islandLockWorld = new IslandLockWorld(); islandLockWorld.island = island; islandLockWorld.superiorPlayer = superiorPlayer; islandLockWorld.dimension = dimension; return !fireEvent(ISLAND_LOCK_WORLD_EVENT, islandLockWorld).isCancelled(); } public static boolean callIslandOpenEvent(Island island, CommandSender commandSender) { return callIslandOpenEvent(island, commandSenderToSuperiorPlayer(commandSender)); } public static boolean callIslandOpenEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { IslandOpen islandOpen = new IslandOpen(); islandOpen.island = island; islandOpen.superiorPlayer = superiorPlayer; return !fireEvent(ISLAND_OPEN_EVENT, islandOpen).isCancelled(); } public static boolean callIslandOpenWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { IslandOpenWarp islandOpenWarp = new IslandOpenWarp(); islandOpenWarp.island = island; islandOpenWarp.superiorPlayer = superiorPlayer; islandOpenWarp.islandWarp = islandWarp; return !fireEvent(ISLAND_OPEN_WARP_EVENT, islandOpenWarp).isCancelled(); } public static boolean callIslandQuitEvent(Island island, SuperiorPlayer superiorPlayer) { IslandQuit islandQuit = new IslandQuit(); islandQuit.island = island; islandQuit.superiorPlayer = superiorPlayer; return !fireEvent(ISLAND_QUIT_EVENT, islandQuit).isCancelled(); } public static boolean callIslandRateEvent(Island island, CommandSender commandSender, SuperiorPlayer ratingPlayer, Rating rating) { return callIslandRateEvent(island, commandSenderToSuperiorPlayer(commandSender), ratingPlayer, rating); } public static boolean callIslandRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Rating rating) { IslandRate islandRate = new IslandRate(); islandRate.island = island; islandRate.superiorPlayer = superiorPlayer; islandRate.ratingPlayer = ratingPlayer; islandRate.rating = rating; return !fireEvent(ISLAND_RATE_EVENT, islandRate).isCancelled(); } public static boolean callIslandRemoveBlockLimitEvent(Island island, CommandSender commandSender, Key block) { return callIslandRemoveBlockLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), block); } public static boolean callIslandRemoveBlockLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block) { IslandRemoveBlockLimit islandRemoveBlockLimit = new IslandRemoveBlockLimit(); islandRemoveBlockLimit.island = island; islandRemoveBlockLimit.superiorPlayer = superiorPlayer; islandRemoveBlockLimit.block = block; return !fireEvent(ISLAND_REMOVE_BLOCK_LIMIT_EVENT, islandRemoveBlockLimit).isCancelled(); } public static boolean callIslandRemoveEffectEvent(Island island, CommandSender commandSender, PotionEffectType effectType) { return callIslandRemoveEffectEvent(island, commandSenderToSuperiorPlayer(commandSender), effectType); } public static boolean callIslandRemoveEffectEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PotionEffectType effectType) { IslandRemoveEffect islandRemoveEffect = new IslandRemoveEffect(); islandRemoveEffect.island = island; islandRemoveEffect.superiorPlayer = superiorPlayer; islandRemoveEffect.effectType = effectType; return !fireEvent(ISLAND_REMOVE_EFFECT_EVENT, islandRemoveEffect).isCancelled(); } public static boolean callIslandRemoveEntityLimitEvent(Island island, CommandSender commandSender, Key entity) { return callIslandRemoveEntityLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), entity); } public static boolean callIslandRemoveEntityLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key entity) { IslandRemoveEntityLimit islandRemoveEntityLimit = new IslandRemoveEntityLimit(); islandRemoveEntityLimit.island = island; islandRemoveEntityLimit.superiorPlayer = superiorPlayer; islandRemoveEntityLimit.entity = entity; return !fireEvent(ISLAND_REMOVE_ENTITY_LIMIT_EVENT, islandRemoveEntityLimit).isCancelled(); } public static boolean callIslandRemoveGeneratorRateEvent(Island island, CommandSender commandSender, Key block, Dimension dimension) { return callIslandRemoveGeneratorRateEvent(island, commandSenderToSuperiorPlayer(commandSender), block, dimension); } public static boolean callIslandRemoveGeneratorRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block, Dimension dimension) { IslandRemoveGeneratorRate islandRemoveGeneratorRate = new IslandRemoveGeneratorRate(); islandRemoveGeneratorRate.island = island; islandRemoveGeneratorRate.superiorPlayer = superiorPlayer; islandRemoveGeneratorRate.block = block; islandRemoveGeneratorRate.dimension = dimension; return !fireEvent(ISLAND_REMOVE_GENERATOR_RATE_EVENT, islandRemoveGeneratorRate).isCancelled(); } public static boolean callIslandRemoveRatingEvent(Island island, CommandSender commandSender, SuperiorPlayer ratingPlayer) { return callIslandRemoveRatingEvent(island, commandSenderToSuperiorPlayer(commandSender), ratingPlayer); } public static boolean callIslandRemoveRatingEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer) { IslandRemoveRating islandRemoveRating = new IslandRemoveRating(); islandRemoveRating.island = island; islandRemoveRating.superiorPlayer = superiorPlayer; islandRemoveRating.ratingPlayer = ratingPlayer; return !fireEvent(ISLAND_REMOVE_RATING_EVENT, islandRemoveRating).isCancelled(); } public static boolean callIslandRemoveRoleLimitEvent(Island island, CommandSender commandSender, PlayerRole playerRole) { return callIslandRemoveRoleLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole); } public static boolean callIslandRemoveRoleLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) { IslandRemoveRoleLimit islandRemoveRoleLimit = new IslandRemoveRoleLimit(); islandRemoveRoleLimit.island = island; islandRemoveRoleLimit.superiorPlayer = superiorPlayer; islandRemoveRoleLimit.playerRole = playerRole; return !fireEvent(ISLAND_REMOVE_ROLE_LIMIT_EVENT, islandRemoveRoleLimit).isCancelled(); } public static boolean callIslandRemoveVisitorHomeEvent(Island island, SuperiorPlayer superiorPlayer) { IslandRemoveVisitorHome islandRemoveVisitorHome = new IslandRemoveVisitorHome(); islandRemoveVisitorHome.island = island; islandRemoveVisitorHome.superiorPlayer = superiorPlayer; return !fireEvent(ISLAND_REMOVE_VISITOR_HOME_EVENT, islandRemoveVisitorHome).isCancelled(); } public static PluginEvent callIslandRenameEvent(Island island, CommandSender commandSender, String islandName) { return callIslandRenameEvent(island, commandSenderToSuperiorPlayer(commandSender), islandName); } public static PluginEvent callIslandRenameEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String islandName) { IslandRename islandRename = new IslandRename(); islandRename.island = island; islandRename.superiorPlayer = superiorPlayer; islandRename.islandName = islandName; return fireEvent(ISLAND_RENAME_EVENT, islandRename); } public static PluginEvent callIslandRenameWarpCategoryEvent(Island island, SuperiorPlayer superiorPlayer, WarpCategory warpCategory, String categoryName) { IslandRenameWarpCategory islandRenameWarpCategory = new IslandRenameWarpCategory(); islandRenameWarpCategory.island = island; islandRenameWarpCategory.superiorPlayer = superiorPlayer; islandRenameWarpCategory.warpCategory = warpCategory; islandRenameWarpCategory.categoryName = categoryName; return fireEvent(ISLAND_RENAME_WARP_CATEGORY_EVENT, islandRenameWarpCategory); } public static PluginEvent callIslandRenameWarpEvent(Island island, Player player, IslandWarp islandWarp, String warpName) { return callIslandRenameWarpEvent(island, commandSenderToSuperiorPlayer(player), islandWarp, warpName); } public static PluginEvent callIslandRenameWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp, String warpName) { IslandRenameWarp islandRenameWarp = new IslandRenameWarp(); islandRenameWarp.island = island; islandRenameWarp.superiorPlayer = superiorPlayer; islandRenameWarp.islandWarp = islandWarp; islandRenameWarp.warpName = warpName; return fireEvent(ISLAND_RENAME_WARP_EVENT, islandRenameWarp); } public static void callIslandRestrictMoveEvent(Island island, SuperiorPlayer superiorPlayer, IslandRestrictMoveEvent.RestrictReason restrictReason) { IslandRestrictMove islandRestrictMove = new IslandRestrictMove(); islandRestrictMove.island = island; islandRestrictMove.superiorPlayer = superiorPlayer; islandRestrictMove.restrictReason = restrictReason; fireEvent(ISLAND_RESTRICT_MOVE_EVENT, islandRestrictMove); } public static void callIslandSchematicPasteEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String schematicName, Location location) { IslandSchematicPaste islandSchematicPaste = new IslandSchematicPaste(); islandSchematicPaste.island = island; islandSchematicPaste.superiorPlayer = superiorPlayer; islandSchematicPaste.schematicName = schematicName; islandSchematicPaste.location = location; fireEvent(ISLAND_SCHEMATIC_PASTE_EVENT, islandSchematicPaste); } public static PluginEvent callIslandSetHomeEvent(Island island, CommandSender commandSender, Location islandHome, IslandSetHomeEvent.Reason reason) { return callIslandSetHomeEvent(island, commandSenderToSuperiorPlayer(commandSender), islandHome, reason); } public static PluginEvent callIslandSetHomeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Location islandHome, IslandSetHomeEvent.Reason reason) { IslandSetHome islandRenameWarp = new IslandSetHome(); islandRenameWarp.island = island; islandRenameWarp.superiorPlayer = superiorPlayer; islandRenameWarp.islandHome = islandHome; islandRenameWarp.reason = reason; return fireEvent(ISLAND_SET_HOME_EVENT, islandRenameWarp); } public static PluginEvent callIslandSetVisitorHomeEvent(Island island, SuperiorPlayer superiorPlayer, Location islandVisitorHome) { IslandSetVisitorHome islandSetVisitorHome = new IslandSetVisitorHome(); islandSetVisitorHome.island = island; islandSetVisitorHome.superiorPlayer = superiorPlayer; islandSetVisitorHome.islandVisitorHome = islandVisitorHome; return fireEvent(ISLAND_SET_VISITOR_HOME_EVENT, islandSetVisitorHome); } public static boolean callIslandTransferEvent(Island island, SuperiorPlayer previousOwner, SuperiorPlayer superiorPlayer) { IslandTransfer islandTransfer = new IslandTransfer(); islandTransfer.island = island; islandTransfer.superiorPlayer = superiorPlayer; islandTransfer.previousOwner = previousOwner; return !fireEvent(ISLAND_TRANSFER_EVENT, islandTransfer).isCancelled(); } public static boolean callIslandUnbanEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer unbannedPlayer) { IslandUnban islandUnban = new IslandUnban(); islandUnban.island = island; islandUnban.superiorPlayer = superiorPlayer; islandUnban.unbannedPlayer = unbannedPlayer; return !fireEvent(ISLAND_UNBAN_EVENT, islandUnban).isCancelled(); } public static boolean callIslandUncoopPlayerEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, IslandUncoopPlayerEvent.UncoopReason uncoopReason) { IslandUncoopPlayer islandUncoopPlayer = new IslandUncoopPlayer(); islandUncoopPlayer.island = island; islandUncoopPlayer.superiorPlayer = superiorPlayer; islandUncoopPlayer.targetPlayer = targetPlayer; islandUncoopPlayer.uncoopReason = uncoopReason; return !fireEvent(ISLAND_UNCOOP_PLAYER_EVENT, islandUncoopPlayer).isCancelled(); } public static boolean callIslandUnlockWorldEvent(Island island, CommandSender commandSender, Dimension dimension) { return callIslandUnlockWorldEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); } public static boolean callIslandUnlockWorldEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) { IslandUnlockWorld islandUncoopPlayer = new IslandUnlockWorld(); islandUncoopPlayer.island = island; islandUncoopPlayer.superiorPlayer = superiorPlayer; islandUncoopPlayer.dimension = dimension; return !fireEvent(ISLAND_UNLOCK_WORLD_EVENT, islandUncoopPlayer).isCancelled(); } public static PluginEvent callIslandUpgradeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Upgrade upgrade, UpgradeLevel currentLevel, UpgradeLevel nextLevel, IslandUpgradeEvent.Cause upgradeCause) { return callIslandUpgradeEvent(island, superiorPlayer, upgrade, nextLevel, currentLevel.getCommands(), upgradeCause, currentLevel.getCost()); } public static PluginEvent callIslandUpgradeEvent(Island island, CommandSender commandSender, Upgrade upgrade, UpgradeLevel nextLevel, IslandUpgradeEvent.Cause upgradeCause) { return callIslandUpgradeEvent(island, commandSenderToSuperiorPlayer(commandSender), upgrade, nextLevel, Collections.emptyList(), upgradeCause, null); } public static PluginEvent callIslandUpgradeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Upgrade upgrade, UpgradeLevel nextLevel, List commands, IslandUpgradeEvent.Cause upgradeCause, @Nullable UpgradeCost upgradeCost) { IslandUpgrade islandUpgrade = new IslandUpgrade(); islandUpgrade.island = island; islandUpgrade.superiorPlayer = superiorPlayer; islandUpgrade.upgrade = upgrade; islandUpgrade.nextLevel = nextLevel; islandUpgrade.commands = commands; islandUpgrade.upgradeCause = upgradeCause; islandUpgrade.upgradeCost = upgradeCost; return fireEvent(ISLAND_UPGRADE_EVENT, islandUpgrade); } public static boolean callIslandVisitorHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) { IslandVisitorHomeTeleport islandVisitorHomeTeleport = new IslandVisitorHomeTeleport(); islandVisitorHomeTeleport.island = island; islandVisitorHomeTeleport.superiorPlayer = superiorPlayer; islandVisitorHomeTeleport.dimension = dimension; return !fireEvent(ISLAND_VISITOR_HOME_TELEPORT_EVENT, islandVisitorHomeTeleport).isCancelled(); } public static boolean callIslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { IslandWarpTeleport islandWarpTeleport = new IslandWarpTeleport(); islandWarpTeleport.island = island; islandWarpTeleport.superiorPlayer = superiorPlayer; islandWarpTeleport.islandWarp = islandWarp; return !fireEvent(ISLAND_WARP_TELEPORT_EVENT, islandWarpTeleport).isCancelled(); } public static boolean callIslandWorldResetEvent(Island island, CommandSender commandSender, Dimension dimension) { return callIslandWorldResetEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); } public static boolean callIslandWorldResetEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) { IslandWorldReset islandWorldReset = new IslandWorldReset(); islandWorldReset.island = island; islandWorldReset.superiorPlayer = superiorPlayer; islandWorldReset.dimension = dimension; return !fireEvent(ISLAND_WORLD_RESET_EVENT, islandWorldReset).isCancelled(); } public static void callIslandWorthCalculatedEvent(Island island, SuperiorPlayer asker, BigDecimal islandLevel, BigDecimal islandWorth) { IslandWorthCalculated islandWorthCalculated = new IslandWorthCalculated(); islandWorthCalculated.island = island; islandWorthCalculated.superiorPlayer = asker; islandWorthCalculated.islandLevel = islandLevel; islandWorthCalculated.islandWorth = islandWorth; fireEvent(ISLAND_WORTH_CALCULATED_EVENT, islandWorthCalculated); } public static void callIslandWorthUpdateEvent(Island island, BigDecimal oldWorth, BigDecimal oldLevel, BigDecimal newWorth, BigDecimal newLevel) { IslandWorthUpdate islandWorthUpdate = new IslandWorthUpdate(); islandWorthUpdate.island = island; islandWorthUpdate.oldWorth = oldWorth; islandWorthUpdate.oldLevel = oldLevel; islandWorthUpdate.newWorth = newWorth; islandWorthUpdate.newLevel = newLevel; fireEvent(ISLAND_WORTH_UPDATE_EVENT, islandWorthUpdate); } public static PluginEvent callMissionCompleteEvent(SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, Mission mission, List itemRewards, List commandRewards) { MissionComplete missionComplete = new MissionComplete(); missionComplete.superiorPlayer = superiorPlayer; missionComplete.missionsHolder = missionsHolder; missionComplete.mission = mission; missionComplete.itemRewards = itemRewards; missionComplete.commandRewards = commandRewards; return fireEvent(MISSION_COMPLETE_EVENT, missionComplete); } public static boolean callMissionResetEvent(CommandSender commandSender, IMissionsHolder missionsHolder, Mission mission) { return callMissionResetEvent(commandSenderToSuperiorPlayer(commandSender), missionsHolder, mission); } public static boolean callMissionResetEvent(@Nullable SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, Mission mission) { MissionReset missionReset = new MissionReset(); missionReset.superiorPlayer = superiorPlayer; missionReset.missionsHolder = missionsHolder; missionReset.mission = mission; return !fireEvent(MISSION_RESET_EVENT, missionReset).isCancelled(); } public static boolean callPlayerChangeBorderColorEvent(SuperiorPlayer superiorPlayer, BorderColor borderColor) { PlayerChangeBorderColor playerChangeBorderColor = new PlayerChangeBorderColor(); playerChangeBorderColor.superiorPlayer = superiorPlayer; playerChangeBorderColor.borderColor = borderColor; return !fireEvent(PLAYER_CHANGE_BORDER_COLOR_EVENT, playerChangeBorderColor).isCancelled(); } public static boolean callPlayerChangeLanguageEvent(SuperiorPlayer superiorPlayer, Locale language) { PlayerChangeLanguage playerChangeLanguage = new PlayerChangeLanguage(); playerChangeLanguage.superiorPlayer = superiorPlayer; playerChangeLanguage.language = language; return !fireEvent(PLAYER_CHANGE_LANGUAGE_EVENT, playerChangeLanguage).isCancelled(); } public static void callPlayerChangeNameEvent(SuperiorPlayer superiorPlayer, String newName) { PlayerChangeName missionComplete = new PlayerChangeName(); missionComplete.superiorPlayer = superiorPlayer; missionComplete.newName = newName; fireEvent(PLAYER_CHANGE_NAME_EVENT, missionComplete); } public static boolean callPlayerChangeRoleEvent(SuperiorPlayer superiorPlayer, PlayerRole newRole) { PlayerChangeRole playerChangeRole = new PlayerChangeRole(); playerChangeRole.superiorPlayer = superiorPlayer; playerChangeRole.newRole = newRole; return !fireEvent(PLAYER_CHANGE_ROLE_EVENT, playerChangeRole).isCancelled(); } public static PluginEvent callPlayerCloseMenuEvent(SuperiorPlayer superiorPlayer, MenuView menuView, @Nullable MenuView newMenuView) { PlayerCloseMenu playerCloseMenu = new PlayerCloseMenu(); playerCloseMenu.superiorPlayer = superiorPlayer; playerCloseMenu.menuView = menuView; playerCloseMenu.newMenuView = newMenuView; return fireEvent(PLAYER_CLOSE_MENU_EVENT, playerCloseMenu); } public static boolean callPlayerOpenMenuEvent(SuperiorPlayer superiorPlayer, MenuView menuView) { PlayerOpenMenu playerOpenMenu = new PlayerOpenMenu(); playerOpenMenu.superiorPlayer = superiorPlayer; playerOpenMenu.menuView = menuView; return !fireEvent(PLAYER_OPEN_MENU_EVENT, playerOpenMenu).isCancelled(); } public static void callPlayerReplaceEvent(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) { PlayerReplace playerReplace = new PlayerReplace(); playerReplace.superiorPlayer = oldPlayer; playerReplace.newPlayer = newPlayer; fireEvent(PLAYER_REPLACE_EVENT, playerReplace); } public static boolean callPlayerToggleBlocksStackerEvent(SuperiorPlayer superiorPlayer) { PlayerToggleBlocksStacker playerToggleBlocksStacker = new PlayerToggleBlocksStacker(); playerToggleBlocksStacker.superiorPlayer = superiorPlayer; return !fireEvent(PLAYER_TOGGLE_BLOCKS_STACKER_EVENT, playerToggleBlocksStacker).isCancelled(); } public static boolean callPlayerToggleBorderEvent(SuperiorPlayer superiorPlayer) { PlayerToggleBorder playerToggleBorder = new PlayerToggleBorder(); playerToggleBorder.superiorPlayer = superiorPlayer; return !fireEvent(PLAYER_TOGGLE_BORDER_EVENT, playerToggleBorder).isCancelled(); } public static boolean callPlayerToggleBypassEvent(SuperiorPlayer superiorPlayer) { PlayerToggleBypass playerToggleBypass = new PlayerToggleBypass(); playerToggleBypass.superiorPlayer = superiorPlayer; return !fireEvent(PLAYER_TOGGLE_BYPASS_EVENT, playerToggleBypass).isCancelled(); } public static boolean callPlayerToggleFlyEvent(SuperiorPlayer superiorPlayer) { PlayerToggleFly playerToggleFly = new PlayerToggleFly(); playerToggleFly.superiorPlayer = superiorPlayer; return !fireEvent(PLAYER_TOGGLE_FLY_EVENT, playerToggleFly).isCancelled(); } public static boolean callPlayerTogglePanelEvent(SuperiorPlayer superiorPlayer) { PlayerTogglePanel playerTogglePanel = new PlayerTogglePanel(); playerTogglePanel.superiorPlayer = superiorPlayer; return !fireEvent(PLAYER_TOGGLE_PANEL_EVENT, playerTogglePanel).isCancelled(); } public static boolean callPlayerToggleSpyEvent(SuperiorPlayer superiorPlayer) { PlayerToggleSpy playerToggleSpy = new PlayerToggleSpy(); playerToggleSpy.superiorPlayer = superiorPlayer; return !fireEvent(PLAYER_TOGGLE_SPY_EVENT, playerToggleSpy).isCancelled(); } public static boolean callPlayerToggleTeamChatEvent(SuperiorPlayer superiorPlayer) { PlayerToggleTeamChat playerToggleTeamChat = new PlayerToggleTeamChat(); playerToggleTeamChat.superiorPlayer = superiorPlayer; return !fireEvent(PLAYER_TOGGLE_TEAM_CHAT_EVENT, playerToggleTeamChat).isCancelled(); } public static void callPluginInitializedEvent() { PluginInitialized pluginInitialized = new PluginInitialized(); pluginInitialized.plugin = plugin; fireEvent(PLUGIN_INITIALIZED_EVENT, pluginInitialized); } public static PluginEvent callPluginInitializeEvent() { PluginInitialize pluginInitialize = new PluginInitialize(); pluginInitialize.plugin = plugin; return fireEvent(PLUGIN_INITIALIZE_EVENT, pluginInitialize); } public static boolean callPluginLoadDataEvent() { PluginLoadData pluginLoadData = new PluginLoadData(); pluginLoadData.plugin = plugin; return !fireEvent(PLUGIN_LOAD_DATA_EVENT, pluginLoadData).isCancelled(); } public static void callPostIslandCreateEvent(Island island, SuperiorPlayer superiorPlayer) { PostIslandCreate postIslandCreate = new PostIslandCreate(); postIslandCreate.island = island; postIslandCreate.superiorPlayer = superiorPlayer; fireEvent(POST_ISLAND_CREATE_EVENT, postIslandCreate); } public static boolean callPreIslandCreateEvent(SuperiorPlayer superiorPlayer, String islandName) { PreIslandCreate preIslandCreate = new PreIslandCreate(); preIslandCreate.superiorPlayer = superiorPlayer; preIslandCreate.islandName = islandName; return !fireEvent(PRE_ISLAND_CREATE_EVENT, preIslandCreate).isCancelled(); } public static PluginEvent callSendMessageEvent(CommandSender receiver, String messageType, IMessageComponent messageComponent, Object... args) { SendMessage pluginInitialize = new SendMessage(); pluginInitialize.receiver = receiver; pluginInitialize.messageType = messageType; pluginInitialize.messageComponent = messageComponent; pluginInitialize.args = args; return fireEvent(SEND_MESSAGE_EVENT, pluginInitialize); } private static PluginEvent fireEvent(PluginEventType type, Args args) { return plugin.getPluginEventsDispatcher().fireEvent(type, args); } @Nullable private static SuperiorPlayer commandSenderToSuperiorPlayer(@Nullable CommandSender commandSender) { return commandSender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(commandSender) : null; } private PluginEventsFactory() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/factory/DefaultBanksFactory.java ================================================ package com.bgsoftware.superiorskyblock.core.factory; import com.bgsoftware.superiorskyblock.api.factory.BanksFactory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; public class DefaultBanksFactory implements BanksFactory { private static final DefaultBanksFactory INSTANCE = new DefaultBanksFactory(); public static DefaultBanksFactory getInstance() { return INSTANCE; } private DefaultBanksFactory() { } @Override public IslandBank createIslandBank(Island island, IslandBank original) { return original; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/factory/DefaultDatabaseBridgeFactory.java ================================================ package com.bgsoftware.superiorskyblock.core.factory; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.factory.DatabaseBridgeFactory; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public class DefaultDatabaseBridgeFactory implements DatabaseBridgeFactory { private static final DefaultDatabaseBridgeFactory INSTANCE = new DefaultDatabaseBridgeFactory(); public static DefaultDatabaseBridgeFactory getInstance() { return INSTANCE; } private DefaultDatabaseBridgeFactory() { } @Override public DatabaseBridge createIslandsDatabaseBridge(@Nullable Island island, DatabaseBridge original) { return original; } @Override public DatabaseBridge createPlayersDatabaseBridge(@Nullable SuperiorPlayer superiorPlayer, DatabaseBridge original) { return original; } @Override public DatabaseBridge createGridDatabaseBridge(@Nullable GridManager gridManager, DatabaseBridge original) { return original; } @Override public DatabaseBridge createStackedBlocksDatabaseBridge(@Nullable StackedBlocksManager stackedBlocksManager, DatabaseBridge original) { return original; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/factory/DefaultIslandsFactory.java ================================================ package com.bgsoftware.superiorskyblock.core.factory; import com.bgsoftware.superiorskyblock.api.factory.IslandsFactory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; public class DefaultIslandsFactory implements IslandsFactory { private static final DefaultIslandsFactory INSTANCE = new DefaultIslandsFactory(); public static DefaultIslandsFactory getInstance() { return INSTANCE; } private DefaultIslandsFactory() { } @Override public Island createIsland(Island original) { return original; } @Override public IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island, IslandCalculationAlgorithm original) { return original; } @Override public IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island, IslandBlocksTrackerAlgorithm original) { return original; } @Override public IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island, IslandEntitiesTrackerAlgorithm original) { return original; } @Override public PersistentDataContainer createPersistentDataContainer(Island island, PersistentDataContainer original) { return original; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/factory/DefaultPlayersFactory.java ================================================ package com.bgsoftware.superiorskyblock.core.factory; import com.bgsoftware.superiorskyblock.api.factory.PlayersFactory; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public class DefaultPlayersFactory implements PlayersFactory { private static final DefaultPlayersFactory INSTANCE = new DefaultPlayersFactory(); public static DefaultPlayersFactory getInstance() { return INSTANCE; } private DefaultPlayersFactory() { } @Override public SuperiorPlayer createPlayer(SuperiorPlayer original) { return original; } @Override public PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer, PlayerTeleportAlgorithm original) { return original; } @Override public PersistentDataContainer createPersistentDataContainer(SuperiorPlayer superiorPlayer, PersistentDataContainer original) { return original; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.factory; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.enums.BankAction; import com.bgsoftware.superiorskyblock.api.factory.BanksFactory; import com.bgsoftware.superiorskyblock.api.factory.DatabaseBridgeFactory; import com.bgsoftware.superiorskyblock.api.factory.IslandsFactory; import com.bgsoftware.superiorskyblock.api.factory.PlayersFactory; import com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.WorldInfoImpl; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.sql.SQLDatabaseBridge; import com.bgsoftware.superiorskyblock.core.persistence.PersistentDataContainerImpl; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.island.bank.SBankTransaction; import com.bgsoftware.superiorskyblock.island.bank.SIslandBank; import com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.player.algorithm.DefaultPlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; import com.bgsoftware.superiorskyblock.world.schematic.options.SchematicOptionsBuilderImpl; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.Sound; import java.math.BigDecimal; import java.util.UUID; import java.util.function.Supplier; public class FactoriesManagerImpl implements FactoriesManager { private IslandsFactory islandsFactory = DefaultIslandsFactory.getInstance(); private PlayersFactory playersFactory = DefaultPlayersFactory.getInstance(); private BanksFactory banksFactory = DefaultBanksFactory.getInstance(); private DatabaseBridgeFactory databaseBridgeFactory = DefaultDatabaseBridgeFactory.getInstance(); @Override public void registerIslandsFactory(@Nullable IslandsFactory islandsFactory) { this.islandsFactory = islandsFactory == null ? DefaultIslandsFactory.getInstance() : islandsFactory; } @Override public IslandsFactory getIslandsFactory() { return islandsFactory; } @Override public void registerPlayersFactory(@Nullable PlayersFactory playersFactory) { this.playersFactory = playersFactory == null ? DefaultPlayersFactory.getInstance() : playersFactory; } @Override public PlayersFactory getPlayersFactory() { return playersFactory; } @Override public void registerBanksFactory(@Nullable BanksFactory banksFactory) { this.banksFactory = banksFactory == null ? DefaultBanksFactory.getInstance() : banksFactory; } @Override public BanksFactory getBanksFactory() { return banksFactory; } @Override public void registerDatabaseBridgeFactory(@Nullable DatabaseBridgeFactory databaseBridgeFactory) { this.databaseBridgeFactory = databaseBridgeFactory == null ? DefaultDatabaseBridgeFactory.getInstance() : databaseBridgeFactory; } @Override public DatabaseBridgeFactory getDatabaseBridgeFactory() { return databaseBridgeFactory; } @Override public Island createIsland(@Nullable SuperiorPlayer owner, UUID uuid, Location center, String islandName, String schemName) { Preconditions.checkNotNull(uuid, "uuid parameter cannot be null."); Preconditions.checkNotNull(center, "center parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); Preconditions.checkNotNull(schemName, "schemName parameter cannot be null."); return createIslandBuilder() .setOwner(owner) .setUniqueId(uuid) .setCenter(center) .setName(islandName) .setSchematicName(schemName) .build(); } @Override public Island.Builder createIslandBuilder() { return new IslandBuilderImpl(); } public Island createIsland(IslandBuilderImpl builder) { return islandsFactory.createIsland(new SIsland(builder)); } @Override public SuperiorPlayer createPlayer(UUID playerUUID) { Preconditions.checkNotNull(playerUUID, "playerUUID parameter cannot be null."); OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerUUID); SuperiorPlayer.Builder builder = createPlayerBuilder() .setUniqueId(playerUUID); if (offlinePlayer != null && offlinePlayer.getName() != null) builder.setName(offlinePlayer.getName()); return builder.build(); } @Override public SuperiorPlayer.Builder createPlayerBuilder() { return new SuperiorPlayerBuilderImpl(); } public SuperiorPlayer createPlayer(SuperiorPlayerBuilderImpl builder) { return playersFactory.createPlayer(new SSuperiorPlayer(builder)); } @Override public BlockOffset createBlockOffset(int offsetX, int offsetY, int offsetZ) { return SBlockOffset.fromOffsets(offsetX, offsetY, offsetZ); } @Override @Deprecated public BlockPosition createBlockPosition(String world, int blockX, int blockY, int blockZ) { return createBlockPosition(blockX, blockY, blockZ); } @Override public BlockPosition createBlockPosition(int blockX, int blockY, int blockZ) { return SBlockPosition.of(blockX, blockY, blockZ); } @Override public BlockPosition createBlockPosition(Location location) { Preconditions.checkNotNull(location, "location cannot be null."); return SBlockPosition.of(location); } @Override public WorldPosition createWorldPosition(double x, double y, double z) { return SWorldPosition.of(x, y, z); } @Override public WorldPosition createWorldPosition(double x, double y, double z, float yaw, float pitch) { return SWorldPosition.of(x, y, z, yaw, pitch); } @Override public WorldPosition createWorldPosition(Location location) { Preconditions.checkNotNull(location, "location cannot be null."); return SWorldPosition.of(location); } @Override public BankTransaction createTransaction(@Nullable UUID player, BankAction action, int position, long time, String failureReason, BigDecimal amount) { Preconditions.checkNotNull(action, "action parameter cannot be null"); Preconditions.checkNotNull(amount, "amount parameter cannot be null"); return new SBankTransaction(player, action, position, time, failureReason, amount); } @Override public WorldInfo createWorldInfo(String worldName, Dimension dimension) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null"); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); return new WorldInfoImpl(worldName, dimension); } @Override public GameSound createGameSound(Sound sound, float volume, float pitch) { Preconditions.checkNotNull(sound, "sound parameter cannot be null"); return new GameSoundImpl(sound, volume, pitch); } @Override public SchematicOptions.Builder createSchematicOptionsBuilder(String schematicName) { Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null"); return new SchematicOptionsBuilderImpl(schematicName); } public IslandBank createIslandBank(Island island, Supplier isGiveInterestFailed) { return banksFactory.createIslandBank(island, new SIslandBank(island, isGiveInterestFailed)); } public IslandCalculationAlgorithm createIslandCalculationAlgorithm(Island island) { try { // noinspection deprecation return islandsFactory.createIslandCalculationAlgorithm(island); } catch (UnsupportedOperationException error) { return islandsFactory.createIslandCalculationAlgorithm(island, DefaultIslandCalculationAlgorithm.getInstance()); } } public IslandBlocksTrackerAlgorithm createIslandBlocksTrackerAlgorithm(Island island) { try { // noinspection deprecation return islandsFactory.createIslandBlocksTrackerAlgorithm(island); } catch (UnsupportedOperationException error) { return islandsFactory.createIslandBlocksTrackerAlgorithm(island, new DefaultIslandBlocksTrackerAlgorithm(island)); } } public IslandEntitiesTrackerAlgorithm createIslandEntitiesTrackerAlgorithm(Island island) { try { // noinspection deprecation return islandsFactory.createIslandEntitiesTrackerAlgorithm(island); } catch (UnsupportedOperationException error) { return islandsFactory.createIslandEntitiesTrackerAlgorithm(island, new DefaultIslandEntitiesTrackerAlgorithm(island)); } } public PlayerTeleportAlgorithm createPlayerTeleportAlgorithm(SuperiorPlayer superiorPlayer) { try { // noinspection deprecation return playersFactory.createPlayerTeleportAlgorithm(superiorPlayer); } catch (UnsupportedOperationException error) { return playersFactory.createPlayerTeleportAlgorithm(superiorPlayer, DefaultPlayerTeleportAlgorithm.getInstance()); } } public boolean hasCustomDatabaseBridge() { return databaseBridgeFactory != DefaultDatabaseBridgeFactory.getInstance(); } public DatabaseBridge createDatabaseBridge(Island island) { return databaseBridgeFactory.createIslandsDatabaseBridge(island, new SQLDatabaseBridge()); } public DatabaseBridge createDatabaseBridge(SuperiorPlayer superiorPlayer) { return databaseBridgeFactory.createPlayersDatabaseBridge(superiorPlayer, new SQLDatabaseBridge()); } public DatabaseBridge createDatabaseBridge(GridManager gridManager) { return databaseBridgeFactory.createGridDatabaseBridge(gridManager, new SQLDatabaseBridge()); } public DatabaseBridge createDatabaseBridge(StackedBlocksManager stackedBlocksManager) { return databaseBridgeFactory.createStackedBlocksDatabaseBridge(stackedBlocksManager, new SQLDatabaseBridge()); } public PersistentDataContainer createPersistentDataContainer(Island island) { return islandsFactory.createPersistentDataContainer(island, new PersistentDataContainerImpl<>( island, IslandsDatabaseBridge::markPersistentDataContainerToBeSaved)); } public PersistentDataContainer createPersistentDataContainer(SuperiorPlayer superiorPlayer) { return playersFactory.createPersistentDataContainer(superiorPlayer, new PersistentDataContainerImpl<>( superiorPlayer, PlayersDatabaseBridge::markPersistentDataContainerToBeSaved)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/Formatters.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.formatting.impl.BlockPositionFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.BooleanFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.BorderColorFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.CapitalizedFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.ColorFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.CommaFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.DateFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.FancyNumberFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.LocaleFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.LocationFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.NumberFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.RatingFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.StripColorFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.TimeFormatter; import org.bukkit.Location; import java.time.Duration; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.stream.Collectors; import java.util.stream.Stream; public class Formatters { public static final IBiFormatter BOOLEAN_FORMATTER = BooleanFormatter.getInstance(); public static final IBiFormatter BORDER_COLOR_FORMATTER = BorderColorFormatter.getInstance(); public static final IFormatter CAPITALIZED_FORMATTER = CapitalizedFormatter.getInstance(); public static final IFormatter COLOR_FORMATTER = ColorFormatter.getInstance(); public static final IFormatter> COMMA_FORMATTER = CommaFormatter.getInstance(); public static final IFormatter DATE_FORMATTER = DateFormatter.getInstance(); public static final IBiFormatter FANCY_NUMBER_FORMATTER = FancyNumberFormatter.getInstance(); public static final IFormatter LOCALE_FORMATTER = LocaleFormatter.getInstance(); public static final IFormatter LOCATION_FORMATTER = LocationFormatter.getInstance(); public static final IFormatter NUMBER_FORMATTER = NumberFormatter.getInstance(); public static final IBiFormatter RATING_FORMATTER = RatingFormatter.getInstance(); public static final IFormatter STRIP_COLOR_FORMATTER = StripColorFormatter.getInstance(); public static final IBiFormatter TIME_FORMATTER = TimeFormatter.getInstance(); public static final IFormatter CHAT_FORMATTER = ChatFormatter.getInstance(); public static final IBiFormatter BLOCK_POSITION_FORMATTER = BlockPositionFormatter.getInstance(); private Formatters() { } public static List formatList(List list, IFormatter formatter) { return list.stream().map(formatter::format).collect(Collectors.toList()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/IBiFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting; public interface IBiFormatter { String format(T value, K value2); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/IFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting; public interface IFormatter { String format(T value); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BlockPositionFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; public class BlockPositionFormatter implements IBiFormatter { private static final BlockPositionFormatter INSTANCE = new BlockPositionFormatter(); public static BlockPositionFormatter getInstance() { return INSTANCE; } private BlockPositionFormatter() { } @Override public String format(BlockPosition value, WorldInfo worldInfo) { return worldInfo.getName() + ", " + value.getX() + ", " + value.getY() + ", " + value.getZ(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BooleanFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import java.util.Locale; public class BooleanFormatter implements IBiFormatter { private static final BooleanFormatter INSTANCE = new BooleanFormatter(); public static BooleanFormatter getInstance() { return INSTANCE; } private BooleanFormatter() { } @Override public String format(Boolean value, Locale locale) { return (value ? Message.PLACEHOLDER_YES : Message.PLACEHOLDER_NO).getMessage(locale); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BorderColorFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import java.util.EnumMap; import java.util.Locale; public class BorderColorFormatter implements IBiFormatter { private static final BorderColorFormatter INSTANCE = new BorderColorFormatter(); private static final EnumMap BORDER_COLOR_MESSAGES = new EnumMap<>(BorderColor.class); static { BORDER_COLOR_MESSAGES.put(BorderColor.RED, Message.BORDER_PLAYER_COLOR_NAME_RED); BORDER_COLOR_MESSAGES.put(BorderColor.BLUE, Message.BORDER_PLAYER_COLOR_NAME_BLUE); BORDER_COLOR_MESSAGES.put(BorderColor.GREEN, Message.BORDER_PLAYER_COLOR_NAME_GREEN); } public static BorderColorFormatter getInstance() { return INSTANCE; } private BorderColorFormatter() { } @Override public String format(BorderColor value, Locale locale) { return BORDER_COLOR_MESSAGES.get(value).getMessage(locale); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/CapitalizedFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import java.util.Locale; public class CapitalizedFormatter implements IFormatter { private static final CapitalizedFormatter INSTANCE = new CapitalizedFormatter(); public static CapitalizedFormatter getInstance() { return INSTANCE; } private CapitalizedFormatter() { } @Override public String format(String value) { StringBuilder formattedKey = new StringBuilder(); try { String[] split = value.split(":"); //Checking if the type is : Integer.parseInt(split[1]); value = split[0]; } catch (Throwable ignored) { } value = value.replace(":", "_-_"); for (String subKey : value.split("_")) { if (!Text.isBlank(subKey)) { formattedKey.append(" ") .append(subKey.substring(0, 1).toUpperCase(Locale.ENGLISH)) .append(subKey.substring(1).toLowerCase(Locale.ENGLISH)); } } return formattedKey.substring(1); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ChatFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.player.PlayerLocales; public class ChatFormatter implements IFormatter { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final ChatFormatter INSTANCE = new ChatFormatter(); public static ChatFormatter getInstance() { return INSTANCE; } private ChatFormatter() { } @Override public String format(ChatFormatter.ChatFormatArgs args) { String islandNameFormat = Message.NAME_CHAT_FORMAT.getMessage(PlayerLocales.getDefaultLocale(), args.island == null ? "" : args.island.getName()); return args.format .replace("{island-level}", String.valueOf(args.island == null ? 0 : args.island.getIslandLevel())) .replace("{island-level-format}", String.valueOf(args.island == null ? 0 : Formatters.FANCY_NUMBER_FORMATTER.format(args.island.getIslandLevel(), args.superiorPlayer.getUserLocale()))) .replace("{island-worth}", String.valueOf(args.island == null ? 0 : args.island.getWorth())) .replace("{island-worth-format}", String.valueOf(args.island == null ? 0 : Formatters.FANCY_NUMBER_FORMATTER.format(args.island.getWorth(), args.superiorPlayer.getUserLocale()))) .replace("{island-name}", islandNameFormat == null ? "" : islandNameFormat) .replace("{island-role}", args.superiorPlayer.getPlayerRole().getDisplayName()) .replace("{island-position-worth}", args.island == null ? "" : (plugin.getGrid().getIslandPosition(args.island, SortingTypes.BY_WORTH) + 1) + "") .replace("{island-position-level}", args.island == null ? "" : (plugin.getGrid().getIslandPosition(args.island, SortingTypes.BY_LEVEL) + 1) + "") .replace("{island-position-rating}", args.island == null ? "" : (plugin.getGrid().getIslandPosition(args.island, SortingTypes.BY_RATING) + 1) + "") .replace("{island-position-players}", args.island == null ? "" : (plugin.getGrid().getIslandPosition(args.island, SortingTypes.BY_PLAYERS) + 1) + ""); } public static class ChatFormatArgs { private final String format; private final SuperiorPlayer superiorPlayer; @Nullable private final Island island; public ChatFormatArgs(String format, SuperiorPlayer superiorPlayer, @Nullable Island island) { this.format = format; this.superiorPlayer = superiorPlayer; this.island = island; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ColorFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import com.bgsoftware.superiorskyblock.external.text.ITextFormatter; import org.bukkit.ChatColor; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ColorFormatter implements IFormatter { private static final ColorFormatter INSTANCE = new ColorFormatter(); private static final List TEXT_FORMATTERS = new LinkedList<>(); static { TEXT_FORMATTERS.add(ChatColorTextFormatter.INSTANCE); if (ServerVersion.isAtLeast(ServerVersion.v1_16)) TEXT_FORMATTERS.add(HexTextFormatter.INSTANCE); } private static final Pattern HEX_COLOR_PATTERN = Pattern.compile("([&§])(\\{HEX:([0-9A-Fa-f]*)})"); public static ColorFormatter getInstance() { return INSTANCE; } private ColorFormatter() { } @Override public String format(String value) { if (Text.isBlank(value)) return ""; String output = value; for (ITextFormatter formatter : TEXT_FORMATTERS) { output = formatter.format(output); } return output; } private static class ChatColorTextFormatter implements ITextFormatter { private static final ChatColorTextFormatter INSTANCE = new ChatColorTextFormatter(); @Override public String format(String value) { return ChatColor.translateAlternateColorCodes('&', value); } } private static class HexTextFormatter implements ITextFormatter { private static final HexTextFormatter INSTANCE = new HexTextFormatter(); @Override public String format(String value) { while (true) { Matcher matcher = HEX_COLOR_PATTERN.matcher(value); if (!matcher.find()) break; value = matcher.replaceFirst(parseHexColor(matcher.group(3))); } return value; } private static String parseHexColor(String hexColor) { if (hexColor.length() != 6 && hexColor.length() != 3) return hexColor; StringBuilder magic = new StringBuilder(ChatColor.COLOR_CHAR + "x"); int multiplier = hexColor.length() == 3 ? 2 : 1; for (char ch : hexColor.toCharArray()) { for (int i = 0; i < multiplier; i++) magic.append(ChatColor.COLOR_CHAR).append(ch); } return magic.toString(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/CommaFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import java.util.stream.Stream; public class CommaFormatter implements IFormatter> { private static final CommaFormatter INSTANCE = new CommaFormatter(); public static CommaFormatter getInstance() { return INSTANCE; } private CommaFormatter() { } @Override public String format(Stream values) { StringBuilder stringBuilder = new StringBuilder(); values.forEach(value -> stringBuilder.append(", ").append(value)); return stringBuilder.substring(2); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/DateFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import java.text.SimpleDateFormat; import java.util.Date; public class DateFormatter implements IFormatter { private static final DateFormatter INSTANCE = new DateFormatter(); private static SimpleDateFormat dateFormatter; public static void setDateFormatter(SuperiorSkyblockPlugin plugin, String dateFormat) { dateFormatter = new SimpleDateFormat(dateFormat); try { for (Island island : plugin.getGrid().getIslands()) { island.updateDatesFormatter(); } } catch (Exception ignored) { } } public static DateFormatter getInstance() { return INSTANCE; } private DateFormatter() { } @Override public String format(Date value) { return dateFormatter.format(value); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/FancyNumberFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import java.util.Locale; public class FancyNumberFormatter implements IBiFormatter { private static final FancyNumberFormatter INSTANCE = new FancyNumberFormatter(); private static final double Q = 1000000000000000D; private static final double T = 1000000000000D; private static final double B = 1000000000D; private static final double M = 1000000D; private static final double K = 1000D; public static FancyNumberFormatter getInstance() { return INSTANCE; } private FancyNumberFormatter() { } @Override public String format(Number value, Locale locale) { double doubleValue = value.doubleValue(); if (doubleValue >= Q) return Formatters.NUMBER_FORMATTER.format(doubleValue / Q) + Message.FORMAT_QUAD.getMessage(locale); else if (doubleValue >= T) return Formatters.NUMBER_FORMATTER.format(doubleValue / T) + Message.FORMAT_TRILLION.getMessage(locale); else if (doubleValue >= B) return Formatters.NUMBER_FORMATTER.format(doubleValue / B) + Message.FORMAT_BILLION.getMessage(locale); else if (doubleValue >= M) return Formatters.NUMBER_FORMATTER.format(doubleValue / M) + Message.FORMAT_MILLION.getMessage(locale); else if (doubleValue >= K) return Formatters.NUMBER_FORMATTER.format(doubleValue / K) + Message.FORMAT_THOUSANDS.getMessage(locale); else return Formatters.NUMBER_FORMATTER.format(value); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/LocaleFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import java.util.Locale; public class LocaleFormatter implements IFormatter { private static final LocaleFormatter INSTANCE = new LocaleFormatter(); public static LocaleFormatter getInstance() { return INSTANCE; } private LocaleFormatter() { } @Override public String format(Locale value) { return value.getLanguage() + "-" + value.getCountry(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/LocationFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import org.bukkit.Location; public class LocationFormatter implements IFormatter { private static final LocationFormatter INSTANCE = new LocationFormatter(); public static LocationFormatter getInstance() { return INSTANCE; } private LocationFormatter() { } @Override public String format(Location value) { return LazyWorldLocation.getWorldName(value) + ", " + value.getBlockX() + ", " + value.getBlockY() + ", " + value.getBlockZ(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/NumberFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import com.bgsoftware.superiorskyblock.core.logging.Log; import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.regex.Matcher; import java.util.regex.Pattern; public class NumberFormatter implements IFormatter { private static final NumberFormatter INSTANCE = new NumberFormatter(); private static final Pattern NUMBER_PATTERN = Pattern.compile("^[a-z]{2}[_|-][A-Z]{2}$"); private static final char SPACE_ASCII = 160; private static Pattern DECIMAL_PATTERN; private static DecimalFormat numberFormatter; private static char decimalSeparator; public static void setNumberFormatter(String numberFormat) { numberFormat = numberFormat.replace("_", "-"); if (!NUMBER_PATTERN.matcher(numberFormat).matches()) { Log.warn("The number format \"", numberFormat, "\" is invalid. Using default one: en-US."); numberFormat = "en-US"; } String[] numberFormatSections = numberFormat.split("-"); numberFormatter = (DecimalFormat) NumberFormat.getInstance(new java.util.Locale(numberFormatSections[0], numberFormatSections[1])); numberFormatter.setGroupingUsed(true); numberFormatter.setMinimumFractionDigits(2); numberFormatter.setMaximumFractionDigits(2); numberFormatter.setRoundingMode(RoundingMode.FLOOR); decimalSeparator = numberFormatter.getDecimalFormatSymbols().getDecimalSeparator(); DECIMAL_PATTERN = Pattern.compile("(.*)" + Pattern.quote(decimalSeparator + "") + "(\\d)0"); } public static NumberFormatter getInstance() { return INSTANCE; } private NumberFormatter() { } @Override public String format(Number value) { //Because of some issues with formatting, spaces are converted to ascii 160. String formattedNumber = numberFormatter.format(value).replace(SPACE_ASCII, ' '); Matcher matcher; if (formattedNumber.endsWith(decimalSeparator + "00")) { return formattedNumber.replace(decimalSeparator + "00", ""); } else if ((matcher = DECIMAL_PATTERN.matcher(formattedNumber)).matches()) { return formattedNumber.replaceAll(Pattern.quote(decimalSeparator + "") + "(\\d)0", decimalSeparator + matcher.group(2)); } return formattedNumber; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/RatingFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import java.util.Locale; public class RatingFormatter implements IBiFormatter { private static final RatingFormatter INSTANCE = new RatingFormatter(); public static RatingFormatter getInstance() { return INSTANCE; } private RatingFormatter() { } @Override public String format(Number value, Locale locale) { StringBuilder starsString = new StringBuilder(); double rating = value.doubleValue(); if (rating >= 1) starsString.append(Message.ISLAND_INFO_RATE_ONE_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale)); if (rating >= 2) starsString.append(Message.ISLAND_INFO_RATE_TWO_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale)); if (rating >= 3) starsString.append(Message.ISLAND_INFO_RATE_THREE_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale)); if (rating >= 4) starsString.append(Message.ISLAND_INFO_RATE_FOUR_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale)); if (rating >= 5) starsString.append(Message.ISLAND_INFO_RATE_FIVE_COLOR.getMessage(locale)).append(Message.ISLAND_INFO_RATE_SYMBOL.getMessage(locale)); for (int i = 5; i > rating && i > 0; i--) starsString.append(Message.ISLAND_INFO_RATE_EMPTY_SYMBOL.getMessage(locale)); return starsString.toString(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/StripColorFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import com.bgsoftware.superiorskyblock.core.Text; import java.util.regex.Pattern; public class StripColorFormatter implements IFormatter { private static final StripColorFormatter INSTANCE = new StripColorFormatter(); private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)([&§])[0-9A-FK-OR]"); public static StripColorFormatter getInstance() { return INSTANCE; } private StripColorFormatter() { } @Override public String format(String value) { return Text.isBlank(value) ? "" : STRIP_COLOR_PATTERN.matcher(value).replaceAll(""); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/TimeFormatter.java ================================================ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import java.time.Duration; import java.util.Locale; public class TimeFormatter implements IBiFormatter { private static final TimeFormatter INSTANCE = new TimeFormatter(); public static TimeFormatter getInstance() { return INSTANCE; } private TimeFormatter() { } @Override public String format(Duration value, Locale locale) { Locale formatLocale = locale == null ? PlayerLocales.getDefaultLocale() : locale; StringBuilder timeBuilder = new StringBuilder(); boolean RTL = PlayerLocales.isRightToLeft(formatLocale); { long days = value.toDays(); if (days > 0) { formatTimeSection(timeBuilder, RTL, days, days == 1 ? Message.FORMAT_DAY_NAME : Message.FORMAT_DAYS_NAME, formatLocale); value = value.minusDays(days); } } { long hours = value.toHours(); if (hours > 0) { formatTimeSection(timeBuilder, RTL, hours, hours == 1 ? Message.FORMAT_HOUR_NAME : Message.FORMAT_HOURS_NAME, formatLocale); value = value.minusHours(hours); } } { long minutes = value.toMinutes(); if (minutes > 0) { formatTimeSection(timeBuilder, RTL, minutes, minutes == 1 ? Message.FORMAT_MINUTE_NAME : Message.FORMAT_MINUTES_NAME, formatLocale); value = value.minusMinutes(minutes); } } { long seconds = value.getSeconds(); if (seconds > 0) formatTimeSection(timeBuilder, RTL, seconds, seconds == 1 ? Message.FORMAT_SECOND_NAME : Message.FORMAT_SECONDS_NAME, formatLocale); } if (timeBuilder.length() == 0) { if (RTL) { timeBuilder.insert(0, "1 ").append(Message.FORMAT_SECOND_NAME.getMessage(formatLocale)).insert(0, " ,"); } else { timeBuilder.append("1 ").append(Message.FORMAT_SECOND_NAME.getMessage(formatLocale)).append(", "); } } return RTL ? timeBuilder.substring(2) : timeBuilder.substring(0, timeBuilder.length() - 2); } private static void formatTimeSection(StringBuilder stringBuilder, boolean RTL, long value, Message timeFormatMessage, Locale locale) { if (RTL) { stringBuilder.insert(0, value) .insert(0, " ") .insert(0, timeFormatMessage.getMessage(locale)) .insert(0, ", "); } else { stringBuilder.append(value) .append(" ") .append(timeFormatMessage.getMessage(locale)) .append(", "); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/ClassProcessor.java ================================================ package com.bgsoftware.superiorskyblock.core.io; public interface ClassProcessor { byte[] processClass(byte[] classBytes, String path); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/FileClassLoader.java ================================================ package com.bgsoftware.superiorskyblock.core.io; import com.bgsoftware.common.annotations.Nullable; import com.google.common.io.ByteStreams; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import java.security.CodeSigner; import java.security.CodeSource; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; public class FileClassLoader extends URLClassLoader { private final Map> classes = new ConcurrentHashMap<>(); private JarFile jar; private final Manifest manifest; private final URL url; @Nullable private final ClassProcessor classProcessor; public FileClassLoader(File file, ClassLoader pluginClassLoader, @Nullable ClassProcessor classProcessor) throws IOException { super(new URL[]{file.toURI().toURL()}, pluginClassLoader); this.jar = new JarFile(file); this.manifest = jar.getManifest(); this.url = file.toURI().toURL(); this.classProcessor = classProcessor; } @Nullable @Override public URL getResource(String name) { URL url = findResource(name); return url == null ? super.getResource(name) : url; } @Override public void close() throws IOException { this.classes.clear(); jar.close(); this.jar = null; super.close(); } @Override protected Class findClass(String name) throws ClassNotFoundException { Class result = classes.get(name); if (result == null) { String path = name.replace('.', '/').concat(".class"); JarEntry entry = jar.getJarEntry(path); if (entry != null) { byte[] classBytes; try (InputStream is = jar.getInputStream(entry)) { //noinspection UnstableApiUsage classBytes = ByteStreams.toByteArray(is); } catch (IOException ex) { throw new ClassNotFoundException(name, ex); } if (classProcessor != null) classBytes = classProcessor.processClass(classBytes, path); int dot = name.lastIndexOf('.'); if (dot != -1) { String pkgName = name.substring(0, dot); if (getPackage(pkgName) == null) { try { if (manifest != null) { definePackage(pkgName, manifest, url); } else { definePackage(pkgName, null, null, null, null, null, null, null); } } catch (IllegalArgumentException ex) { if (getPackage(pkgName) == null) { throw new IllegalStateException("Cannot find package " + pkgName); } } } } CodeSigner[] signers = entry.getCodeSigners(); CodeSource source = new CodeSource(url, signers); result = defineClass(name, classBytes, 0, classBytes.length, source); } if (result == null) { result = super.findClass(name); } classes.put(name, result); } return result; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/Files.java ================================================ package com.bgsoftware.superiorskyblock.core.io; import com.bgsoftware.superiorskyblock.core.logging.Log; import javax.annotation.Nullable; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.function.Predicate; public class Files { private static final Set BLACKLISTED_FILE_NAMES = initializeBlacklistedFileNames(); private static final Object mutex = new Object(); private Files() { } public static void deleteDirectory(File directory) { if (directory.isDirectory()) { File[] childFiles = directory.listFiles(); if (childFiles != null) { for (File file : childFiles) deleteDirectory(file); } } //noinspection ResultOfMethodCallIgnored directory.delete(); } public static void replaceString(File file, String str, String replace) { synchronized (mutex) { StringBuilder stringBuilder = new StringBuilder(); try { try (BufferedReader reader = new BufferedReader(new FileReader(file))) { String line; while ((line = reader.readLine()) != null) stringBuilder.append("\n").append(line); } if (stringBuilder.length() > 0) { try (FileWriter writer = new FileWriter(file)) { writer.write(stringBuilder.substring(1).replace(str, replace)); } } } catch (Exception error) { Log.entering("ENTER", file.getName(), str, replace); Log.error(error, "An unexpected error occurred while replacing strings in file:"); } } } public static List listFolderFiles(File folder, boolean recursive) { return listFolderFiles(folder, recursive, null); } public static List listFolderFiles(File folder, boolean recursive, @Nullable Predicate predicate) { if (!folder.isDirectory()) return Collections.emptyList(); List folderFiles = new LinkedList<>(); File[] folderFilesArr = folder.listFiles(); if (folderFilesArr != null && folderFilesArr.length > 0) { for (File file : folderFilesArr) { if (file.isDirectory()) { if (recursive) folderFiles.addAll(listFolderFiles(folder, true, predicate)); } else if (!BLACKLISTED_FILE_NAMES.contains(file.getName().toLowerCase(Locale.ENGLISH)) && (predicate == null || predicate.test(file))) { folderFiles.add(file); } } } return folderFiles.isEmpty() ? Collections.emptyList() : folderFiles; } public static String getFileName(File file) { String[] fileNameSections = file.getName().split("\\."); return fileNameSections.length == 1 ? fileNameSections[0] : file.getName().replace("." + fileNameSections[fileNameSections.length - 1], ""); } private static Set initializeBlacklistedFileNames() { return Collections.singleton(".ds_store"); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/IOUtils.java ================================================ package com.bgsoftware.superiorskyblock.core.io; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class IOUtils { private static final int EOF = -1; private IOUtils() { } public static byte[] toByteArray(InputStream inputStream) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); copy(inputStream, outputStream); return outputStream.toByteArray(); } public static int copy(InputStream inputStream, OutputStream outputStream) throws IOException { long bytesCopied = copyLarge(inputStream, outputStream); return bytesCopied > 0x7FFFFFFFL ? -1 : (int) bytesCopied; } public static long copyLarge(InputStream inputStream, OutputStream outputStream) throws IOException { return copyLarge(inputStream, outputStream, new byte[4096]); } public static long copyLarge(InputStream inputStream, OutputStream outputStream, byte[] buf) throws IOException { long totalBytesCopied = 0; int bytesCopied; while ((bytesCopied = inputStream.read(buf)) != EOF) { outputStream.write(buf, 0, bytesCopied); totalBytesCopied += bytesCopied; } return totalBytesCopied; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/JarFiles.java ================================================ package com.bgsoftware.superiorskyblock.core.io; import com.bgsoftware.superiorskyblock.core.Either; import java.net.URL; import java.net.URLClassLoader; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; public class JarFiles { private JarFiles() { } public static Either, Throwable> getClass(URL jar, Class clazz, ClassLoader classLoader) { try (URLClassLoader cl = new URLClassLoader(new URL[]{jar}, classLoader); JarInputStream jis = new JarInputStream(jar.openStream())) { JarEntry jarEntry; while ((jarEntry = jis.getNextJarEntry()) != null) { String name = jarEntry.getName(); if (!name.endsWith(".class")) { continue; } name = name.replace("/", "."); String clazzName = name.substring(0, name.lastIndexOf(".class")); try { Class c = cl.loadClass(clazzName); if (clazz.isAssignableFrom(c)) { return Either.left(c); } } catch (NoClassDefFoundError ignored) { // If we can't find the class, can just be ignored. } } } catch (Throwable error) { return Either.right(error); } return Either.right(null); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.io; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.parser.MenuParseException; import com.bgsoftware.superiorskyblock.api.menu.parser.MenuParser; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.itemstack.MinecraftNamesMapper; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BackButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton; import com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.banner.PatternType; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.ItemFlag; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.function.Function; public class MenuParserImpl implements MenuParser { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final MenuParserImpl INSTANCE = new MenuParserImpl(); private static final LazyReference NAMES_MAPPER = new LazyReference() { @Override protected MinecraftNamesMapper create() { return new MinecraftNamesMapper(); } }; public static MenuParserImpl getInstance() { return INSTANCE; } private MenuParserImpl() { } @Override public > MenuParseResult parseMenu(String callerName, YamlConfiguration cfg) throws MenuParseException { RegularMenuLayoutImpl.Builder menuLayoutBuilder = new RegularMenuLayoutImpl.Builder<>(); menuLayoutBuilder.setTitle(Formatters.COLOR_FORMATTER.format(cfg.getString("title", ""))); menuLayoutBuilder.setInventoryType(getMinecraftEnum(InventoryType.class, cfg.getString("type", "CHEST"))); MenuPatternSlots menuPatternSlots = new MenuPatternSlots(); List pattern = cfg.getStringList("pattern"); menuLayoutBuilder.setRowsCount(pattern.size()); for (int row = 0; row < pattern.size() && row < 6; row++) { String patternLine = pattern.get(row).replace(" ", ""); for (int i = 0; i < patternLine.length() && i < 9; i++) { int slot = row * 9 + i; char ch = patternLine.charAt(i); AbstractMenuTemplateButton.AbstractBuilder buttonBuilder = new DummyButton.Builder<>(); buttonBuilder.setButtonItem(getItemStack(callerName, cfg.getConfigurationSection("items." + ch))); buttonBuilder.setClickCommands(cfg.getStringList("commands." + ch)); buttonBuilder.setClickSound(getSound(cfg.getConfigurationSection("sounds." + ch))); buttonBuilder.setRequiredPermission(cfg.getString("permissions." + ch + ".permission")); buttonBuilder.setLackPermissionsSound(getSound(cfg.getConfigurationSection("permissions." + ch + ".no-access-sound"))); menuLayoutBuilder.setButton(slot, buttonBuilder.build()); menuPatternSlots.addSlot(ch, slot); } } boolean previousMoveAllowed = cfg.getBoolean("previous-menu", true); boolean skipOneItem = cfg.getBoolean("skip-one-item", false); GameSound openingSound = getSound(cfg.getConfigurationSection("open-sound")); return new MenuParseResult<>(menuLayoutBuilder, openingSound, previousMoveAllowed, skipOneItem, menuPatternSlots, cfg); } @Override public , E> MenuParseResult parseMenu( String callerName, YamlConfiguration cfg, PagedMenuTemplateButton.Builder pagedButtonBuilder) throws MenuParseException { PagedMenuLayoutImpl.Builder menuLayoutBuilder = new PagedMenuLayoutImpl.Builder<>(); menuLayoutBuilder.setTitle(Formatters.COLOR_FORMATTER.format(cfg.getString("title", ""))); menuLayoutBuilder.setInventoryType(getMinecraftEnum(InventoryType.class, cfg.getString("type", "CHEST"))); MenuPatternSlots menuPatternSlots = new MenuPatternSlots(); List pattern = cfg.getStringList("pattern"); menuLayoutBuilder.setRowsCount(pattern.size()); String backButton = cfg.getString("back", ""); boolean backButtonFound = false; for (int row = 0; row < pattern.size() && row < 6; row++) { String patternLine = pattern.get(row).replace(" ", ""); for (int i = 0; i < patternLine.length() && i < 9; i++) { int slot = row * 9 + i; char ch = patternLine.charAt(i); boolean isBackButton = backButton.contains(ch + ""); if (isBackButton) { backButtonFound = true; } AbstractMenuTemplateButton.AbstractBuilder buttonBuilder = isBackButton ? new BackButton.Builder<>() : new DummyButton.Builder<>(); buttonBuilder.setButtonItem(getItemStackUnsafe(callerName, cfg.getConfigurationSection("items." + ch))); buttonBuilder.setClickCommands(cfg.getStringList("commands." + ch)); buttonBuilder.setClickSound(getSound(cfg.getConfigurationSection("sounds." + ch))); buttonBuilder.setRequiredPermission(cfg.getString("permissions." + ch + ".permission")); buttonBuilder.setLackPermissionsSound(getSound(cfg.getConfigurationSection("permissions." + ch + ".no-access-sound"))); menuLayoutBuilder.setButton(slot, buttonBuilder.build()); menuPatternSlots.addSlot(ch, slot); } } if (plugin.getSettings().isOnlyBackButton() && !backButtonFound) { throw new MenuParseException("Menu doesn't have a back button, it's impossible to close it."); } menuLayoutBuilder.setPreviousPageSlots(parseButtonSlots(cfg, "previous-page", menuPatternSlots)); menuLayoutBuilder.setCurrentPageSlots(parseButtonSlots(cfg, "current-page", menuPatternSlots)); menuLayoutBuilder.setNextPageSlots(parseButtonSlots(cfg, "next-page", menuPatternSlots)); menuLayoutBuilder.setPagedObjectSlots(parseButtonSlots(cfg, "slots", menuPatternSlots), pagedButtonBuilder); if (cfg.isList("custom-order")) menuLayoutBuilder.setCustomLayoutOrder(cfg.getIntegerList("custom-order")); boolean previousMoveAllowed = cfg.getBoolean("previous-menu", true); boolean skipOneItem = cfg.getBoolean("skip-one-item", false); GameSound openingSound = getSound(cfg.getConfigurationSection("open-sound")); return new MenuParseResult<>(menuLayoutBuilder, openingSound, previousMoveAllowed, skipOneItem, menuPatternSlots, cfg); } @Nullable public > MenuParseResult loadCustomMenu(String fileName, @Nullable IMenuConverter converter) { return loadMenuInternal(fileName, true, converter); } @Nullable public > MenuParseResult loadMenu(String fileName, @Nullable IMenuConverter converter) { return loadMenuInternal(fileName, false, converter); } @Nullable public , E> MenuParseResult loadMenu(String fileName, @Nullable IMenuConverter converter, PagedMenuTemplateButton.Builder pagedButtonItemBuilder) { File file = new File(plugin.getDataFolder(), "menus/" + fileName); CommentedConfiguration cfg = loadMenuFile(file, fileName, false, converter); if (cfg != null) { try { return parseMenu(fileName, cfg, pagedButtonItemBuilder); } catch (MenuParseException error) { Log.errorFromFile(fileName, error.getMessage()); } } return null; } @Nullable public TemplateItem getItemStack(String fileName, ConfigurationSection section) { try { return getItemStackUnsafe(fileName, section); } catch (MenuParseException error) { Log.errorFromFile(fileName, error.getMessage()); return null; } } @Nullable public GameSound getSound(ConfigurationSection section) { if (section == null) return null; String soundType = section.getString("type"); if (soundType == null) return null; Sound sound; try { sound = getMinecraftEnum(Sound.class, soundType); } catch (Exception ignored) { return null; } return new GameSoundImpl(sound, (float) section.getDouble("volume", 1), (float) section.getDouble("pitch", 1)); } @Nullable private > MenuParseResult loadMenuInternal(String fileName, boolean customMenu, @Nullable IMenuConverter converter) { String menuPath = customMenu ? "custom/" : ""; File file = new File(plugin.getDataFolder(), "menus/" + menuPath + fileName); CommentedConfiguration cfg = loadMenuFile(file, fileName, customMenu, converter); if (cfg != null) { try { return parseMenu(fileName, cfg); } catch (MenuParseException error) { Log.errorFromFile(fileName, error.getMessage()); } } return null; } @Nullable private static CommentedConfiguration loadMenuFile(File file, String fileName, boolean customMenu, @Nullable IMenuConverter converter) { if (!file.exists() && !customMenu) Resources.saveResource("menus/" + fileName); CommentedConfiguration cfg = new CommentedConfiguration(); try { cfg.load(file); } catch (InvalidConfigurationException error) { Log.errorFromFile(error, fileName, "There is an issue with the format of the file:"); return null; } catch (IOException error) { Log.errorFromFile(error, fileName, "An unexpected error occurred while parsing file:"); return null; } if (converter != null && converter.convert(plugin, cfg)) { try { cfg.save(file); } catch (Exception error) { Log.errorFromFile(error, fileName, "An unexpected error occurred while saving file:"); } } return cfg; } private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSection section) throws MenuParseException { if (section == null) return null; TemplateItem templateItem; String sourceItem = section.getString("source"); if (sourceItem != null) { templateItem = getItemStackUnsafe(fileName, section.getRoot().getConfigurationSection(sourceItem)); } else { if (!section.isString("type")) return null; Material type; short data; try { String materialType = section.getString("type"); materialType = MinecraftNamesMapper.getMinecraftName(materialType) .map(minecraftKey -> NAMES_MAPPER.get().getMappedName(Material.class, minecraftKey).orElse(minecraftKey)) .orElse(materialType); if (materialType.contains(":")) { String[] materialSections = materialType.toUpperCase(Locale.ENGLISH).split(":"); if (materialSections.length < 2) throw new IllegalArgumentException(); type = Material.valueOf(materialSections[0]); data = Short.parseShort(materialSections[1]); } else { type = Material.valueOf(materialType.toUpperCase(Locale.ENGLISH)); data = (short) section.getInt("data"); } } catch (IllegalArgumentException error) { throw new MenuParseException("Couldn't convert " + section.getCurrentPath() + " into an item stack. Check type & data sections!"); } templateItem = new TemplateItem(new ItemBuilder(type, data)); } ItemBuilder itemBuilder = templateItem.getEditableBuilder(); if (section.isString("name")) itemBuilder.withName(Formatters.COLOR_FORMATTER.format(section.getString("name"))); if (section.isList("lore")) itemBuilder.withLore(section.getStringList("lore")); if (section.isInt("amount")) itemBuilder.withAmount(section.getInt("amount")); if (section.isConfigurationSection("enchants")) { for (String enchantmentName : section.getConfigurationSection("enchants").getKeys(false)) { Enchantment enchantment; try { enchantment = getMinecraftEnum(Enchantment.class, enchantmentName, Enchantment::getByName); } catch (IllegalArgumentException ex) { Log.warnFromFile(fileName, "Couldn't convert ", section.getCurrentPath(), ".enchants.", enchantmentName.toUpperCase(Locale.ENGLISH), " into an enchantment, skipping..."); continue; } itemBuilder.withEnchant(enchantment, section.getInt("enchants." + enchantmentName)); } } if (section.getBoolean("glow", false)) { itemBuilder.makeItemGlow(); } if (section.isList("flags")) { for (String flag : section.getStringList("flags")) { String flagName = flag.toUpperCase(Locale.ENGLISH); try { itemBuilder.withFlags(ItemFlag.valueOf(flagName)); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", section.getCurrentPath(), " (", flagName, ") into an item flag, skipping..."); } } } if (section.isString("skull")) { itemBuilder.asSkullOf(section.getString("skull")); } if (section.getBoolean("unbreakable", false)) { itemBuilder.setUnbreakable(); } if (section.getBoolean("hideTooltip", false)) { itemBuilder.setHideTooltip(); } if (section.isConfigurationSection("effects")) { ConfigurationSection effectsSection = section.getConfigurationSection("effects"); for (String effectName : effectsSection.getKeys(false)) { PotionEffectType potionEffectType; try { potionEffectType = getMinecraftEnum(PotionEffectType.class, effectName, PotionEffectType::getByName); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", effectsSection.getCurrentPath(), ".", effectName.toUpperCase(Locale.ENGLISH), " into a potion effect, skipping..."); continue; } int duration = effectsSection.getInt(effectName + ".duration", -1); int amplifier = effectsSection.getInt(effectName + ".amplifier", 0); if (duration == -1) { Log.warnFromFile(fileName, "Potion effect ", effectsSection.getCurrentPath(), ".", effectName, " is missing duration, skipping..."); continue; } itemBuilder.withPotionEffect(new PotionEffect(potionEffectType, duration, amplifier)); } } if (section.isString("entity")) { String entity = section.getString("entity"); try { itemBuilder.withEntityType(getMinecraftEnum(EntityType.class, entity)); } catch (IllegalArgumentException ex) { Log.warnFromFile(fileName, "Couldn't convert ", entity, " into an entity type, skipping..."); } } if (section.isConfigurationSection("bannerMeta")) { for (String dyeColorName : section.getConfigurationSection("bannerMeta").getKeys(false)) { DyeColor dyeColor; PatternType patternType; try { dyeColor = DyeColor.valueOf(dyeColorName.toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", section.getCurrentPath(), ".bannerMeta.", dyeColorName.toUpperCase(Locale.ENGLISH), " into an dye color, skipping..."); continue; } try { patternType = PatternType.valueOf(section.getString("bannerMeta." + dyeColorName)); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", section.getCurrentPath(), ".bannerMeta.", dyeColorName.toUpperCase(Locale.ENGLISH), ".", section.getString("bannerMeta." + dyeColorName), " into an pattern type, skipping..."); continue; } itemBuilder.withBannerMeta(dyeColor, patternType); } } if (section.isInt("customModel")) { itemBuilder.withCustomModel(section.getInt("customModel")); } if (section.isString("itemModel")) { itemBuilder.withItemModel(section.getString("itemModel")); } if (section.isString("rarity")) { String rarity = section.getString("rarity"); try { itemBuilder.withRarity(rarity); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", rarity, " into a rarity, skipping..."); } } if (section.isConfigurationSection("trim")) { String trimMaterial = section.getString("trim.material"); String trimPattern = section.getString("trim.pattern"); if (trimMaterial == null) { Log.warnFromFile(fileName, "Couldn't find trim material for item with trim pattern, skipping..."); } else if (trimPattern == null) { Log.warnFromFile(fileName, "Couldn't find trim pattern for item with trim material, skipping..."); } else { try { itemBuilder.withTrim(trimMaterial, trimPattern); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, error.getMessage()); } } } if (section.isString("leatherColor")) { String leatherColor = section.getString("leatherColor"); if (leatherColor.startsWith("#")) leatherColor = leatherColor.substring(1); try { itemBuilder.withLeatherColor(Integer.parseInt(leatherColor, 16)); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", leatherColor, " into a color, skipping..."); } } return templateItem; } public List parseButtonSlots(ConfigurationSection section, String key, MenuPatternSlots menuPatternSlots) { return !section.isString(key) ? Collections.emptyList() : menuPatternSlots.getSlots(section.getString(key)); } private static T getMinecraftEnum(Class type, String name) throws IllegalArgumentException { return getMinecraftEnum(type, name, mappedName -> EnumHelper.getEnum(type, mappedName)); } private static T getMinecraftEnum(Class type, String name, Function enumCreator) throws IllegalArgumentException { String mappedName = MinecraftNamesMapper.getMinecraftName(name) .map(minecraftKey -> NAMES_MAPPER.get().getMappedName(type, minecraftKey).orElse(minecraftKey)) .orElse(name); return Optional.ofNullable(enumCreator.apply(mappedName.toUpperCase(Locale.ENGLISH))) .orElseThrow(() -> new IllegalArgumentException("No enum constant " + type.getCanonicalName() + "." + name)); } public interface IMenuConverter { boolean convert(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/Resources.java ================================================ package com.bgsoftware.superiorskyblock.core.io; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.logging.Log; import java.io.File; import java.io.InputStream; public class Resources { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private Resources() { } public static void copyResource(String resourcePath) { String fixedPath = resourcePath + ".jar"; File dstFile = new File(plugin.getDataFolder(), fixedPath); if (dstFile.exists()) //noinspection ResultOfMethodCallIgnored dstFile.delete(); plugin.saveResource(resourcePath, true); File file = new File(plugin.getDataFolder(), resourcePath); //noinspection ResultOfMethodCallIgnored file.renameTo(dstFile); } public static void saveResource(String resourcePath) { saveResource(resourcePath, resourcePath); } public static void saveResource(String destination, String resourcePath) { try { for (ServerVersion serverVersion : ServerVersion.getByOrder()) { String version = serverVersion.name().substring(1); if (resourcePath.endsWith(".yml") && plugin.getResource(resourcePath.replace(".yml", version + ".yml")) != null) { resourcePath = resourcePath.replace(".yml", version + ".yml"); break; } else if (resourcePath.endsWith(".schematic") && plugin.getResource(resourcePath.replace(".schematic", version + ".schematic")) != null) { resourcePath = resourcePath.replace(".schematic", version + ".schematic"); break; } } File file = new File(plugin.getDataFolder(), resourcePath); plugin.saveResource(resourcePath, true); if (!destination.equals(resourcePath)) { File dest = new File(plugin.getDataFolder(), destination); //noinspection ResultOfMethodCallIgnored file.renameTo(dest); } } catch (Exception error) { Log.entering("ENTER", destination, resourcePath); Log.error(error, "An unexpected error occurred while saving resource:"); } } public static InputStream getResource(String resourcePath) { String[] suffixAndPath = getPathAndSuffix(resourcePath); String resourcePathNoSuffix = suffixAndPath[0]; String suffix = suffixAndPath[1]; try { for (ServerVersion serverVersion : ServerVersion.getByOrder()) { String version = serverVersion.name().substring(1); String realPath = resourcePathNoSuffix + version + suffix; try (InputStream resource = plugin.getResource(realPath)) { if (resource != null) { resourcePath = realPath; break; } } } return plugin.getResource(resourcePath); } catch (Exception error) { Log.entering("ENTER", resourcePath); Log.error(error, "An unexpected error occurred while retrieving resource:"); return null; } } private static String[] getPathAndSuffix(String name) { int lastIndex = name.lastIndexOf('.'); String suffix = lastIndex == -1 || lastIndex + 1 >= name.length() ? "" : name.substring(lastIndex + 1); return suffix.isEmpty() ? new String[]{name, ""} : new String[]{name.substring(0, name.length() - suffix.length()), suffix}; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/ZipFiles.java ================================================ package com.bgsoftware.superiorskyblock.core.io; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class ZipFiles { private ZipFiles() { } public static void zipFolder(File input, File output) throws IOException { if (!input.isDirectory()) throw new IOException("Input file must be a directory."); try (ZipOutputStream outputStream = new ZipOutputStream(Files.newOutputStream(output.toPath()))) { zipFolderInternal(input, "", outputStream); } } public static void zipFile(File input, File output) throws IOException { if (input.isDirectory()) throw new IOException("Input file must be a file."); try (ZipOutputStream outputStream = new ZipOutputStream(Files.newOutputStream(output.toPath()))) { zipFileInternal(input, input.getName(), outputStream); } } private static void zipFolderInternal(File input, String parent, ZipOutputStream outputStream) throws IOException { // Add the folder as an entry String folderPath = parent + input.getName() + File.separator; ZipEntry zipEntry = new ZipEntry(folderPath); outputStream.putNextEntry(zipEntry); outputStream.closeEntry(); for (File innerFile : input.listFiles()) { if (innerFile.isDirectory()) { zipFolderInternal(innerFile, folderPath, outputStream); } else { zipFileInternal(innerFile, folderPath + innerFile.getName(), outputStream); } } } private static void zipFileInternal(File input, String zipEntryName, ZipOutputStream outputStream) throws IOException { ZipEntry zipEntry = new ZipEntry(zipEntryName); try { outputStream.putNextEntry(zipEntry); Files.copy(input.toPath(), outputStream); } finally { outputStream.closeEntry(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/loader/DefaultFilesLookupProvider.java ================================================ package com.bgsoftware.superiorskyblock.core.io.loader; import java.io.File; public class DefaultFilesLookupProvider implements FilesLookupProvider { private static final DefaultFilesLookupProvider INSTANCE = new DefaultFilesLookupProvider(); public static DefaultFilesLookupProvider getInstance() { return INSTANCE; } private DefaultFilesLookupProvider() { } @Override public FilesLookup createFilesLookup(File folder) { return new DefaultFilesLookup(folder); } private static class DefaultFilesLookup implements FilesLookup { private final File folder; DefaultFilesLookup(File folder) { this.folder = folder; } @Override public File getFile(String name) { return new File(this.folder, name); } @Override public void close() { // Do nothing } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/loader/FilesLookup.java ================================================ package com.bgsoftware.superiorskyblock.core.io.loader; import java.io.File; public interface FilesLookup extends AutoCloseable { File getFile(String name); @Override void close(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/loader/FilesLookupFactory.java ================================================ package com.bgsoftware.superiorskyblock.core.io.loader; import java.io.File; public class FilesLookupFactory { private static final FilesLookupFactory INSTANCE = new FilesLookupFactory(); public static FilesLookupFactory getInstance() { return INSTANCE; } private FilesLookupProvider filesLookupProvider = findSuitableFilesLookupProvider(); private FilesLookupFactory() { } public void setProvider(FilesLookupProvider filesLookupProvider) { this.filesLookupProvider = filesLookupProvider; } public FilesLookup lookupFolder(File folder) { try { return this.filesLookupProvider.createFilesLookup(folder); } catch (IllegalStateException error) { if (this.filesLookupProvider == DefaultFilesLookupProvider.getInstance()) throw error; this.filesLookupProvider = DefaultFilesLookupProvider.getInstance(); return lookupFolder(folder); } } private static FilesLookupProvider findSuitableFilesLookupProvider() { try { Class.forName("io.papermc.paper.pluginremap.PluginRemapper"); return (FilesLookupProvider) Class.forName( "com.bgsoftware.superiorskyblock.external.remapper.PluginRemapperFilesLookupProvider") .newInstance(); } catch (Throwable ignored) { } return DefaultFilesLookupProvider.getInstance(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/io/loader/FilesLookupProvider.java ================================================ package com.bgsoftware.superiorskyblock.core.io.loader; import java.io.File; public interface FilesLookupProvider { FilesLookup createFilesLookup(File folder) throws IllegalStateException; } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java ================================================ package com.bgsoftware.superiorskyblock.core.itemstack; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.ChatColor; import org.bukkit.Color; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.block.banner.Pattern; import org.bukkit.block.banner.PatternType; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BannerMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.SpawnEggMeta; import org.bukkit.potion.PotionEffect; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Locale; public class ItemBuilder { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; private ItemStack itemStack; @Nullable private ItemMeta itemMeta; private String textureValue = ""; public ItemBuilder(ItemStack itemStack) { this(itemStack.getType(), itemStack.getDurability()); this.itemMeta = itemStack.getItemMeta().clone(); } public ItemBuilder(Material type) { this(type, 0); } public ItemBuilder(Material type, int damage) { itemStack = new ItemStack(type, 1, (short) damage); itemMeta = itemStack.getItemMeta(); } public ItemBuilder withType(Material type) { this.itemStack.setType(type); return this; } public ItemBuilder withDurablity(short durability) { if (durability >= 0) this.itemStack.setDurability(durability); return this; } public ItemBuilder withAmount(int amount) { if (amount >= 1 && amount <= itemStack.getMaxStackSize()) itemStack.setAmount(amount); return this; } public ItemBuilder asSkullOf(SuperiorPlayer superiorPlayer) { if (itemStack.getType() == Materials.PLAYER_HEAD.toBukkitType()) textureValue = superiorPlayer == null ? ItemSkulls.getNullPlayerTexture() : superiorPlayer.getTextureValue(); return this; } public ItemBuilder asSkullOf(String textureValue) { if (itemStack.getType() == Materials.PLAYER_HEAD.toBukkitType()) this.textureValue = ItemSkulls.parseTexture(textureValue); return this; } public ItemBuilder withName(String name) { if (itemMeta != null && name != null) itemMeta.setDisplayName(Formatters.COLOR_FORMATTER.format(name)); return this; } public ItemBuilder replaceName(String regex, String replace) { if (itemMeta != null && itemMeta.hasDisplayName()) withName(itemMeta.getDisplayName().replace(regex, replace)); return this; } public ItemBuilder withLore(List lore) { if (itemMeta != null && lore != null) itemMeta.setLore(new SequentialListBuilder() .build(lore, Formatters.COLOR_FORMATTER::format)); return this; } public ItemBuilder appendLore(List lore) { if (itemMeta == null || itemMeta.getLore() == null) { return withLore(lore); } else { List currentLore = itemMeta.getLore(); currentLore.addAll(lore); return withLore(currentLore); } } public ItemBuilder withLore(String... lore) { return withLore(Arrays.asList(lore)); } public ItemBuilder withLore(String firstLine, List listLine) { if (itemMeta == null) return this; List loreList = new LinkedList<>(); firstLine = Formatters.COLOR_FORMATTER.format(firstLine); loreList.add(firstLine); for (String line : listLine) loreList.add(ChatColor.getLastColors(firstLine) + Formatters.COLOR_FORMATTER.format(line)); if (loreList.size() > 10) { for (int i = 10; i < loreList.size(); i++) { loreList.remove(loreList.get(i)); } loreList.add(ChatColor.getLastColors(firstLine) + "..."); } itemMeta.setLore(loreList); return this; } public ItemBuilder replaceLore(String regex, String replace) { if (itemMeta == null || !itemMeta.hasLore()) return this; List loreList = new ArrayList<>(itemMeta.getLore().size()); for (String line : itemMeta.getLore()) { loreList.add(line.replace(regex, replace)); } withLore(loreList); return this; } public ItemBuilder replaceLoreWithLines(String regex, String... lines) { if (itemMeta == null || !itemMeta.hasLore()) return this; List currentLore = itemMeta.getLore(); List loreList = new ArrayList<>(currentLore.size()); List linesToAdd = Arrays.asList(lines); boolean isEmpty = linesToAdd.isEmpty() || linesToAdd.stream().allMatch(String::isEmpty); for (String line : currentLore) { if (line.contains(regex)) { if (!isEmpty) loreList.addAll(linesToAdd); } else { loreList.add(line); } } withLore(loreList); return this; } public ItemBuilder replaceAll(String regex, String replace) { replaceName(regex, replace); replaceLore(regex, replace); return this; } public ItemBuilder withEnchant(Enchantment enchant, int level) { if (itemMeta != null) itemMeta.addEnchant(enchant, level, true); return this; } public ItemBuilder makeItemGlow() { plugin.getNMSAlgorithms().makeItemGlow(itemMeta); return this; } public ItemBuilder withFlags(ItemFlag... itemFlags) { if (itemMeta != null) { itemMeta.addItemFlags(itemFlags); for (ItemFlag itemFlag : itemFlags) { if (itemFlag == ItemFlag.HIDE_ATTRIBUTES) { plugin.getNMSAlgorithms().hideAttributes(itemMeta); break; } } } return this; } public ItemBuilder setUnbreakable() { if (itemMeta != null) itemMeta.spigot().setUnbreakable(true); return this; } public ItemBuilder setHideTooltip() { if (itemMeta != null) plugin.getNMSAlgorithms().setHideTooltip(itemMeta); return this; } public ItemBuilder withPotionEffect(PotionEffect potionEffect) { if (itemMeta instanceof PotionMeta) plugin.getNMSAlgorithms().addPotion((PotionMeta) itemMeta, potionEffect); return this; } @SuppressWarnings("deprecation") public ItemBuilder withEntityType(EntityType entityType) { if (itemMeta == null) return this; if (BukkitItems.isValidAndSpawnEgg(itemStack)) { if (ServerVersion.isLegacy()) { try { ((SpawnEggMeta) itemMeta).setSpawnedType(entityType); } catch (NoClassDefFoundError error) { itemStack.setDurability(entityType.getTypeId()); } } else { itemStack.setType(Material.valueOf(entityType.name() + "_SPAWN_EGG")); } } return this; } public ItemBuilder withBannerMeta(DyeColor dyeColor, PatternType patternType) { if (itemMeta instanceof BannerMeta) { BannerMeta bannerMeta = (BannerMeta) itemMeta; bannerMeta.addPattern(new Pattern(dyeColor, patternType)); } return this; } public ItemBuilder withCustomModel(int customModel) { plugin.getNMSAlgorithms().setCustomModel(itemMeta, customModel); return this; } public ItemBuilder withItemModel(String itemModel) { plugin.getNMSAlgorithms().setItemModel(itemMeta, itemModel); return this; } public ItemBuilder withRarity(String rarity) { plugin.getNMSAlgorithms().setRarity(itemMeta, rarity.toUpperCase(Locale.ENGLISH)); return this; } public ItemBuilder withTrim(String trimMaterial, String trimPattern) { plugin.getNMSAlgorithms().setTrim(itemMeta, trimMaterial.toLowerCase(Locale.ENGLISH), trimPattern.toLowerCase(Locale.ENGLISH)); return this; } public ItemBuilder withLeatherColor(int leatherColor) { if (itemMeta instanceof LeatherArmorMeta) { LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) itemMeta; leatherArmorMeta.setColor(Color.fromRGB(leatherColor)); } return this; } @Nullable public ItemMeta getItemMeta() { return itemMeta; } public ItemStack build(SuperiorPlayer superiorPlayer) { OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer(); if (itemMeta != null) { if (itemMeta.hasDisplayName()) { withName(placeholdersService.get().parsePlaceholders(offlinePlayer, itemMeta.getDisplayName())); } if (itemMeta.hasLore()) { withLore(new SequentialListBuilder() .build(itemMeta.getLore(), line -> placeholdersService.get().parsePlaceholders(offlinePlayer, line))); } } if (textureValue.equals("%superior_player_texture%")) textureValue = superiorPlayer.getTextureValue(); return build(); } public ItemStack build() { itemStack.setItemMeta(itemMeta); return textureValue.isEmpty() ? itemStack : ItemSkulls.getPlayerHead(itemStack, textureValue); } public ItemBuilder copy() { ItemBuilder itemBuilder = new ItemBuilder(Material.AIR); itemBuilder.itemStack = itemStack.clone(); if (itemMeta != null) itemBuilder.itemMeta = itemMeta.clone(); itemBuilder.textureValue = textureValue; return itemBuilder; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemSkulls.java ================================================ package com.bgsoftware.superiorskyblock.core.itemstack; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.io.Resources; import com.bgsoftware.superiorskyblock.core.itemstack.heads.MinecraftHeadsClient; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import org.bukkit.inventory.ItemStack; import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.UUID; @SuppressWarnings("WeakerAccess") public class ItemSkulls { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final String NULL_PLAYER_TEXTURE = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmFkYzA0OGE3Y2U3OGY3ZGFkNzJhMDdkYTI3ZDg1YzA5MTY4ODFlNTUyMmVlZWQxZTNkYWYyMTdhMzhjMWEifX19"; private static final Map entitySkullTextures = new HashMap<>(); private static final LazyReference minecraftHeadsClient = new LazyReference() { @Override protected MinecraftHeadsClient create() { return new MinecraftHeadsClient(); } }; private ItemSkulls() { } public static void readTextures(SuperiorSkyblockPlugin plugin) { entitySkullTextures.clear(); File file = new File(plugin.getDataFolder(), "heads.yml"); if (!file.exists()) Resources.saveResource("heads.yml"); CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file); try { cfg.syncWithConfig(file, Resources.getResource("heads.yml")); } catch (Exception error) { Log.entering("ENTER"); Log.error(error, "An unexpected error occurred while syncing heads file:"); } for (String entityType : cfg.getConfigurationSection("").getKeys(false)) entitySkullTextures.put(entityType, parseTexture(cfg.getString(entityType))); } public static ItemStack getPlayerHead(ItemStack itemStack, String texture) { return plugin.getNMSTags().getSkullWithTexture(itemStack, texture); } public static ItemStack getPlayerHeadNoNMS(ItemStack itemStack, String texture) { CompoundTag compoundTag = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack); CompoundTag tagCompound = compoundTag.getCompound("tag").orElseGet(CompoundTag::of); CompoundTag skullOwner = tagCompound.getCompound("SkullOwner").orElseGet(CompoundTag::of); UUID ownerUUID = new UUID(texture.hashCode(), texture.hashCode()); if (ServerVersion.isAtLeast(ServerVersion.v1_16)) { skullOwner.setTag("Id", IntArrayTag.fromUUID(ownerUUID)); } else { skullOwner.setString("Id", ownerUUID.toString()); } CompoundTag properties = CompoundTag.of(); ListTag textures = ListTag.of(CompoundTag.class); CompoundTag signature = CompoundTag.of(); signature.setString("Value", texture); textures.addTag(signature); properties.setTag("textures", textures); skullOwner.setTag("Properties", properties); tagCompound.setTag("SkullOwner", skullOwner); compoundTag.setTag("nbt", tagCompound); return Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(compoundTag); } public static String getNullPlayerTexture() { return NULL_PLAYER_TEXTURE; } public static String getTexture(String entityType) { return entitySkullTextures.getOrDefault(entityType, ""); } public static String parseTexture(String texture) { return MinecraftHeadsClient.getMinecraftHeadsTextureId(texture) .map(textureId -> minecraftHeadsClient.get().getTexture(textureId)) .orElse(texture); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/MinecraftNamesMapper.java ================================================ package com.bgsoftware.superiorskyblock.core.itemstack; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import javax.net.ssl.HttpsURLConnection; import java.io.InputStreamReader; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MinecraftNamesMapper { private static final Pattern MINECRAFT_KEY_PATTERN = Pattern.compile("minecraft:(.+)"); private static final String MINECRAFT_NAMES_MAPPING_URL = "https://bg-software.com/minecraft_mappings.json"; private static final String MINECRAFT_NAMES_MAPPING_LEGACY_URL = "https://bg-software.com/minecraft_mappings_legacy.json"; private static final Gson GSON = new Gson(); public static Optional getMinecraftName(String name) { Matcher matcher = MINECRAFT_KEY_PATTERN.matcher(name); return matcher.matches() ? Optional.of(matcher.group(1).toLowerCase(Locale.ENGLISH)) : Optional.empty(); } private final Map, Map> enumNamesMapping; public MinecraftNamesMapper() { this.enumNamesMapping = fetchEnumNamesMapping(); } public Optional getMappedName(Class expectedEnumClass, String name) { return Optional.ofNullable(enumNamesMapping.get(expectedEnumClass)) .map(mappings -> mappings.get(name)); } private static Map, Map> fetchEnumNamesMapping() { Map, Map> mappedNames = new ArrayMap<>(); try { HttpsURLConnection connection = (HttpsURLConnection) new URL(ServerVersion.isLegacy() ? MINECRAFT_NAMES_MAPPING_LEGACY_URL : MINECRAFT_NAMES_MAPPING_URL).openConnection(); connection.setRequestMethod("GET"); 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)"); connection.setDoInput(true); try (InputStreamReader reader = new InputStreamReader(connection.getInputStream())) { JsonElement mappingsElement = GSON.fromJson(reader, JsonElement.class); if (!mappingsElement.isJsonArray()) throw new MappingFormatException("Expected to receive json array, received " + mappingsElement.getClass()); JsonArray mappings = mappingsElement.getAsJsonArray(); for (JsonElement classMappingElement : mappings) { if (!classMappingElement.isJsonObject()) continue; JsonObject classMapping = classMappingElement.getAsJsonObject(); String className = ensureFieldExists(classMapping, "type").getAsString(); Class clazz; try { clazz = Class.forName(className); } catch (ClassNotFoundException error) { throw new MappingFormatException("Invalid class name: " + className); } Map classMappings = new HashMap<>(); JsonElement jsonMappingsElement = ensureFieldExists(classMapping, "mappings"); if (!jsonMappingsElement.isJsonObject()) throw new MappingFormatException("Mapping for class '" + className + "' is not an object"); JsonObject jsonMappings = jsonMappingsElement.getAsJsonObject(); jsonMappings.entrySet().forEach(entry -> { if (!entry.getValue().isJsonPrimitive()) { Log.warn("Mapping entry is not string: " + entry.getKey() + ", skipping..."); return; } classMappings.put(entry.getKey(), entry.getValue().getAsString()); }); if (!classMappings.isEmpty()) mappedNames.put(clazz, classMappings); } } } catch (Exception error) { Log.error(error, "Failed to fetch minecraft names mapper:"); } return mappedNames.isEmpty() ? Collections.emptyMap() : mappedNames; } private static JsonElement ensureFieldExists(JsonObject object, String fieldName) throws MappingFormatException { JsonElement value = object.get(fieldName); if (value != null) return value; throw new MappingFormatException("Missing field: " + fieldName); } private static class MappingFormatException extends IllegalArgumentException { MappingFormatException(String message) { super(message); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/heads/MinecraftHeadsClient.java ================================================ package com.bgsoftware.superiorskyblock.core.itemstack.heads; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.DynamicArray; import com.bgsoftware.superiorskyblock.core.logging.Log; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MinecraftHeadsClient { private static final Pattern MINECRAFT_HEADS_PATTERN = Pattern.compile("minecraft-heads:(\\d+)"); private static final int EXPECTED_HEADS_SIZE = 50_000; private static final String MINECRAFT_HEADS_DATABASE_URL = "https://minecraft-heads.com/csv/2020-01-31-IUgRbJoHRbVhjKnOlkmH/Custom-Head-DB.csv"; public static Optional getMinecraftHeadsTextureId(String texture) { Matcher matcher = MINECRAFT_HEADS_PATTERN.matcher(texture); return matcher.matches() ? Optional.of(Integer.parseInt(matcher.group(1))) : Optional.empty(); } private final List cachedHeads; public MinecraftHeadsClient() { this.cachedHeads = fetchHeadsDatabase(); } @Nullable public String getTexture(int id) { int index = id - 1; return index < cachedHeads.size() ? cachedHeads.get(index) : null; } private static List fetchHeadsDatabase() { DynamicArray heads = new DynamicArray<>(EXPECTED_HEADS_SIZE); boolean addedAnyHead = false; try { URLConnection connection = new URL(MINECRAFT_HEADS_DATABASE_URL).openConnection(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { String texture; while ((texture = reader.readLine()) != null) { String[] textureSegments = texture.split(";"); if (textureSegments.length >= 4) { int id; try { id = Integer.parseInt(textureSegments[1]); } catch (NumberFormatException ignored) { continue; } String textureValue = textureSegments[3]; String textureUrl = "{\"textures\":{\"SKIN\":{\"url\":\"http://textures.minecraft.net/texture/" + textureValue + "\"}}}"; heads.set(id - 1, Base64.getEncoder().encodeToString(textureUrl.getBytes(StandardCharsets.UTF_8))); addedAnyHead = true; } } } } catch (Exception error) { Log.error(error, "Failed to obtain heads from minecraft-heads:"); } return addedAnyHead ? heads.toList() : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/BaseKey.java ================================================ package com.bgsoftware.superiorskyblock.core.key; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; public abstract class BaseKey implements Key { protected final LazyReference toStringCache = new LazyReference() { @Override protected String create() { return toStringInternal(); } }; protected final LazyReference hashCodeCache = new LazyReference() { @Override protected Integer create() { return hashCodeInternal(); } }; private final Class baseKeyClass; private final boolean apiKey; protected BaseKey(Class baseKeyClass, boolean apiKey) { this.baseKeyClass = baseKeyClass; this.apiKey = apiKey; } @Override public abstract String getGlobalKey(); public abstract T toGlobalKey(); @Override public abstract String getSubKey(); protected abstract String toStringInternal(); protected abstract int hashCodeInternal(); protected abstract boolean equalsInternal(T other); protected abstract int compareToInternal(T other); public abstract T createAPIKeyInternal(); public final T markAPIKey() { if (this.apiKey) return (T) this; return createAPIKeyInternal(); } public boolean isAPIKey() { return this.apiKey; } @Override public final String toString() { return this.toStringCache.get(); } @Override public final int hashCode() { return this.hashCodeCache.get(); } @Override public final boolean equals(Object o) { if (this == o) return true; if (o == null) return false; if (getClass() != o.getClass()) { if (o instanceof LazyKey) { LazyKey lazyKey = (LazyKey) o; return this.equalsInternal(lazyKey.getBaseKey()); } if (!this.baseKeyClass.isAssignableFrom(o.getClass())) return false; } return this.equalsInternal((T) o); } @Override public final int compareTo(@NotNull Key o) { if (this == o) return 0; if (getClass() != o.getClass()) { if (o instanceof LazyKey) { LazyKey lazyKey = (LazyKey) o; return this.compareToInternal(lazyKey.getBaseKey()); } if (!this.baseKeyClass.isAssignableFrom(o.getClass())) return toString().compareTo(o.toString()); } return this.compareToInternal((T) o); } protected final void loadLazyCaches() { toStringCache.get(); hashCodeCache.get(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java ================================================ package com.bgsoftware.superiorskyblock.core.key; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import org.bukkit.Material; import org.bukkit.entity.EntityType; import java.util.Optional; public class ConstantKeys { public static final Key AIR = Keys.of(Material.AIR); @Nullable public static final Key BASALT = Optional.ofNullable(EnumHelper.getEnum(Material.class, "BASALT")) .map(Keys::of).orElse(null); public static final Key CARVED_PUMPKIN = Keys.of(EnumHelper.getEnum(Material.class, "CARVED_PUMPKIN", "PUMPKIN")); public static final Key CAULDRON = Keys.of(Material.CAULDRON); public static final Key CHEST = Keys.of(Material.CHEST); @Nullable public static final Key CHORUS_PLANT = Optional.ofNullable(EnumHelper.getEnum(Material.class, "CHORUS_PLANT")) .map(Keys::of).orElse(null); @Nullable public static final Key CLOSED_EYEBLOSSOM = Optional.ofNullable(EnumHelper.getEnum(Material.class, "CLOSED_EYEBLOSSOM")) .map(Keys::of).orElse(null); public static final Key COBBLESTONE = Keys.of(Material.COBBLESTONE); public static final Key COMMAND_BLOCK = Keys.of(EnumHelper.getEnum(Material.class, "COMMAND_BLOCK", "COMMAND")); public static final Key EGG_MOB_SPAWNER = Keys.ofSpawner("EGG"); public static final Key END_PORTAL_FRAME = Keys.of(Materials.END_PORTAL_FRAME.toBukkitType()); public static final Key END_PORTAL_FRAME_WITH_EYE = Keys.of(Materials.END_PORTAL_FRAME.toBukkitType(), (short) 7); public static final Key FURNACE = Keys.of(Material.FURNACE); public static final Key HOPPER = Keys.of(Material.HOPPER); @Nullable public static final Key IRON_BLOCK = Keys.of(Material.IRON_BLOCK); public static final Key LAVA = Keys.of(Material.LAVA); public static final Key MOB_SPAWNER = Keys.of(Materials.SPAWNER.toBukkitType()); public static final Key OBSIDIAN = Keys.of(Material.OBSIDIAN); @Nullable public static final Key OPEN_EYEBLOSSOM = Optional.ofNullable(EnumHelper.getEnum(Material.class, "OPEN_EYEBLOSSOM")) .map(Keys::of).orElse(null); public static final Key SNOW_BLOCK = Keys.of(Material.SNOW_BLOCK); public static final Key SOUL_SAND = Keys.of(Material.SOUL_SAND); @Nullable public static final Key TARGET = Optional.ofNullable(EnumHelper.getEnum(Material.class, "TARGET")) .map(Keys::of).orElse(null); public static final Key TNT = Keys.of(Material.TNT); public static final Key WATER = Keys.of(Material.WATER); public static final Key WET_SPONGE = Keys.of(EnumHelper.getEnum(Material.class, "WET_SPONGE", "SPONGE")); public static final Key WITHER_SKELETON_SKULL = initializeWitherSkeletonSkullKey(); public static final Key ENTITY_MINECART_COMMAND = Keys.of(EntityType.MINECART_COMMAND); public static final Key ENTITY_MINECART_CHEST = Keys.of(EntityType.MINECART_CHEST); public static final Key ENTITY_MINECART_FURNACE = Keys.of(EntityType.MINECART_FURNACE); public static final Key ENTITY_MINECART_TNT = Keys.of(EntityType.MINECART_TNT); public static final Key ENTITY_MINECART_HOPPER = Keys.of(EntityType.MINECART_HOPPER); public static final Key ENTITY_MINECART_MOB_SPAWNER = Keys.of(EntityType.MINECART_MOB_SPAWNER); private ConstantKeys() { } private static Key initializeWitherSkeletonSkullKey() { Material newSkullMaterial = EnumHelper.getEnum(Material.class, "WITHER_SKELETON_SKULL"); if (newSkullMaterial != null) return Keys.of(newSkullMaterial); return Keys.of(Material.SKULL_ITEM, (byte) 1); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/KeyIndicator.java ================================================ package com.bgsoftware.superiorskyblock.core.key; public enum KeyIndicator { MATERIAL, ENTITY_TYPE, CUSTOM } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java ================================================ package com.bgsoftware.superiorskyblock.core.key; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.key.types.CustomKey; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.CreatureSpawner; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.util.Locale; import java.util.Optional; import java.util.regex.Pattern; public class Keys { public static final Key EMPTY = CustomKey.of("", null, KeyIndicator.CUSTOM); private static final Pattern KEY_SPLITTER_PATTERN = Pattern.compile("[:;]"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private Keys() { } /* Entity keys */ public static Key of(EntityType entityType) { return EntityTypeKey.of(entityType); } public static Key ofEntityType(String customType) { try { return EntityTypeKey.of(EntityType.valueOf(customType.toUpperCase(Locale.ENGLISH))); } catch (IllegalArgumentException error) { return CustomKey.of(customType, null, KeyIndicator.ENTITY_TYPE); } } public static Key of(Entity entity) { Key baseKey = BukkitEntities.getLimitEntityType(entity); return plugin.getBlockValues().convertKey(baseKey, entity); } /* Block keys */ public static Key of(Block block) { Material blockType = block.getType(); Key baseKey; if (blockType == Materials.SPAWNER.toBukkitType()) { CreatureSpawner creatureSpawner = (CreatureSpawner) block.getState(); baseKey = getSpawnerKeyFromCreatureSpawner(creatureSpawner); } else { short data = plugin.getNMSAlgorithms().getBlockDataValue(block); baseKey = MaterialKey.of(blockType, data, MaterialKeySource.BLOCK); } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return plugin.getBlockValues().convertKey(baseKey, block.getLocation(wrapper.getHandle())); } } public static Key of(BlockState blockState) { Key baseKey; if (blockState instanceof CreatureSpawner) { baseKey = getSpawnerKeyFromCreatureSpawner((CreatureSpawner) blockState); } else { short data = plugin.getNMSAlgorithms().getBlockDataValue(blockState); baseKey = MaterialKey.of(blockState.getType(), data, MaterialKeySource.BLOCK); } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return plugin.getBlockValues().convertKey(baseKey, blockState.getLocation(wrapper.getHandle())); } } public static Key of(Key baseKey, Location location) { Preconditions.checkArgument(baseKey instanceof MaterialKey); return plugin.getBlockValues().convertKey(baseKey, location); } /* Item keys */ public static Key of(ItemStack itemStack) { Material itemType = itemStack.getType(); Key baseKey = (itemType == Materials.SPAWNER.toBukkitType()) ? plugin.getProviders().getSpawnerKey(itemStack) : MaterialKey.of(itemType, itemStack.getDurability(), MaterialKeySource.ITEM); return plugin.getBlockValues().convertKey(baseKey, itemStack); } public static Key of(Material type, short data) { if (ServerVersion.isLessThan(ServerVersion.v1_21) || type == Materials.SPAWNER.toBukkitType()) { return of(new ItemStack(type, 1, data)); } // In 1.21, we cannot set invalid durability for ItemStacks. // Therefore, this code is duplicated from the above method, but // creates the baseKey directly, not from ItemStack. Key baseKey = MaterialKey.of(type, data, MaterialKeySource.ITEM); try { // Now we try to convert the key. // This may throw an exception that is handled below. ItemStack itemStack = new ItemStack(type, 1, data); return plugin.getBlockValues().convertKey(baseKey, itemStack); } catch (IllegalArgumentException error) { // In 1.21, you cannot create ItemStack out of Material types that are not an item // If this occurs, we simply return the base key. return baseKey; } } public static Key of(Material type) { return type == Materials.SPAWNER.toBukkitType() ? SpawnerKey.GLOBAL_KEY : MaterialKey.of(type); } public static Key ofMaterialAndData(String material, @Nullable String data) { try { Material blockType = Material.valueOf(material); if (Text.isBlank(data)) { return Keys.of(blockType); } if (blockType == Materials.SPAWNER.toBukkitType()) { return ofSpawner(data); } short blockData = Short.parseShort(data); return Keys.of(blockType, blockData); } catch (Exception error) { return Keys.of(material, data, KeyIndicator.MATERIAL); } } public static Key ofMaterialAndData(String key) { String[] keySections = KEY_SPLITTER_PATTERN.split(key.toUpperCase(Locale.ENGLISH)); return ofMaterialAndData(keySections[0], keySections.length >= 2 ? keySections[1] : null); } /* Spawner keys */ public static Key ofSpawner(EntityType entityType) { return SpawnerKey.of(of(entityType)); } public static Key ofSpawner(EntityType entityType, Location location) { return plugin.getBlockValues().convertKey(ofSpawner(entityType), location); } public static Key ofSpawner(String customType) { return SpawnerKey.of(ofEntityType(customType)); } public static Key ofSpawner(String customType, Location location) { return plugin.getBlockValues().convertKey(ofSpawner(customType), location); } /* Custom keys */ public static Key of(String globalKey, @Nullable String subKey, KeyIndicator keyType) { return CustomKey.of(globalKey, subKey, keyType); } public static Key ofCustom(String key) { String[] sections = KEY_SPLITTER_PATTERN.split(key); return of(sections[0], sections.length > 2 ? sections[1] : null, KeyIndicator.CUSTOM); } public static Key of(Class baseKeyClass, LazyReference keyLoader) { return new LazyKey<>(baseKeyClass, keyLoader); } private static SpawnerKey getSpawnerKeyFromCreatureSpawner(CreatureSpawner creatureSpawner) { EntityTypeKey entityTypeKey = Optional.ofNullable(creatureSpawner.getSpawnedType()) .map(EntityTypeKey::of).orElse(null); return SpawnerKey.of(entityTypeKey); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/KeysManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.key; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.KeysManager; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.key.map.KeyMapStrategy; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySetStrategy; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.google.common.base.Preconditions; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.function.Supplier; public class KeysManagerImpl extends Manager implements KeysManager { public KeysManagerImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override public void loadData() { // No data to be loaded. } @Override public Key getKey(EntityType entityType) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null."); return ((BaseKey) Keys.of(entityType)).markAPIKey(); } @Override public Key getEntityTypeKey(String entityTypeName) { Preconditions.checkNotNull(entityTypeName, "entityTypeName parameter cannot be null."); return ((BaseKey) Keys.ofEntityType(entityTypeName)).markAPIKey(); } @Override public Key getKey(Entity entity) { Preconditions.checkNotNull(entity, "entity parameter cannot be null."); return ((BaseKey) Keys.of(entity)).markAPIKey(); } @Override public Key getKey(Block block) { Preconditions.checkNotNull(block, "block parameter cannot be null."); return ((BaseKey) Keys.of(block)).markAPIKey(); } @Override public Key getKey(BlockState blockState) { Preconditions.checkNotNull(blockState, "blockState parameter cannot be null."); return ((BaseKey) Keys.of(blockState)).markAPIKey(); } @Override public Key getKey(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "material parameter cannot be null."); return ((BaseKey) Keys.of(itemStack)).markAPIKey(); } @Override public Key getKey(Material material, short data) { Preconditions.checkNotNull(material, "material parameter cannot be null."); return ((BaseKey) Keys.of(material, data)).markAPIKey(); } @Override public Key getKey(Material material) { Preconditions.checkNotNull(material, "material parameter cannot be null."); return ((BaseKey) Keys.of(material)).markAPIKey(); } @Override public Key getMaterialAndDataKey(String type) { Preconditions.checkNotNull(type, "type parameter cannot be null."); return ((BaseKey) Keys.ofMaterialAndData(type)).markAPIKey(); } @Override public Key getSpawnerKey(EntityType entityType) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null."); return ((BaseKey) Keys.ofSpawner(entityType)).markAPIKey(); } @Override public Key getSpawnerKey(String entityTypeName) { Preconditions.checkNotNull(entityTypeName, "entityTypeName parameter cannot be null."); return ((BaseKey) Keys.ofSpawner(entityTypeName)).markAPIKey(); } @Override public Key getKey(String key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); // Due to backwards compatibility, we want to try and check if this is either a MaterialKey or EntityTypeKey. Key materialKey = Key.ofMaterialAndData(key); if (materialKey instanceof MaterialKey) return materialKey; Key entityTypeKey = Key.ofEntityType(key); if (entityTypeKey instanceof EntityTypeKey) return entityTypeKey; // This key does not fit MaterialKey nor EntityTypeKey, therefore we'll create a CustomKey. String[] keySections = key.split(":"); Key customKey = Keys.of(keySections[0], keySections.length >= 2 ? keySections[1] : null, KeyIndicator.CUSTOM); return ((BaseKey) customKey).markAPIKey(); } @Override public Key getKey(String globalKey, String subKey) { Preconditions.checkNotNull(globalKey, "globalKey parameter cannot be null."); Preconditions.checkNotNull(subKey, "subKey parameter cannot be null."); return ((BaseKey) Keys.of(globalKey, subKey, KeyIndicator.CUSTOM)).markAPIKey(); } @Override public KeySet createKeySet(Supplier> setCreator) { return KeySets.createSet(KeyIndicator.CUSTOM, KeySetStrategy.custom(setCreator)); } @Override public KeySet createKeySet(Supplier> setCreator, Collection collection) { if (collection instanceof KeySet) return (KeySet) collection; KeySet keySet = KeySets.createSet(KeyIndicator.CUSTOM, KeySetStrategy.custom(setCreator)); keySet.addAll(collection); return keySet; } @Override public KeyMap createKeyMap(Supplier> mapCreator) { return KeyMaps.createMap(KeyIndicator.CUSTOM, KeyMapStrategy.custom(mapCreator)); } @Override public KeyMap createKeyMap(Supplier> mapCreator, Map map) { if (map instanceof KeyMap) return (KeyMap) map; KeyMap keyMap = KeyMaps.createMap(KeyIndicator.CUSTOM, KeyMapStrategy.custom(mapCreator)); keyMap.putAll(map); return keyMap; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/MaterialKeySource.java ================================================ package com.bgsoftware.superiorskyblock.core.key; public enum MaterialKeySource { ITEM, BLOCK } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java ================================================ package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.types.CustomKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.google.common.base.Preconditions; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; public class AbstractKeyMap extends AbstractMap implements KeyMap { private final LazyReference> innerMap; private final LazyReference> customInnerMap; private final Class keyType; private EntrySet entrySet; private int size; protected AbstractKeyMap(KeyMapStrategy strategy, Class keyType) { this.innerMap = new LazyReference>() { @Override protected Map create() { return strategy.create(false); } }; this.customInnerMap = new LazyReference>() { @Override protected Map create() { return strategy.create(true); } }; this.keyType = keyType; } @Override public int size() { return this.size; } @Override public boolean containsKey(Object key) { return this.get(key) != null; } @Override public V get(Object obj) { if (size() == 0) return null; if (obj instanceof LazyKey) { return get(((LazyKey) obj).getBaseKey()); } return getInternal((Key) obj, true); } private V getInternal(Key key, boolean tryGlobal) { Preconditions.checkArgument(!(key instanceof LazyKey), "Cannot call getInternal on LazyKey directly."); V value; if (this.keyType.isInstance(key)) { value = this.innerMap.getIfPresent().map(m -> m.get(key)).orElse(null); } else if (key instanceof CustomKey) { value = this.customInnerMap.getIfPresent().map(m -> m.get(key)).orElse(null); } else { value = null; } if (!tryGlobal || value != null) return value; Key globalKey = ((BaseKey) key).toGlobalKey(); return globalKey == key ? null : getInternal(globalKey, false); } @Override public V put(Key key, V value) { if (key instanceof LazyKey) { return put(((LazyKey) key).getBaseKey(), value); } V oldValue; if (this.keyType.isInstance(key)) { oldValue = this.innerMap.get().put(this.keyType.cast(key), value); } else if (key instanceof CustomKey) { oldValue = this.customInnerMap.get().put((CustomKey) key, value); } else { throw new IllegalArgumentException("key " + key.getClass() + " is not of type " + this.keyType); } if (oldValue == null) ++this.size; return oldValue; } @Override public V remove(Object key) { return size() == 0 ? null : removeNoSizeCheck(key); } private V removeNoSizeCheck(Object key) { if (key instanceof LazyKey) { return removeNoSizeCheck(((LazyKey) key).getBaseKey()); } V oldValue; if (this.keyType.isInstance(key)) { oldValue = this.innerMap.getIfPresent().map(m -> m.remove(key)).orElse(null); } else if (key instanceof CustomKey) { oldValue = this.customInnerMap.getIfPresent().map(m -> m.remove(key)).orElse(null); } else { return null; } if (oldValue != null) --this.size; return oldValue; } @Override public void clear() { this.innerMap.getIfPresent().ifPresent(Map::clear); this.customInnerMap.getIfPresent().ifPresent(Map::clear); this.size = 0; } @NotNull @Override public Set> entrySet() { return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet; } @Nullable @Override public Key getKey(Key original) { return this.getKey(original, null); } @Override public Key getKey(Key original, @Nullable Key def) { if (size() == 0) return def; if (original instanceof LazyKey) { return getKey(((LazyKey) original).getBaseKey()); } Map map; if (this.keyType.isInstance(original)) { map = this.innerMap.getIfPresent().orElse(null); } else if (original instanceof CustomKey) { map = this.customInnerMap.getIfPresent().orElse(null); } else { map = null; } if (map != null) { if (map.containsKey(original)) return original; Key globalKey = ((BaseKey) original).toGlobalKey(); if (globalKey != original && map.containsKey(globalKey)) return globalKey; } return def; } @Override public boolean removeIf(Predicate predicate) { if (isEmpty()) return false; boolean removed = false; { Map innerMap = this.innerMap.getIfPresent().orElse(null); if (innerMap != null) { int originalSize = innerMap.size(); removed |= innerMap.entrySet().removeIf(entry -> predicate.test(entry.getKey())); int delta = innerMap.size() - originalSize; this.size -= delta; } } { Map customInnerMap = this.customInnerMap.getIfPresent().orElse(null); if (customInnerMap != null) { int originalSize = customInnerMap.size(); removed |= customInnerMap.entrySet().removeIf(entry -> predicate.test(entry.getKey())); int delta = customInnerMap.size() - originalSize; this.size -= delta; } } return removed; } @Override public V getRaw(Key key, V def) { if (size() == 0) return def; return getRawNoSizeCheck(key, def); } private V getRawNoSizeCheck(Key key, V def) { if (key instanceof LazyKey) { return getRawNoSizeCheck(((LazyKey) key).getBaseKey(), def); } return Optional.ofNullable(getInternal(key, false)).orElse(def); } @Override public V getOrDefault(Object key, V defaultValue) { V value = get(key); return value == null ? defaultValue : value; } @Override public Map asMap() { return this; } private class EntrySet extends AbstractSet> { @Override public int size() { return AbstractKeyMap.this.size(); } @Override public boolean isEmpty() { return AbstractKeyMap.this.isEmpty(); } @Override public boolean contains(Object o) { Object key; Object value; if (o instanceof Entry) { Entry entry = (Entry) o; key = entry.getKey(); value = entry.getValue(); } else { key = o; value = null; } V realValue = AbstractKeyMap.this.get(key); return realValue != null && (value == null || Objects.equals(realValue, value)); } @NotNull @Override public Iterator> iterator() { return new EntryIterator(); } @Override public void clear() { AbstractKeyMap.this.clear(); } } private class EntryIterator implements Iterator> { private Iterator currIterator; private boolean isInnerMapIterator; private final boolean shouldRunCustomIterator; EntryIterator() { Map innerMap = AbstractKeyMap.this.innerMap.getIfPresent().orElse(null); Map customInnerMap = AbstractKeyMap.this.customInnerMap.getIfPresent().orElse(null); this.shouldRunCustomIterator = customInnerMap != null && !customInnerMap.isEmpty(); if (innerMap != null) { this.currIterator = innerMap.entrySet().iterator(); this.isInnerMapIterator = true; } else { this.currIterator = customInnerMap == null ? Collections.emptyIterator() : customInnerMap.entrySet().iterator(); this.isInnerMapIterator = false; } } @Override public boolean hasNext() { if (this.isInnerMapIterator) { return this.shouldRunCustomIterator || this.currIterator.hasNext(); } return this.currIterator.hasNext(); } @Override public Entry next() { if (!this.currIterator.hasNext()) { if (!this.isInnerMapIterator || !this.shouldRunCustomIterator) { throw new NoSuchElementException(); } Map customInnerMap = AbstractKeyMap.this.customInnerMap.getIfPresent().orElse(null); // Should never occur as `shouldRunCustomIterator` would be false if (customInnerMap == null || customInnerMap.isEmpty()) throw new NoSuchElementException(); this.currIterator = customInnerMap.entrySet().iterator(); this.isInnerMapIterator = false; } return this.currIterator.next(); } @Override public void remove() { this.currIterator.remove(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/map/CustomKeyMap.java ================================================ package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.google.common.base.Preconditions; import java.util.AbstractMap; import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; public class CustomKeyMap extends AbstractMap implements KeyMap { private final LazyReference> innerMap; protected CustomKeyMap(KeyMapStrategy strategy) { this.innerMap = new LazyReference>() { @Override protected Map create() { return strategy.create(false); } }; } @Override public int size() { return this.innerMap.getIfPresent().map(Map::size).orElse(0); } @Override public boolean containsKey(Object key) { return this.get(key) != null; } @Override public V get(Object obj) { if (size() == 0) return null; if (obj instanceof LazyKey) { return get(((LazyKey) obj).getBaseKey()); } return getInternal((Key) obj, true); } private V getInternal(Key key, boolean tryGlobal) { Preconditions.checkArgument(!(key instanceof LazyKey), "Cannot call getInternal on LazyKey directly."); V value = this.innerMap.getIfPresent().map(m -> m.get(key)).orElse(null); if (!tryGlobal || value != null) return value; Key globalKey = ((BaseKey) key).toGlobalKey(); return globalKey == key ? null : getInternal(globalKey, false); } @Override public V put(Key key, V value) { if (key instanceof LazyKey) { return put(((LazyKey) key).getBaseKey(), value); } return this.innerMap.get().put(key, value); } @Override public V remove(Object key) { return size() == 0 ? null : removeNoSizeCheck(key); } private V removeNoSizeCheck(Object key) { if (key instanceof LazyKey) { return removeNoSizeCheck(((LazyKey) key).getBaseKey()); } return this.innerMap.getIfPresent().map(m -> m.remove(key)).orElse(null); } @Override public void clear() { this.innerMap.getIfPresent().ifPresent(Map::clear); } @NotNull @Override public Set> entrySet() { return this.innerMap.getIfPresent().map(Map::entrySet).orElse(Collections.emptySet()); } @Nullable @Override public Key getKey(Key original) { return this.getKey(original, null); } @Override public Key getKey(Key original, @Nullable Key def) { if (size() == 0) return def; if (original instanceof LazyKey) { return getKey(((LazyKey) original).getBaseKey()); } Map map = this.innerMap.getIfPresent().orElse(null); if (map != null) { if (map.containsKey(original)) return original; Key globalKey = ((BaseKey) original).toGlobalKey(); if (globalKey != original && map.containsKey(globalKey)) return globalKey; } return def; } @Override public boolean removeIf(Predicate predicate) { if (isEmpty()) return false; return this.innerMap.getIfPresent().map(m -> m.entrySet().removeIf(entry -> predicate.test(entry.getKey()))) .orElse(false); } @Override public V getRaw(Key key, V def) { if (size() == 0) return def; return getRawNoSizeCheck(key, def); } private V getRawNoSizeCheck(Key key, V def) { if (key instanceof LazyKey) { return getRawNoSizeCheck(((LazyKey) key).getBaseKey(), def); } return Optional.ofNullable(getInternal(key, false)).orElse(def); } @Override public V getOrDefault(Object key, V defaultValue) { V value = get(key); return value == null ? defaultValue : value; } @Override public Map asMap() { return this; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/map/EntityTypeKeyMap.java ================================================ package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; public class EntityTypeKeyMap extends AbstractKeyMap { public EntityTypeKeyMap(KeyMapStrategy strategy) { super(strategy, EntityTypeKey.class); } @Override public String toString() { return "EntityTypeKeyMap" + super.toString(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMapStrategy.java ================================================ package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; public abstract class KeyMapStrategy { public static final KeyMapStrategy ARRAY_MAP = new KeyMapStrategy() { @Override public Map create(boolean isCustomKeyMap) { return new ArrayMap<>(); } }; public static final KeyMapStrategy CONCURRENT_HASH_MAP = new KeyMapStrategy() { @Override public Map create(boolean isCustomKeyMap) { return new ConcurrentHashMap<>(); } }; public static final KeyMapStrategy HASH_MAP = new KeyMapStrategy() { @Override public Map create(boolean isCustomKeyMap) { return new HashMap<>(); } }; public static KeyMapStrategy custom(Supplier> supplier) { return new KeyMapStrategy() { @Override public Map create(boolean isCustomKeyMap) { return (Map) supplier.get(); } }; } private KeyMapStrategy() { } public abstract Map create(boolean isCustomKeyMap); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMaps.java ================================================ package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; public class KeyMaps { @SuppressWarnings("rawtypes") private static final KeyMap EMPTY_MAP = new EmptyKeyMap(); private KeyMaps() { } public static KeyMap createEmptyMap() { return (KeyMap) EMPTY_MAP; } public static KeyMap unmodifiableKeyMap(KeyMap delegate) { return delegate == EMPTY_MAP ? createEmptyMap() : new UnmodifiableKeyMap<>(delegate); } public static KeyMap createHashMap(KeyIndicator keyIndicator) { return createMap(keyIndicator, KeyMapStrategy.HASH_MAP); } public static KeyMap createConcurrentHashMap(KeyIndicator keyIndicator) { return createMap(keyIndicator, KeyMapStrategy.CONCURRENT_HASH_MAP); } public static KeyMap createArrayMap(KeyIndicator keyIndicator) { return createMap(keyIndicator, KeyMapStrategy.ARRAY_MAP); } public static KeyMap createMap(KeyIndicator keyIndicator, KeyMapStrategy strategy) { switch (keyIndicator) { case MATERIAL: return new MaterialKeyMap<>(strategy); case ENTITY_TYPE: return new EntityTypeKeyMap<>(strategy); } return new LazyLoadedKeyMap<>(strategy); } private static class EmptyKeyMap implements KeyMap { @Nullable @Override public Key getKey(Key original) { return null; } @Override public Key getKey(Key original, @Nullable Key def) { return def; } @Override public V getRaw(Key key, V def) { return def; } @Override public Map asMap() { return this; } @Override public int size() { return 0; } @Override public boolean isEmpty() { return true; } @Override public boolean containsKey(Object key) { return false; } @Override public boolean containsValue(Object value) { return false; } @Override public V get(Object key) { return null; } @NotNull @Override public Set keySet() { return Collections.emptySet(); } @NotNull @Override public Collection values() { return Collections.emptyList(); } @NotNull @Override public Set> entrySet() { return Collections.emptySet(); } @Override public boolean equals(Object obj) { return obj instanceof Map && ((Map) obj).isEmpty(); } @Override public int hashCode() { return 0; } @Override public V getOrDefault(Object key, V defaultValue) { return defaultValue; } @Override public void forEach(BiConsumer action) { // Do nothing. } @Override public void replaceAll(BiFunction function) { // Do nothing. } @Nullable @Override public V putIfAbsent(Key key, V value) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public V remove(Object key) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public boolean replace(Key key, V oldValue, V newValue) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Nullable @Override public V replace(Key key, V value) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public V computeIfAbsent(Key key, @NotNull Function mappingFunction) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public V computeIfPresent(Key key, @NotNull BiFunction remappingFunction) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public V compute(Key key, @NotNull BiFunction remappingFunction) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public V merge(Key key, @NotNull V value, @NotNull BiFunction remappingFunction) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Nullable @Override public V put(Key key, V value) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public void putAll(@NotNull Map m) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public void clear() { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } @Override public boolean removeIf(Predicate predicate) { throw new UnsupportedOperationException("Cannot modify EmptyKeyMap"); } } private static class UnmodifiableKeyMap implements KeyMap { private final KeyMap delegate; UnmodifiableKeyMap(KeyMap delegate) { this.delegate = delegate; } @Nullable @Override public Key getKey(Key original) { return this.delegate.getKey(original); } @Override public Key getKey(Key original, @Nullable Key def) { return this.delegate.getKey(original, def); } @Override public V getRaw(Key key, V def) { return this.delegate.getRaw(key, def); } @Override public Map asMap() { return this; } @Override public int size() { return this.delegate.size(); } @Override public boolean isEmpty() { return this.delegate.isEmpty(); } @Override public boolean containsKey(Object key) { return this.delegate.containsKey(key); } @Override public boolean containsValue(Object value) { return this.delegate.containsValue(value); } @Override public V get(Object key) { return this.delegate.get(key); } @NotNull @Override public Set keySet() { return this.delegate.keySet(); } @NotNull @Override public Collection values() { return this.delegate.values(); } @NotNull @Override public Set> entrySet() { return this.delegate.entrySet(); } @Override public boolean removeIf(Predicate predicate) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeyMap"); } @Nullable @Override public V put(Key key, V value) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeyMap"); } @Override public V remove(Object key) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeyMap"); } @Override public void putAll(@NotNull Map m) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeyMap"); } @Override public void clear() { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeyMap"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java ================================================ package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import java.util.AbstractMap; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; public class LazyLoadedKeyMap extends AbstractMap implements KeyMap { private final KeyMapStrategy strategy; @Nullable private KeyMap delegate; @Nullable private KeyMap pendingCustomKeys; public LazyLoadedKeyMap(KeyMapStrategy strategy) { this.strategy = strategy; } @Override public int size() { return runOnMap(KeyMap::size, 0); } @Override public boolean containsKey(Object o) { return runOnMap(m -> m.containsKey(o), false); } @Override public V get(Object obj) { return runOnMap(m -> m.get(obj), null); } @Override public V put(Key key, V value) { if (this.delegate != null) return this.delegate.put(key, value); return putNoDelegate(key, value); } private V putNoDelegate(Key key, V value) { if (key instanceof LazyKey) { return putNoDelegate(((LazyKey) key).getBaseKey(), value); } if (key instanceof EntityTypeKey) { this.delegate = new EntityTypeKeyMap<>(this.strategy); addPendingCustomKeys(); } else if (key instanceof MaterialKey) { this.delegate = new MaterialKeyMap<>(this.strategy); addPendingCustomKeys(); } else { if (this.pendingCustomKeys == null) this.pendingCustomKeys = new CustomKeyMap<>(this.strategy); return this.pendingCustomKeys.put(key, value); } return this.delegate.put(key, value); } @Override public V remove(Object key) { return runOnMap(m -> m.remove(key), null); } @Override public void clear() { runOnMap(KeyMap::clear); } @NotNull @Override public Set> entrySet() { return runOnMap(KeyMap::entrySet, Collections.emptySet()); } @Override public String toString() { return runOnMap(KeyMap::toString, "LazyLoadedKeyMap{}"); } @Nullable @Override public Key getKey(Key original) { return runOnMap(m -> m.getKey(original), null); } @Override public Key getKey(Key original, @Nullable Key def) { return runOnMap(m -> m.getKey(original, def), def); } @Override public boolean removeIf(Predicate predicate) { return runOnMap(m -> m.removeIf(predicate), false); } @Override public V getRaw(Key key, V def) { return runOnMap(m -> m.getRaw(key, def), def); } @Override public V getOrDefault(Object key, V defaultValue) { return runOnMap(m -> m.getOrDefault(key, defaultValue), defaultValue); } @Override public Map asMap() { return runOnMap(KeyMap::asMap, this); } private T runOnMap(Function, T> function, T def) { if (this.delegate != null) return function.apply(this.delegate); else if (this.pendingCustomKeys != null) return function.apply(this.pendingCustomKeys); else return def; } private void runOnMap(Consumer> consumer) { if (this.delegate != null) consumer.accept(this.delegate); else if (this.pendingCustomKeys != null) consumer.accept(this.pendingCustomKeys); } private void addPendingCustomKeys() { if (this.pendingCustomKeys == null) return; this.delegate.putAll(this.pendingCustomKeys); this.pendingCustomKeys = null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/map/MaterialKeyMap.java ================================================ package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; public class MaterialKeyMap extends AbstractKeyMap { public MaterialKeyMap(KeyMapStrategy strategy) { super(strategy, MaterialKey.class); } @Override public String toString() { return "MaterialKeyMap" + super.toString(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/set/AbstractKeySet.java ================================================ package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.types.CustomKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.google.common.base.Preconditions; import java.util.AbstractSet; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; public class AbstractKeySet extends AbstractSet implements KeySet { private final LazyReference> innerSet; private final LazyReference> customInnerSet; private final Class keyType; private int size; protected AbstractKeySet(KeySetStrategy strategy, Class keyType) { this.innerSet = new LazyReference>() { @Override protected Set create() { return strategy.create(false); } }; this.customInnerSet = new LazyReference>() { @Override protected Set create() { return strategy.create(true); } }; this.keyType = keyType; } @Override public int size() { return this.size; } @Override public boolean contains(Object o) { if (size() == 0) return false; if (o instanceof LazyKey) { return contains(((LazyKey) o).getBaseKey()); } return containsInternal((Key) o, true); } private boolean containsInternal(Key key, boolean tryGlobal) { Preconditions.checkArgument(!(key instanceof LazyKey), "Cannot call getInternal on LazyKey directly."); boolean contained; if (this.keyType.isInstance(key)) { contained = this.innerSet.getIfPresent().map(s -> s.contains(key)).orElse(false); } else if (key instanceof CustomKey) { contained = this.customInnerSet.getIfPresent().map(s -> s.contains(key)).orElse(false); } else { contained = false; } if (!tryGlobal || contained) return contained; Key globalKey = ((BaseKey) key).toGlobalKey(); return globalKey != key && containsInternal(globalKey, false); } @Override public boolean add(Key key) { if (key instanceof LazyKey) { return add(((LazyKey) key).getBaseKey()); } boolean modified; if (this.keyType.isInstance(key)) { modified = this.innerSet.get().add(this.keyType.cast(key)); } else if (key instanceof CustomKey) { modified = this.customInnerSet.get().add((CustomKey) key); } else { throw new IllegalArgumentException("key " + key.getClass() + " is not of type " + this.keyType); } if (modified) ++this.size; return modified; } @Override public boolean remove(Object key) { return size() != 0 && removeNoSizeCheck(key); } private boolean removeNoSizeCheck(Object key) { if (key instanceof LazyKey) { return remove(((LazyKey) key).getBaseKey()); } boolean contained; if (this.keyType.isInstance(key)) { contained = this.innerSet.getIfPresent().map(s -> s.remove(key)).orElse(false); } else if (key instanceof CustomKey) { contained = this.customInnerSet.getIfPresent().map(s -> s.remove(key)).orElse(false); } else { return false; } if (contained) --this.size; return contained; } @Override public void clear() { this.innerSet.getIfPresent().ifPresent(Set::clear); this.customInnerSet.getIfPresent().ifPresent(Set::clear); this.size = 0; } @Override public Iterator iterator() { return new SetIterator(); } @Nullable @Override public Key getKey(Key original) { return this.getKey(original, null); } @Override public Key getKey(Key original, @Nullable Key def) { if (size() == 0) return def; if (original instanceof LazyKey) { return getKey(((LazyKey) original).getBaseKey()); } Set set; if (this.keyType.isInstance(original)) { set = this.innerSet.getIfPresent().orElse(null); } else if (original instanceof CustomKey) { set = this.customInnerSet.getIfPresent().orElse(null); } else { set = null; } if (set != null) { if (set.contains(original)) return original; Key globalKey = ((BaseKey) original).toGlobalKey(); if (globalKey != original && set.contains(globalKey)) return globalKey; } return def; } @Override public Set asSet() { return this; } private class SetIterator implements Iterator { private Iterator currIterator; private boolean isInnerSetIterator; private final boolean shouldRunCustomIterator; SetIterator() { Set innerSet = AbstractKeySet.this.innerSet.getIfPresent().orElse(null); Set customInnerSet = AbstractKeySet.this.customInnerSet.getIfPresent().orElse(null); this.shouldRunCustomIterator = customInnerSet != null && !customInnerSet.isEmpty(); if (innerSet != null) { this.currIterator = innerSet.iterator(); this.isInnerSetIterator = true; } else { this.currIterator = customInnerSet == null ? Collections.emptyIterator() : customInnerSet.iterator(); this.isInnerSetIterator = false; } } @Override public boolean hasNext() { if (this.isInnerSetIterator) { return this.shouldRunCustomIterator || this.currIterator.hasNext(); } return this.currIterator.hasNext(); } @Override public Key next() { if (!this.currIterator.hasNext()) { if (!this.isInnerSetIterator || !this.shouldRunCustomIterator) { throw new NoSuchElementException(); } Set customInnerSet = AbstractKeySet.this.customInnerSet.getIfPresent().orElse(null); // Should never occur as `shouldRunCustomIterator` would be false if (customInnerSet == null || customInnerSet.isEmpty()) throw new NoSuchElementException(); this.currIterator = customInnerSet.iterator(); this.isInnerSetIterator = false; } return this.currIterator.next(); } @Override public void remove() { this.currIterator.remove(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java ================================================ package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.google.common.base.Preconditions; import java.util.AbstractSet; import java.util.Collections; import java.util.Iterator; import java.util.Set; public class CustomKeySet extends AbstractSet implements KeySet { private final LazyReference> innerSet; public CustomKeySet(KeySetStrategy strategy) { this.innerSet = new LazyReference>() { @Override protected Set create() { return strategy.create(true); } }; } @Override public int size() { return this.innerSet.getIfPresent().map(Set::size).orElse(0); } @Override public boolean contains(Object o) { if (size() == 0) return false; if (o instanceof LazyKey) { return contains(((LazyKey) o).getBaseKey()); } return containsInternal((Key) o, true); } private boolean containsInternal(Key key, boolean tryGlobal) { Preconditions.checkArgument(!(key instanceof LazyKey), "Cannot call getInternal on LazyKey directly."); boolean contained = this.innerSet.getIfPresent().map(s -> s.contains(key)).orElse(false); if (!tryGlobal || contained) return contained; Key globalKey = ((BaseKey) key).toGlobalKey(); return globalKey != key && containsInternal(globalKey, false); } @Override public boolean add(Key key) { if (key instanceof LazyKey) { return add(((LazyKey) key).getBaseKey()); } return this.innerSet.get().add(key); } @Override public boolean remove(Object key) { return size() != 0 && removeNoSizeCheck(key); } private boolean removeNoSizeCheck(Object key) { if (key instanceof LazyKey) { return remove(((LazyKey) key).getBaseKey()); } return this.innerSet.getIfPresent().map(s -> s.remove(key)).orElse(false); } @Override public void clear() { this.innerSet.getIfPresent().ifPresent(Set::clear); } @Override public Iterator iterator() { return this.innerSet.getIfPresent().map(Set::iterator).orElse(Collections.emptyIterator()); } @Nullable @Override public Key getKey(Key original) { return this.getKey(original, null); } @Override public Key getKey(Key original, @Nullable Key def) { if (size() == 0) return def; if (original instanceof LazyKey) { return getKey(((LazyKey) original).getBaseKey()); } Set set = this.innerSet.getIfPresent().orElse(null); if (set != null) { if (set.contains(original)) return original; Key globalKey = ((BaseKey) original).toGlobalKey(); if (globalKey != original && set.contains(globalKey)) return globalKey; } return def; } @Override public Set asSet() { return this; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/set/EntityTypeKeySet.java ================================================ package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; public class EntityTypeKeySet extends AbstractKeySet { public EntityTypeKeySet(KeySetStrategy strategy) { super(strategy, EntityTypeKey.class); } @Override public String toString() { return "EntityTypeKeySet" + super.toString(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySetStrategy.java ================================================ package com.bgsoftware.superiorskyblock.core.key.set; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Supplier; public abstract class KeySetStrategy { public static final KeySetStrategy HASH_SET = new KeySetStrategy() { @Override public Set create(boolean isCustomKeySet) { return new HashSet<>(); } }; public static KeySetStrategy custom(Supplier> supplier) { return new KeySetStrategy() { @Override public Set create(boolean isCustomKeyMap) { return (Set) supplier.get(); } }; } private KeySetStrategy() { } public abstract Set create(boolean isCustomKeySet); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java ================================================ package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; public class KeySets { private static final KeySet EMPTY_SET = new EmptyKeySet(); private KeySets() { } public static KeySet createEmptySet() { return EMPTY_SET; } public static KeySet unmodifiableKeySet(KeySet delegate) { return delegate == EMPTY_SET ? createEmptySet() : new UnmodifiableKeySet(delegate); } public static KeySet createHashSet(KeyIndicator keyIndicator) { return createSet(keyIndicator, KeySetStrategy.HASH_SET); } public static KeySet createSet(KeyIndicator keyIndicator, KeySetStrategy strategy) { switch (keyIndicator) { case MATERIAL: return new MaterialKeySet(strategy); case ENTITY_TYPE: return new EntityTypeKeySet(strategy); } return new LazyLoadedKeySet(strategy); } public static KeySet createHashSet(KeyIndicator keyIndicator, Collection rawKeys) { KeySet keySet = createHashSet(keyIndicator); Function keyCreator; switch (keyIndicator) { case MATERIAL: keyCreator = Keys::ofMaterialAndData; break; case ENTITY_TYPE: keyCreator = Keys::ofEntityType; break; default: keyCreator = Keys::ofCustom; break; } rawKeys.forEach(key -> keySet.add(keyCreator.apply(key))); return keySet; } private static class EmptyKeySet implements KeySet { @Nullable @Override public Key getKey(Key original) { return null; } @Override public Key getKey(Key original, Key def) { return def; } @Override public Set asSet() { return this; } @Override public int size() { return 0; } @Override public boolean isEmpty() { return true; } @Override public boolean contains(Object o) { return false; } @Override public boolean containsAll(@NotNull Collection c) { return c.isEmpty(); } @NotNull @Override public Iterator iterator() { return Collections.emptyIterator(); } @NotNull @Override public Object[] toArray() { return new Object[0]; } @NotNull @Override public T[] toArray(@NotNull T[] a) { if (a.length > 0) a[0] = null; return a; } @Override public void forEach(Consumer action) { // Do nothing. } @Override public boolean removeIf(Predicate filter) { return false; } @Override public Spliterator spliterator() { return Spliterators.emptySpliterator(); } @Override public boolean add(Key key) { throw new UnsupportedOperationException("Cannot modify EmptyKeySet"); } @Override public boolean remove(Object o) { throw new UnsupportedOperationException("Cannot modify EmptyKeySet"); } @Override public boolean addAll(@NotNull Collection c) { throw new UnsupportedOperationException("Cannot modify EmptyKeySet"); } @Override public boolean retainAll(@NotNull Collection c) { throw new UnsupportedOperationException("Cannot modify EmptyKeySet"); } @Override public boolean removeAll(@NotNull Collection c) { throw new UnsupportedOperationException("Cannot modify EmptyKeySet"); } @Override public void clear() { throw new UnsupportedOperationException("Cannot modify EmptyKeySet"); } } private static class UnmodifiableKeySet implements KeySet { private final KeySet delegate; UnmodifiableKeySet(KeySet delegate) { this.delegate = delegate; } @Nullable @Override public Key getKey(Key original) { return this.delegate.getKey(original); } @Override public Key getKey(Key original, Key def) { return this.delegate.getKey(original, def); } @Override public Set asSet() { return this; } @Override public int size() { return this.delegate.size(); } @Override public boolean isEmpty() { return this.delegate.isEmpty(); } @Override public boolean contains(Object o) { return this.delegate.contains(o); } @NotNull @Override public Iterator iterator() { return this.delegate.iterator(); } @NotNull @Override public Object[] toArray() { return this.delegate.toArray(); } @NotNull @Override public T[] toArray(@NotNull T[] a) { return this.delegate.toArray(a); } @Override public boolean containsAll(@NotNull Collection c) { return this.delegate.containsAll(c); } @Override public boolean add(Key key) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeySet"); } @Override public boolean remove(Object o) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeySet"); } @Override public boolean addAll(@NotNull Collection c) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeySet"); } @Override public boolean retainAll(@NotNull Collection c) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeySet"); } @Override public boolean removeAll(@NotNull Collection c) { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeySet"); } @Override public void clear() { throw new UnsupportedOperationException("Cannot modify UnmodifiableKeySet"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java ================================================ package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import java.util.AbstractSet; import java.util.Collections; import java.util.Iterator; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; public class LazyLoadedKeySet extends AbstractSet implements KeySet { private final KeySetStrategy strategy; @Nullable private KeySet delegate; @Nullable private KeySet pendingCustomKeys; public LazyLoadedKeySet(KeySetStrategy strategy) { this.strategy = strategy; } @Override public int size() { return runOnSet(KeySet::size, 0); } @Override public boolean contains(Object o) { return runOnSet(s -> s.contains(o), false); } @Override public boolean add(Key key) { if (this.delegate != null) return this.delegate.add(key); return addNoDelegate(key); } public boolean addNoDelegate(Key key) { if (key instanceof LazyKey) { return addNoDelegate(((LazyKey) key).getBaseKey()); } if (key instanceof EntityTypeKey) { this.delegate = new EntityTypeKeySet(this.strategy); addPendingCustomKeys(); } else if (key instanceof MaterialKey) { this.delegate = new MaterialKeySet(this.strategy); addPendingCustomKeys(); } else { if (this.pendingCustomKeys == null) this.pendingCustomKeys = new CustomKeySet(this.strategy); return this.pendingCustomKeys.add(key); } return this.delegate.add(key); } @Override public boolean remove(Object key) { return runOnSet(s -> s.remove(key), false); } @Override public void clear() { runOnSet(Set::clear); } @Override public Iterator iterator() { return runOnSet(Set::iterator, Collections.emptyIterator()); } @Nullable @Override public Key getKey(Key original) { return runOnSet(s -> s.getKey(original), null); } @Override public Key getKey(Key original, Key def) { return runOnSet(s -> s.getKey(original, def), def); } @Override public String toString() { return runOnSet(Object::toString, "LazyLoadedKeySet[]"); } @Override public Set asSet() { return runOnSet(KeySet::asSet, this); } private T runOnSet(Function function, T def) { if (this.delegate != null) return function.apply(this.delegate); else if (this.pendingCustomKeys != null) return function.apply(this.pendingCustomKeys); else return def; } private void runOnSet(Consumer consumer) { if (this.delegate != null) consumer.accept(this.delegate); else if (this.pendingCustomKeys != null) consumer.accept(this.pendingCustomKeys); } private void addPendingCustomKeys() { if (this.pendingCustomKeys == null) return; this.delegate.addAll(this.pendingCustomKeys); this.pendingCustomKeys = null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/set/MaterialKeySet.java ================================================ package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; public class MaterialKeySet extends AbstractKeySet { public MaterialKeySet(KeySetStrategy strategy) { super(strategy, MaterialKey.class); } @Override public String toString() { return "MaterialKeySet" + super.toString(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/types/CustomKey.java ================================================ package com.bgsoftware.superiorskyblock.core.key.types; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.google.common.base.Preconditions; import org.bukkit.Material; import org.bukkit.entity.EntityType; import java.util.Locale; import java.util.Objects; public class CustomKey extends BaseKey { private final LazyReference apiKeyCache = new LazyReference() { @Override protected CustomKey create() { if (CustomKey.this.isAPIKey()) throw new UnsupportedOperationException(); return new CustomKey(CustomKey.this.globalKey, CustomKey.this.subKey, true); } }; private final String globalKey; private final String subKey; public static CustomKey of(String globalKey, @Nullable String subKey, KeyIndicator keyType) { switch (keyType) { case ENTITY_TYPE: Preconditions.checkArgument(EnumHelper.getEnum(EntityType.class, globalKey) == null, "CustomKey received a valid EntityType type: " + globalKey); break; case MATERIAL: Preconditions.checkArgument(EnumHelper.getEnum(Material.class, globalKey) == null, "CustomKey received a valid Material type: " + globalKey); break; } return new CustomKey(globalKey, subKey, false); } private CustomKey(String globalKey, @Nullable String subKey, boolean apiKey) { super(CustomKey.class, apiKey); this.globalKey = Preconditions.checkNotNull(globalKey, "globalKey cannot be null").toUpperCase(Locale.ENGLISH); this.subKey = Text.isBlank(subKey) ? null : subKey.toUpperCase(Locale.ENGLISH); } @Override public String getGlobalKey() { return this.globalKey; } @Override public CustomKey toGlobalKey() { return this.subKey == null ? this : CustomKey.of(this.globalKey, null, KeyIndicator.CUSTOM); } @Override public String getSubKey() { return this.subKey; } @Override protected String toStringInternal() { return this.subKey == null ? this.globalKey : this.globalKey + ":" + this.subKey; } @Override protected int hashCodeInternal() { return Objects.hash(this.globalKey, this.subKey); } @Override protected boolean equalsInternal(CustomKey other) { return this.globalKey.equals(other.globalKey) && Objects.equals(this.subKey, other.subKey); } @Override protected int compareToInternal(CustomKey other) { return toString().compareTo(other.toString()); } @Override public CustomKey createAPIKeyInternal() { return this.apiKeyCache.get(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java ================================================ package com.bgsoftware.superiorskyblock.core.key.types; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.google.common.base.Preconditions; import org.bukkit.entity.EntityType; import java.util.EnumMap; public class EntityTypeKey extends BaseKey { private static final EnumMap ENTITY_TYPE_KEYS_CACHE = new EnumMap<>(EntityType.class); static { // Load all entity type keys for (EntityType entityType : EntityType.values()) { EntityTypeKey entityTypeKey = of(entityType); entityTypeKey.loadLazyCaches(); } } private final LazyReference apiKeyCache = new LazyReference() { @Override protected EntityTypeKey create() { if (EntityTypeKey.this.isAPIKey()) throw new UnsupportedOperationException(); return new EntityTypeKey(EntityTypeKey.this.entityType, true); } }; private final EntityType entityType; public static EntityTypeKey of(EntityType entityType) { return ENTITY_TYPE_KEYS_CACHE.computeIfAbsent(entityType, EntityTypeKey::new); } private EntityTypeKey(EntityType entityType) { this(entityType, false); } private EntityTypeKey(EntityType entityType, boolean apiKey) { super(EntityTypeKey.class, apiKey); this.entityType = Preconditions.checkNotNull(entityType, "entityType cannot be null"); } @Override public String getGlobalKey() { return this.entityType.name(); } @Override public EntityTypeKey toGlobalKey() { return this; } @Override public String getSubKey() { return ""; } @Override protected int compareToInternal(EntityTypeKey other) { return Integer.compare(this.entityType.ordinal(), other.entityType.ordinal()); } @Override protected String toStringInternal() { return this.getGlobalKey(); } @Override protected int hashCodeInternal() { return this.entityType.hashCode(); } @Override protected boolean equalsInternal(EntityTypeKey other) { return this.entityType == other.entityType; } @Override public EntityTypeKey createAPIKeyInternal() { return this.apiKeyCache.get(); } public EntityType getEntityType() { return entityType; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/types/LazyKey.java ================================================ package com.bgsoftware.superiorskyblock.core.key.types; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.google.common.base.Preconditions; public class LazyKey extends BaseKey { private final LazyReference baseKeyLoader; public LazyKey(Class baseKeyClass, LazyReference baseKeyLoader) { super(baseKeyClass, false); Preconditions.checkArgument(baseKeyClass != BaseKey.class); this.baseKeyLoader = baseKeyLoader; } public T getBaseKey() { return this.baseKeyLoader.get(); } @Override public final String getGlobalKey() { return getBaseKey().getGlobalKey(); } @Override public final T toGlobalKey() { return ((BaseKey) getBaseKey()).toGlobalKey(); } @Override public final String getSubKey() { return getBaseKey().getSubKey(); } @Override protected final String toStringInternal() { return getBaseKey().toString(); } @Override protected final int hashCodeInternal() { return getBaseKey().hashCode(); } @Override protected final boolean equalsInternal(T other) { return getBaseKey().equals(other); } @Override protected final int compareToInternal(T other) { return getBaseKey().compareTo(other); } @Override public T createAPIKeyInternal() { return ((BaseKey) getBaseKey()).createAPIKeyInternal(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java ================================================ package com.bgsoftware.superiorskyblock.core.key.types; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.MaterialKeySource; import com.google.common.base.Objects; import com.google.common.base.Preconditions; import org.bukkit.Material; import java.util.EnumMap; public class MaterialKey extends BaseKey { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final EnumMap GLOBAL_MATERIAL_KEYS_CACHE = new EnumMap<>(Material.class); private static final EnumMap ID_MATERIAL_KEYS_CACHE = new EnumMap<>(Material.class); static { // Load all material type keys for (Material material : Material.values()) { if (material != Materials.SPAWNER.toBukkitType()) { MaterialKey globalKey = of(material); globalKey.loadLazyCaches(); int maxDataValue = plugin.getNMSAlgorithms().getMaxBlockDataValue(material) + 1; for (int i = 0; i < maxDataValue; ++i) { MaterialKey materialKey = of(material, (short) i, MaterialKeySource.BLOCK); materialKey.loadLazyCaches(); } } } } private final LazyReference apiKeyCache = new LazyReference() { @Override protected MaterialKey create() { if (MaterialKey.this.isAPIKey()) throw new UnsupportedOperationException(); return createAPIKeyForCacheInternal(); } }; protected final Material type; private final short durability; private final String durabilityAsString; protected final boolean isGlobalType; private final MaterialKeySource materialKeySource; public static MaterialKey of(Material type, short durability, MaterialKeySource materialKeySource) { Preconditions.checkArgument(type != Materials.SPAWNER.toBukkitType()); if (materialKeySource == MaterialKeySource.BLOCK) { MaterialKey[] cachedIds = ID_MATERIAL_KEYS_CACHE.computeIfAbsent(type, MaterialKey::createMaterialKeyCacheForType); if (durability < cachedIds.length) { return cachedIds[durability]; } } return new MaterialKey(type, durability, false, materialKeySource); } public static MaterialKey of(Material type) { return GLOBAL_MATERIAL_KEYS_CACHE.computeIfAbsent(type, unused -> new MaterialKey(type, (short) 0, true, MaterialKeySource.BLOCK)); } protected MaterialKey(Material type, short durability, boolean isGlobalType, MaterialKeySource materialKeySource) { this(type, durability, isGlobalType, materialKeySource, false); } protected MaterialKey(Material type, short durability, boolean isGlobalType, MaterialKeySource materialKeySource, boolean apiKey) { super(MaterialKey.class, apiKey); this.type = Preconditions.checkNotNull(type, "type parameter cannot be null"); this.durability = durability; this.durabilityAsString = isGlobalType ? "" : String.valueOf(this.durability); this.isGlobalType = isGlobalType; this.materialKeySource = materialKeySource; } @Override public String getGlobalKey() { return this.type.name(); } @Override public MaterialKey toGlobalKey() { return this.isGlobalType ? this : MaterialKey.of(this.type); } @Override public String getSubKey() { return this.durabilityAsString; } public MaterialKeySource getMaterialKeySource() { return materialKeySource; } @Override protected String toStringInternal() { return this.isGlobalType ? this.getGlobalKey() : this.getGlobalKey() + ":" + this.getSubKey(); } @Override protected int hashCodeInternal() { return Objects.hashCode(this.type, this.durability); } @Override protected boolean equalsInternal(MaterialKey other) { return this.type == other.type && this.durability == other.durability && this.isGlobalType == other.isGlobalType; } @Override protected int compareToInternal(MaterialKey other) { return this.toString().compareTo(other.toString()); } @Override public MaterialKey createAPIKeyInternal() { return this.apiKeyCache.get(); } protected MaterialKey createAPIKeyForCacheInternal() { return new MaterialKey(MaterialKey.this.type, MaterialKey.this.durability, MaterialKey.this.isGlobalType, MaterialKey.this.materialKeySource, true); } public Material getMaterial() { return this.type; } public short getDurability() { return this.durability; } private static MaterialKey[] createMaterialKeyCacheForType(Material type) { MaterialKey[] cache = new MaterialKey[plugin.getNMSAlgorithms().getMaxBlockDataValue(type) + 1]; for (int i = 0; i < cache.length; ++i) cache[i] = new MaterialKey(type, (short) i, false, MaterialKeySource.BLOCK); return cache; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java ================================================ package com.bgsoftware.superiorskyblock.core.key.types; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.MaterialKeySource; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.google.common.base.Objects; import org.bukkit.Material; import org.bukkit.entity.EntityType; public class SpawnerKey extends MaterialKey { private static final Material SPAWNER_TYPE = Materials.SPAWNER.toBukkitType(); private static final KeyMap SPAWNER_KEYS_CACHE = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); public static final SpawnerKey GLOBAL_KEY = new SpawnerKey(null); static { // Load all spawner type keys for (EntityType entityType : EntityType.values()) { SpawnerKey spawnerKey = of(Keys.of(entityType)); spawnerKey.loadLazyCaches(); } } private final Key spawnerTypeKey; public static SpawnerKey of(@Nullable Key spawnerTypeKey) { return spawnerTypeKey == null ? GLOBAL_KEY : SPAWNER_KEYS_CACHE.computeIfAbsent(spawnerTypeKey, SpawnerKey::new); } private SpawnerKey(@Nullable Key spawnerTypeKey) { this(spawnerTypeKey, false); } private SpawnerKey(@Nullable Key spawnerTypeKey, boolean apiKey) { super(SPAWNER_TYPE, (short) 0, spawnerTypeKey == null, MaterialKeySource.BLOCK, apiKey); this.spawnerTypeKey = spawnerTypeKey; } @Override public SpawnerKey toGlobalKey() { return GLOBAL_KEY; } @Override public String getSubKey() { return this.isGlobalType ? "" : getSubKeyInternal(); } @Override protected MaterialKey createAPIKeyForCacheInternal() { return new SpawnerKey(this.spawnerTypeKey, true); } private String getSubKeyInternal() { assert this.spawnerTypeKey != null; return this.spawnerTypeKey.toString(); } @Override protected String toStringInternal() { return this.isGlobalType ? this.getGlobalKey() : this.getGlobalKey() + ":" + this.getSubKeyInternal(); } @Override protected int hashCodeInternal() { return Objects.hashCode(SPAWNER_TYPE, this.spawnerTypeKey); } @Override protected boolean equalsInternal(MaterialKey other) { if (other instanceof SpawnerKey) { return Objects.equal(this.spawnerTypeKey, ((SpawnerKey) other).spawnerTypeKey); } return this.isGlobalType && other.isGlobalType && other.type == SPAWNER_TYPE; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java ================================================ package com.bgsoftware.superiorskyblock.core.logging; import java.util.Locale; public enum Debug { ADD_COOP, ADD_MEMBER, BAN_PLAYER, BLOCK_BREAK, BLOCK_COUNT_DECREASE, BLOCK_COUNT_INCREASE, BLOCK_PLACE, CALCULATE_ALL_ISLANDS, CALCULATE_ISLAND, CHUNK_CALCULATION_BLOCKS, CHUNK_CALCULATION_ENTITIES, CLEAR_BLOCK_LIMITS, CLEAR_ENTITY_LIMITS, CLEAR_GENERATOR_RATES, CLEAR_ISLAND_EFFECTS, CREATE_ISLAND, CREATE_WARP, CREATE_WARP_CATEGORY, DATABASE_QUERY, DELETE_ISLAND, DELETE_WARP, DELETE_WARP_CATEGORY, DEPOSIT_MONEY, DISABLE_ISLAND_FLAG, DISABLE_REDSTONE, ENABLE_ISLAND_FLAG, ENTER_ISLAND, ENTITY_DESPAWN, ENTITY_SPAWN, EXECUTE_COMMAND, EXECUTE_ISLAND_COMMANDS, FIND_SAFE_TELEPORT, FIRE_EVENT, GENERATE_BLOCK, GET_VALUE, GIVE_BANK_INTEREST, INVITE_MEMBER, ISLAND_ACTIVE, KICK_MEMBER, LEAVE_ISLAND, LOAD_CHUNK, MENU_CLICK, OPEN_MENU, PASTE_SCHEMATIC, PERMISSION_LOOKUP, PURGE_ISLAND, REGISTER_SORTING_TYPE, REMOVE_BLOCK_LIMIT, REMOVE_COOP, REMOVE_ENTITY_LIMIT, REMOVE_GENERATOR_RATE, REMOVE_ISLAND_EFFECT, REMOVE_PLAYER_STATUS, REMOVE_RATING, REMOVE_RATINGS, REMOVE_ROLE_LIMIT, REPLACE_PLAYER, RESET_ISLAND_FLAGS, RESET_PERMISSIONS, REVOKE_INVITE, REWARD_MISSION, SAVE_SCHEMATIC, SEND_MESSAGE, SEND_TITLE, SET_ADMIN_BYPASS, SET_ADMIN_SPY, SET_BANK_LIMIT, SET_BIOME, SET_BLOCK_AMOUNT, SET_BLOCK_LIMIT, SET_BONUS_LEVEL, SET_BONUS_WORTH, SET_BORDER_COLOR, SET_COOP_LIMIT, SET_CROP_GROWTH, SET_DESCRIPTION, SET_DIMENSION_ENABLED, SET_DISBANDS, SET_DISCORD, SET_ENTITY_LIMIT, SET_GENERATOR_PERCENTAGE, SET_GENERATOR_RATE, SET_IGNORED, SET_ISLAND_EFFECT, SET_ISLAND_FLY, SET_ISLAND_HOME, SET_ISLAND_LAST_TIME_UPDATED, SET_ISLAND_MISSION_COMPLETED, SET_LANGUAGE, SET_LAST_ISLAND, SET_LOCKED, SET_MOB_DROPS, SET_NAME, SET_PAYPAL, SET_PERMISSION, SET_PLAYER_ISLAND, SET_PLAYER_LAST_TIME_UPDATED, SET_PLAYER_MISSION_COMPLETED, SET_PLAYER_ROLE, SET_PLAYER_STATUS, SET_RATING, SET_ROLE_LIMIT, SET_SCHEMATIC, SET_SCHEMATIC_POSITION, SET_SIZE, SET_SPAWNER_RATES, SET_TEAM_CHAT, SET_TEAM_LIMIT, SET_TEXTURE_VALUE, SET_TOGGLED_BORDER, SET_TOGGLED_PANEL, SET_TOGGLED_SCHEMATIC, SET_TOGGLED_STACKER, SET_UPGRADE, SET_VISITOR_HOME, SET_WARPS_LIMIT, SET_WARP_CATEGORY_ICON, SET_WARP_CATEGORY_NAME, SET_WARP_CATEGORY_SLOT, SET_WARP_ICON, SET_WARP_LOCATION, SET_WARP_NAME, SET_WARP_PRIVATE, SORT_ISLANDS, TELEPORT_PLAYER, TRACK_TASK, TRANSFER_ISLAND, UNBAN_PLAYER, UNPURGE_ISLAND, UPDATE_BORDER, VOID_TELEPORT, WITHDRAW_MONEY, SHOW_STACKTRACE, PROFILER; private static String[] DEBUG_NAMES = null; public static String[] getDebugNames() { if (DEBUG_NAMES == null) { Debug[] debugs = Debug.values(); DEBUG_NAMES = new String[debugs.length]; for (int i = 0; i < debugs.length; ++i) DEBUG_NAMES[i] = debugs[i].name().toLowerCase(Locale.ENGLISH); } return DEBUG_NAMES; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/logging/Log.java ================================================ package com.bgsoftware.superiorskyblock.core.logging; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.module.logging.ModuleLoggerFileHandler; import org.slf4j.LoggerFactory; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.util.EnumSet; import java.util.logging.Level; import java.util.logging.Logger; public class Log { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Logger LOGGER = initializeLogger(); private static final EnumSet DEBUG_FILTERS = EnumSet.noneOf(Debug.class); private static boolean debugMode = false; private static Logger initializeLogger() { Logger logger = Logger.getLogger("SuperiorSkyblock2"); logger.setParent(plugin.getLogger()); logger.setUseParentHandlers(true); File logsFolder = new File(plugin.getDataFolder(), "logs"); File archiveLogsFile = new File(logsFolder, "archive"); ModuleLoggerFileHandler.addToLogger(logsFolder, archiveLogsFile, logger); return logger; } private Log() { } public static void info(Object first, Object... parts) { logInternal(Level.INFO, first, parts); } public static void warn(Object first, Object... parts) { logInternal(Level.WARNING, first, parts); } public static void warnFromFile(String fileName, Object first, Object... parts) { logInternalWithFile(Level.WARNING, fileName, first, parts); } public static void error(Object first, Object... parts) { logInternal(Level.SEVERE, first, parts); } public static void error(Throwable error, Object first, Object... parts) { error(first, parts); printStackTrace(error); } public static void errorFromFile(String fileName, Object first, Object... parts) { logInternalWithFile(Level.SEVERE, fileName, first, parts); } public static void errorFromFile(Throwable error, String fileName, Object first, Object... parts) { errorFromFile(fileName, first, parts); printStackTrace(error); } public static void profile(String[] profiledDataLines) { if (!isDebugged(Debug.PROFILER)) return; for (String line : profiledDataLines) logInternal(Level.INFO, line); } public static void debug(Debug debug, Object... params) { if (isDebugged(debug)) { String[] classAndMethod = getClassAndMethodNames(); enteringInternal(Level.INFO, classAndMethod[0], classAndMethod[1], null, params); if (isDebugged(Debug.SHOW_STACKTRACE)) printStackTrace(); } } public static void debugResult(Debug debug, @Nullable String message, Object result) { if (isDebugged(debug)) { String[] classAndMethod = getClassAndMethodNames(); enteringInternal(Level.INFO, classAndMethod[0], classAndMethod[1], message, result); if (isDebugged(Debug.SHOW_STACKTRACE)) printStackTrace(); } } public static void entering(@Nullable String message, Object... params) { String[] classAndMethod = getClassAndMethodNames(); enteringInternal(Level.INFO, classAndMethod[0], classAndMethod[1], message, params); } public static boolean isDebugMode() { return debugMode; } public static boolean isDebugged(Debug debug) { return debugMode && DEBUG_FILTERS.contains(debug); } public static void toggleDebugMode() { debugMode = !debugMode; } public static void setDebugFilter(@Nullable Debug debugFilter) { if (debugFilter == null) { DEBUG_FILTERS.clear(); } else if (DEBUG_FILTERS.contains(debugFilter)) { DEBUG_FILTERS.remove(debugFilter); } else { DEBUG_FILTERS.add(debugFilter); } } private static void enteringInternal(Level level, String clazz, String method, @Nullable String message, Object... params) { StringBuilder paramsMessage = new StringBuilder(); for (Object param : params) paramsMessage.append(" {").append(param).append("}"); logInternal(level, clazz, "::", method, message == null ? "" : " " + message, paramsMessage.toString()); } private static void logInternalWithFile(Level level, String fileName, Object first, Object... parts) { LOGGER.log(level, buildFromPartsWithFile(fileName, first, parts)); } private static void logInternal(Level level, Object first, Object... parts) { LOGGER.log(level, buildFromParts(first, parts)); } private static String buildFromParts(Object first, Object... parts) { StringBuilder builder = new StringBuilder().append(first); for (Object part : parts) builder.append(part); return builder.toString(); } private static String buildFromPartsWithFile(String prefixFile, Object first, Object... parts) { StringBuilder builder = new StringBuilder("[").append(prefixFile).append("] ").append(first); for (Object part : parts) builder.append(part); return builder.toString(); } private static String[] getClassAndMethodNames() { StackTraceElement currentElement = Thread.currentThread().getStackTrace()[3]; String methodName = currentElement.getMethodName(); if (methodName.contains("lambda")) { methodName = methodName.split("\\$")[1]; } String className = currentElement.getClassName(); return new String[]{className.substring(className.lastIndexOf(".") + 1), methodName}; } private static void printStackTrace() { printStackTrace(new Exception("Stack trace")); } private static void printStackTrace(Throwable error) { StringWriter buffer = new StringWriter(); PrintWriter pw = new PrintWriter(buffer); error.printStackTrace(pw); LOGGER.log(Level.SEVERE, buffer.toString()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/logging/StackTrace.java ================================================ package com.bgsoftware.superiorskyblock.core.logging; public class StackTrace { private final StackTraceHolder stackTrace = new StackTraceHolder(); public void dump() { this.stackTrace.printStackTrace(); } private static class StackTraceHolder extends Throwable { @Override public String toString() { return "Original Stacktrace:"; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/AbstractMenu.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.BaseMenu; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.Inventory; import java.util.concurrent.CompletableFuture; public abstract class AbstractMenu, A extends ViewArgs> extends BaseMenu { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); protected AbstractMenu(String identifier, MenuParseResult parseResult) { super(identifier, parseResult.getLayoutBuilder().build(), parseResult.getOpeningSound(), parseResult.isPreviousMoveAllowed(), parseResult.isSkipOneItem()); } @Override public final CompletableFuture createView(SuperiorPlayer superiorPlayer, A args) { return super.createView(superiorPlayer, args); } @Override public final CompletableFuture createView(SuperiorPlayer superiorPlayer, A args, @Nullable MenuView previousMenu) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkState(superiorPlayer.isOnline(), "Cannot create view for offline player: " + superiorPlayer.getName()); Preconditions.checkNotNull(args, "args parameter cannot be null."); V view = createViewInternal(superiorPlayer, args, previousMenu); addView(view); return refreshView(view); } @Override public void onClick(InventoryClickEvent clickEvent, V menuView) { if (!menuView.isRefreshing()) super.onClick(clickEvent, menuView); } @Override protected void onCloseInternal(InventoryCloseEvent closeEvent, V menuView) { menuView.onClose(); } protected abstract V createViewInternal(SuperiorPlayer superiorPlayer, A args, @Nullable MenuView previousMenu); public CompletableFuture refreshView(V view) { CompletableFuture res = new CompletableFuture<>(); buildInventory(view).whenComplete((inventory, error) -> { if (error != null) { res.completeExceptionally(error); } else { BukkitExecutor.sync(() -> { view.setInventory(inventory); res.complete(view); }); } }); return res; } public CompletableFuture buildInventory(V menuView) { if (!Bukkit.isPrimaryThread()) { return CompletableFuture.completedFuture(this.menuLayout.buildInventory(menuView)); } CompletableFuture inventoryFuture = new CompletableFuture<>(); BukkitExecutor.async(() -> inventoryFuture.complete(this.menuLayout.buildInventory(menuView))); return inventoryFuture; } @Override protected void onButtonClickLackPermission(MenuViewButton menuButton, InventoryClickEvent clickEvent) { if (menuButton instanceof AbstractMenuViewButton) ((AbstractMenuViewButton) menuButton).onButtonClickLackPermission(clickEvent); } protected boolean onPreButtonClick(MenuViewButton menuButton, InventoryClickEvent clickEvent) { return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/AbstractPagedMenu.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.superiorskyblock.api.menu.PagedMenu; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.google.common.base.Preconditions; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; public abstract class AbstractPagedMenu, A extends ViewArgs, E> extends AbstractMenu implements PagedMenu { private final boolean acceptNull; protected AbstractPagedMenu(String identifier, MenuParseResult parseResult, boolean acceptNull) { super(identifier, parseResult); Preconditions.checkState(parseResult.getLayoutBuilder() instanceof PagedMenuLayout.Builder, "Paged menu " + identifier + " doesn't use the correct layout."); this.acceptNull = acceptNull; } @Override public boolean onPreButtonClick(MenuViewButton menuButton, InventoryClickEvent clickEvent) { if (!(menuButton instanceof PagedMenuViewButton)) return true; MenuLayout menuLayout = getLayout(); if (!(menuLayout instanceof PagedMenuLayout)) return false; PagedMenuViewButton pagedMenuButton = (PagedMenuViewButton) menuButton; V menuView = menuButton.getView(); menuView.updatePagedObjects(); List pagedObjects = menuView.getPagedObjects(); int objectsPerPage = ((PagedMenuLayout) menuLayout).getObjectsPerPageCount(); int currentPage = menuView.getCurrentPage(); int objectIndex = ((PagedMenuTemplateButton) pagedMenuButton.getTemplate()).getButtonIndex() + (objectsPerPage * (currentPage - 1)); if (objectIndex >= pagedObjects.size()) { if (this.acceptNull) pagedMenuButton.updateObject(null); return this.acceptNull; } pagedMenuButton.updateObject(pagedObjects.get(objectIndex)); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import java.math.BigDecimal; import java.util.Locale; public class MenuActions { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public static void handleDeposit(SuperiorPlayer superiorPlayer, Island island, BankTransaction bankTransaction, @Nullable GameSound successSound, @Nullable GameSound failSound, BigDecimal amount) { if (bankTransaction.getFailureReason().isEmpty()) { superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, successSound)); } else { superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, failSound)); String failureReason = bankTransaction.getFailureReason(); if (!failureReason.isEmpty()) { switch (failureReason) { case "No permission": Message.NO_DEPOSIT_PERMISSION.send(superiorPlayer, island.getRequiredPlayerRole(IslandPrivileges.DEPOSIT_MONEY)); break; case "Invalid amount": Message.INVALID_AMOUNT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); break; case "Not enough money": Message.NOT_ENOUGH_MONEY_TO_DEPOSIT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); break; case "Exceed bank limit": Message.BANK_LIMIT_EXCEED.send(superiorPlayer); break; case "Vault is not installed": Message.VAULT_NOT_INSTALLED.send(superiorPlayer); break; default: Message.DEPOSIT_ERROR.send(superiorPlayer, failureReason); break; } } } } public static void handleWithdraw(SuperiorPlayer superiorPlayer, Island island, BankTransaction bankTransaction, GameSound successSound, GameSound failSound, BigDecimal amount) { if (bankTransaction.getFailureReason().isEmpty()) { superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, successSound)); } else { superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, failSound)); String failureReason = bankTransaction.getFailureReason(); if (!failureReason.isEmpty()) { switch (failureReason) { case "No permission": Message.NO_WITHDRAW_PERMISSION.send(superiorPlayer, island.getRequiredPlayerRole(IslandPrivileges.WITHDRAW_MONEY)); break; case "Invalid amount": Message.INVALID_AMOUNT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); break; case "Bank is empty": Message.ISLAND_BANK_EMPTY.send(superiorPlayer); break; case "Vault is not installed": Message.VAULT_NOT_INSTALLED.send(superiorPlayer); break; default: Message.WITHDRAW_ERROR.send(superiorPlayer, failureReason); break; } } } } public static void simulateIslandCreationClick(SuperiorPlayer clickedPlayer, String islandName, MenuIslandCreationConfig creationConfig, boolean isPreviewMode, @Nullable MenuView menuView) { Schematic schematic = creationConfig.getSchematic(); // Checking for preview of islands. if (isPreviewMode) { Location previewLocation = plugin.getSettings().getIslandPreviews().getLocations().get(schematic.getName().toLowerCase(Locale.ENGLISH)); if (previewLocation != null) { plugin.getGrid().startIslandPreview(clickedPlayer, schematic, islandName); return; } } Player whoClicked = clickedPlayer.asPlayer(); GameSoundImpl.playSound(whoClicked, creationConfig.getSound()); creationConfig.getCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("%player%", clickedPlayer.getName()))); Message.ISLAND_CREATE_PROCCESS_REQUEST.send(clickedPlayer); if (menuView != null) menuView.closeView(); Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); boolean offset = creationConfig.shouldOffsetIslandValue() || plugin.getSettings().getWorlds().getDimensionConfig(dimension).isSchematicOffset(); BlockOffset spawnOffset = creationConfig.getSpawnOffset(); plugin.getGrid().createIsland(clickedPlayer, schematic.getName(), creationConfig.getBonusWorth(), creationConfig.getBonusLevel(), creationConfig.getBiome(), islandName, offset, spawnOffset); } public static void simulateWarpsClick(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) { BukkitExecutor.sync(() -> { superiorPlayer.runIfOnline(player -> { MenuView currentView = superiorPlayer.getOpenedView(); if (currentView == null) { player.closeInventory(); } else { currentView.closeView(); } island.warpPlayer(superiorPlayer, islandWarp.getName()); }); }, 1L); } private MenuActions() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuCommandsImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.MenuCommands; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MenuCommandsImpl implements MenuCommands { private static final MenuCommandsImpl INSTANCE = new MenuCommandsImpl(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; private static final Pattern COMMAND_PATTERN_ARGS = Pattern.compile("\\[(.+)](.+)"); private static final Pattern COMMAND_PATTERN = Pattern.compile("\\[(.+)]"); public static MenuCommandsImpl getInstance() { return INSTANCE; } private MenuCommandsImpl() { } @Override public void runCommand(MenuView menuView, String command, InventoryClickEvent clickEvent) { this.runCommand(menuView, command, clickEvent, Bukkit.getConsoleSender()); } private void runCommand(MenuView menuView, String command, InventoryClickEvent clickEvent, CommandSender sender) { Matcher matcher = COMMAND_PATTERN_ARGS.matcher(command); if (matcher.matches()) { String subCommand = matcher.group(1); String args = matcher.group(2).trim(); handleSubCommand(menuView, subCommand, args, clickEvent, sender); } else if ((matcher = COMMAND_PATTERN.matcher(command)).matches()) { String subCommand = matcher.group(1); handleSubCommand(menuView, subCommand, "", clickEvent, sender); } else if (command.equalsIgnoreCase("close")) { setClickedCloseButton(menuView); menuView.closeView(); } else if (command.equalsIgnoreCase("back")) { setClickedCloseButton(menuView); clickEvent.getWhoClicked().closeInventory(); } else { SuperiorPlayer targetPlayer = menuView instanceof IPlayerMenuView ? ((IPlayerMenuView) menuView).getSuperiorPlayer() : null; if (targetPlayer != null) command = placeholdersService.get().parsePlaceholders(targetPlayer.asOfflinePlayer(), command); else if (sender instanceof Player) command = placeholdersService.get().parsePlaceholders((Player) sender, command); Bukkit.dispatchCommand(sender instanceof Player || command.startsWith("PLAYER:") ? clickEvent.getWhoClicked() : Bukkit.getConsoleSender(), command.replace("PLAYER:", "").replace("%player%", clickEvent.getWhoClicked().getName())); } } private void handleSubCommand(MenuView menuView, String subCommand, String args, InventoryClickEvent clickEvent, CommandSender sender) { switch (subCommand.toLowerCase(Locale.ENGLISH)) { case "player": runCommand(menuView, args, clickEvent, clickEvent.getWhoClicked()); break; case "admin": String commandLabel = plugin.getSettings().getIslandCommand().split(",")[0]; runCommand(menuView, commandLabel + " admin " + args, clickEvent, sender); break; case "close": setClickedCloseButton(menuView); menuView.closeView(); clickEvent.getWhoClicked().closeInventory(); break; case "back": setClickedCloseButton(menuView); clickEvent.getWhoClicked().closeInventory(); break; default: plugin.getCommands().dispatchSubCommand(sender, subCommand, args); break; } } private static void setClickedCloseButton(MenuView menuView) { if (menuView instanceof AbstractMenuView) ((AbstractMenuView) menuView).setClickedCloseButton(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton; import org.bukkit.block.Biome; import java.math.BigDecimal; import java.util.Collection; import java.util.Collections; public class MenuConfig { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private MenuConfig() { } public static class IslandCreation implements MenuIslandCreationConfig { private final Schematic schematic; @Nullable private final IslandCreationButton.Template template; private final Biome biome; public IslandCreation(IslandCreationButton.Template template) { this(template.getSchematic(), template); } public IslandCreation(Schematic schematic, IslandCreationButton.Template template) { this.schematic = schematic; this.template = template; Biome biome = template == null ? null : template.getBiome(); this.biome = biome == null ? plugin.getNMSAlgorithms().getBiome(plugin.getSettings().getWorlds().getDimensionConfig( plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBiome()) : biome; } @Override public Schematic getSchematic() { return this.schematic; } @Override public GameSound getSound() { return this.template == null ? null : this.template.getAccessSound(); } @Override public Collection getCommands() { return this.template == null ? Collections.emptyList() : this.template.getAccessCommands(); } @Override public boolean shouldOffsetIslandValue() { return this.template != null && this.template.isOffset(); } @Override public BlockOffset getSpawnOffset() { return this.template == null ? null : this.template.getSpawnOffset(); } @Override public BigDecimal getBonusWorth() { return this.template == null ? BigDecimal.ZERO : this.template.getBonusWorth(); } @Override public BigDecimal getBonusLevel() { return this.template == null ? BigDecimal.ZERO : this.template.getBonusLevel(); } @Override public Biome getBiome() { return this.biome; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuIdentifiers.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; public class MenuIdentifiers { public static final String MENU_BANK_LOGS = "MenuBankLogs"; public static final String MENU_BIOMES = "MenuBiomes"; public static final String MENU_BLANK = "MenuBlank"; public static final String MENU_BORDER_COLOR = "MenuBorderColor"; public static final String MENU_CONFIG_EDITOR = "MenuConfigEditor"; public static final String MENU_CONFIRM_BAN = "MenuConfirmBan"; public static final String MENU_CONFIRM_DISBAND = "MenuConfirmDisband"; public static final String MENU_CONFIRM_KICK = "MenuConfirmKick"; public static final String MENU_CONFIRM_LEAVE = "MenuConfirmLeave"; public static final String MENU_CONFIRM_TRANSFER = "MenuConfirmTransfer"; public static final String MENU_CONTROL_PANEL = "MenuControlPanel"; public static final String MENU_COOPS = "MenuCoops"; public static final String MENU_COUNTS = "MenuCounts"; public static final String MENU_CUSTOM_PREFIX = "MenuCustom_"; public static final String MENU_GLOBAL_WARPS = "MenuGlobalWarps"; public static final String MENU_ISLAND_BANK = "MenuIslandBank"; public static final String MENU_ISLAND_BANNED_PLAYERS = "MenuIslandBannedPlayers"; public static final String MENU_ISLAND_CHEST = "MenuIslandChest"; public static final String MENU_ISLAND_CREATION = "MenuIslandCreation"; public static final String MENU_ISLAND_FLAGS = "MenuIslandFlags"; public static final String MENU_ISLAND_MEMBERS = "MenuIslandMembers"; public static final String MENU_ISLAND_PRIVILEGES = "MenuIslandPrivileges"; public static final String MENU_ISLAND_RATE = "MenuIslandRate"; public static final String MENU_ISLAND_RATINGS = "MenuIslandRatings"; public static final String MENU_ISLAND_UNIQUE_VISITORS = "MenuUniqueVisitors"; public static final String MENU_ISLAND_UPGRADES = "MenuIslandUpgrades"; public static final String MENU_ISLAND_VALUES = "MenuIslandValues"; public static final String MENU_ISLAND_VISITORS = "MenuIslandVisitors"; public static final String MENU_MEMBER_MANAGE = "MenuMemberManage"; public static final String MENU_MEMBER_ROLE = "MenuMemberRole"; public static final String MENU_MISSIONS = "MenuMissions"; public static final String MENU_MISSIONS_CATEGORY = "MenuMissionsCategory"; public static final String MENU_PLAYER_LANGUAGE = "MenuPlayerLanguage"; public static final String MENU_TOP_ISLANDS = "MenuTopIslands"; public static final String MENU_WARP_CATEGORIES = "MenuWarpCategories"; public static final String MENU_WARP_CATEGORIES_ICON_EDIT = "MenuWarpCategoryIconEdit"; public static final String MENU_WARP_CATEGORIES_MANAGE = "MenuWarpCategoryManage"; public static final String MENU_WARP_ICON_EDIT = "MenuWarpIconEdit"; public static final String MENU_WARP_MANAGE = "MenuWarpManage"; public static final String MENU_WARPS = "MenuWarps"; private MenuIdentifiers() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuParseResult.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.parser.MenuParser; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import org.bukkit.configuration.file.YamlConfiguration; import java.util.List; public class MenuParseResult> implements MenuParser.ParseResult { private final MenuLayout.Builder menuLayoutBuilder; private final GameSound openingSound; private final boolean isPreviousMoveAllowed; private final boolean isSkipOneItem; private final MenuPatternSlots patternSlots; private final YamlConfiguration config; public MenuParseResult(MenuLayout.Builder menuLayoutBuilder) { this(menuLayoutBuilder, null, true, false, null, null); } public MenuParseResult(MenuLayout.Builder menuLayoutBuilder, @Nullable GameSound openingSound, boolean isPreviousMoveAllowed, boolean isSkipOneItem, MenuPatternSlots patternSlots, YamlConfiguration config) { this.menuLayoutBuilder = menuLayoutBuilder; this.openingSound = openingSound; this.isPreviousMoveAllowed = isPreviousMoveAllowed; this.isSkipOneItem = isSkipOneItem; this.patternSlots = patternSlots; this.config = config; } @Override public MenuLayout.Builder getLayoutBuilder() { return menuLayoutBuilder; } @Nullable public GameSound getOpeningSound() { return openingSound; } @Override public boolean isPreviousMoveAllowed() { return isPreviousMoveAllowed; } @Override public boolean isSkipOneItem() { return isSkipOneItem; } @Override public List getSlotsForChar(char ch) { return patternSlots.getSlots(ch); } public MenuPatternSlots getPatternSlots() { return patternSlots; } public YamlConfiguration getConfig() { return config; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuPatternSlots.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Char2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.CharIterator; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class MenuPatternSlots { private final Char2ObjectMapView> charSlots = CollectionsFactory.createChar2ObjectArrayMap(); public MenuPatternSlots() { } public CharIterator getChars() { return this.charSlots.keyIterator(); } public void addSlot(char character, int slot) { this.charSlots.computeIfAbsent(character, ch -> new LinkedList<>()).add(slot); } public List getSlots(char character) { List slots = this.charSlots.get(character); return slots == null ? Collections.emptyList() : slots; } public List getSlots(String str) { for (char ch : str.toCharArray()) { List slots = getSlots(ch); if (!slots.isEmpty()) return slots; } return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/Menus.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuBankLogs; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuBiomes; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuBorderColor; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmBan; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmDisband; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmLeave; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuControlPanel; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuCoops; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuCounts; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuGlobalWarps; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandBank; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandBannedPlayers; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandChest; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandCreation; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandFlags; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandMembers; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandPrivileges; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandRate; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandRatings; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandUniqueVisitors; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandUpgrades; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandValues; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandVisitors; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMemberManage; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMemberRole; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissions; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissionsCategory; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuPlayerLanguage; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategories; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryIconEdit; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpIconEdit; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarps; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuBlank; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuConfigEditor; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; public class Menus { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public static final MenuBlank MENU_BLANK = MenuBlank.createInstance(); public static final MenuConfigEditor MENU_CONFIG_EDITOR = MenuConfigEditor.createInstance(); public static MenuBankLogs MENU_BANK_LOGS; public static MenuBiomes MENU_BIOMES; public static MenuBorderColor MENU_BORDER_COLOR; public static MenuConfirmBan MENU_CONFIRM_BAN; public static MenuConfirmDisband MENU_CONFIRM_DISBAND; public static MenuConfirmKick MENU_CONFIRM_KICK; public static MenuConfirmLeave MENU_CONFIRM_LEAVE; public static MenuConfirmTransfer MENU_CONFIRM_TRANSFER; public static MenuControlPanel MENU_CONTROL_PANEL; public static MenuCoops MENU_COOPS; public static MenuCounts MENU_COUNTS; public static MenuGlobalWarps MENU_GLOBAL_WARPS; public static MenuIslandBank MENU_ISLAND_BANK; public static MenuIslandBannedPlayers MENU_ISLAND_BANNED_PLAYERS; public static MenuIslandChest MENU_ISLAND_CHEST; public static MenuIslandCreation MENU_ISLAND_CREATION; public static MenuIslandFlags MENU_ISLAND_FLAGS; public static MenuIslandMembers MENU_ISLAND_MEMBERS; public static MenuIslandPrivileges MENU_ISLAND_PRIVILEGES; public static MenuIslandRate MENU_ISLAND_RATE; public static MenuIslandRatings MENU_ISLAND_RATINGS; public static MenuIslandUniqueVisitors MENU_ISLAND_UNIQUE_VISITORS; public static MenuIslandUpgrades MENU_ISLAND_UPGRADES; public static MenuIslandValues MENU_ISLAND_VALUES; public static MenuIslandVisitors MENU_ISLAND_VISITORS; public static MenuMemberManage MENU_MEMBER_MANAGE; public static MenuMemberRole MENU_MEMBER_ROLE; public static MenuMissions MENU_MISSIONS; public static MenuMissionsCategory MENU_MISSIONS_CATEGORY; public static MenuPlayerLanguage MENU_PLAYER_LANGUAGE; public static MenuTopIslands MENU_TOP_ISLANDS; public static MenuWarpCategories MENU_WARP_CATEGORIES; public static MenuWarpCategoryIconEdit MENU_WARP_CATEGORY_ICON_EDIT; public static MenuWarpCategoryManage MENU_WARP_CATEGORY_MANAGE; public static MenuWarpIconEdit MENU_WARP_ICON_EDIT; public static MenuWarpManage MENU_WARP_MANAGE; public static MenuWarps MENU_WARPS; private Menus() { } public static void registerMenus() { // We register the internal menus createMenu(MENU_BLANK); createMenu(MENU_CONFIG_EDITOR); // Load menus from files MENU_BANK_LOGS = createMenu(MenuBankLogs.createInstance()); MENU_BIOMES = createMenu(MenuBiomes.createInstance()); MENU_BORDER_COLOR = createMenu(MenuBorderColor.createInstance()); MENU_CONFIRM_BAN = createMenu(MenuConfirmBan.createInstance()); MENU_CONFIRM_DISBAND = createMenu(MenuConfirmDisband.createInstance()); MENU_CONFIRM_KICK = createMenu(MenuConfirmKick.createInstance()); MENU_CONFIRM_LEAVE = createMenu(MenuConfirmLeave.createInstance()); MENU_CONFIRM_TRANSFER = createMenu(MenuConfirmTransfer.createInstance()); MENU_CONTROL_PANEL = createMenu(MenuControlPanel.createInstance()); MENU_COOPS = createMenu(MenuCoops.createInstance()); MENU_COUNTS = createMenu(MenuCounts.createInstance()); MENU_GLOBAL_WARPS = createMenu(MenuGlobalWarps.createInstance()); MENU_ISLAND_BANK = createMenu(MenuIslandBank.createInstance()); MENU_ISLAND_BANNED_PLAYERS = createMenu(MenuIslandBannedPlayers.createInstance()); MENU_ISLAND_CHEST = createMenu(MenuIslandChest.createInstance()); MENU_ISLAND_CREATION = createMenu(MenuIslandCreation.createInstance()); MENU_ISLAND_FLAGS = createMenu(MenuIslandFlags.createInstance()); MENU_ISLAND_MEMBERS = createMenu(MenuIslandMembers.createInstance()); MENU_ISLAND_PRIVILEGES = createMenu(MenuIslandPrivileges.createInstance()); MENU_ISLAND_RATE = createMenu(MenuIslandRate.createInstance()); MENU_ISLAND_RATINGS = createMenu(MenuIslandRatings.createInstance()); MENU_ISLAND_UNIQUE_VISITORS = createMenu(MenuIslandUniqueVisitors.createInstance()); MENU_ISLAND_UPGRADES = createMenu(MenuIslandUpgrades.createInstance()); MENU_ISLAND_VALUES = createMenu(MenuIslandValues.createInstance()); MENU_ISLAND_VISITORS = createMenu(MenuIslandVisitors.createInstance()); MENU_MEMBER_MANAGE = createMenu(MenuMemberManage.createInstance()); MENU_MEMBER_ROLE = createMenu(MenuMemberRole.createInstance()); MENU_MISSIONS = createMenu(MenuMissions.createInstance()); MENU_MISSIONS_CATEGORY = createMenu(MenuMissionsCategory.createInstance()); MENU_PLAYER_LANGUAGE = createMenu(MenuPlayerLanguage.createInstance()); MENU_TOP_ISLANDS = createMenu(MenuTopIslands.createInstance()); MENU_WARP_CATEGORIES = createMenu(MenuWarpCategories.createInstance()); MENU_WARP_CATEGORY_ICON_EDIT = createMenu(MenuWarpCategoryIconEdit.createInstance()); MENU_WARP_CATEGORY_MANAGE = createMenu(MenuWarpCategoryManage.createInstance()); MENU_WARP_ICON_EDIT = createMenu(MenuWarpIconEdit.createInstance()); MENU_WARP_MANAGE = createMenu(MenuWarpManage.createInstance()); MENU_WARPS = createMenu(MenuWarps.createInstance()); } private static , V extends AbstractMenuView, A extends ViewArgs> M createMenu(M menu) { if (menu == null) throw new IllegalStateException("Menu could not be initialized."); plugin.getMenus().registerMenu(menu); return menu; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenusManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.MenusManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.MenuCommands; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.parser.MenuParser; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuCustom; import com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.google.common.base.Preconditions; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; public class MenusManagerImpl extends Manager implements MenusManager { private final Map> registeredMenus = new HashMap<>(); public MenusManagerImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override public void loadData() { plugin.getProviders().getMenusProvider().initializeMenus(); } @Override public void openBankLogs(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openBankLogs(targetPlayer, previousMenu, targetIsland); } @Override public void refreshBankLogs(Island island) { plugin.getProviders().getMenusProvider().refreshBankLogs(island); } @Override public void openBiomes(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openBiomes(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandBiomesMenu(SuperiorPlayer superiorPlayer) { openBiomes(superiorPlayer, null, superiorPlayer.getIsland()); } @Override public void openBorderColor(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { plugin.getProviders().getMenusProvider().openBorderColor(targetPlayer, previousMenu); } @Override public void openBorderColorMenu(SuperiorPlayer superiorPlayer) { openBorderColor(superiorPlayer, null); } @Override public void openConfirmBan(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer bannedPlayer) { plugin.getProviders().getMenusProvider().openConfirmBan(targetPlayer, previousMenu, targetIsland, bannedPlayer); } @Override public void openConfirmDisband(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openConfirmDisband(targetPlayer, previousMenu, targetIsland); } @Override public void openConfirmDisbandMenu(SuperiorPlayer superiorPlayer) { openConfirmDisband(superiorPlayer, null, superiorPlayer.getIsland()); } @Override public void openConfirmKick(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer kickedPlayer) { plugin.getProviders().getMenusProvider().openConfirmKick(targetPlayer, previousMenu, targetIsland, kickedPlayer); } @Override public void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { plugin.getProviders().getMenusProvider().openConfirmLeave(targetPlayer, previousMenu); } @Override public void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner) { plugin.getProviders().getMenusProvider().openConfirmTransfer(targetPlayer, previousMenu, targetIsland, newOwner); } @Override public void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openControlPanel(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandPanelMenu(SuperiorPlayer superiorPlayer) { openControlPanel(superiorPlayer, null, superiorPlayer.getIsland()); } @Override public void openCoops(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openCoops(targetPlayer, previousMenu, targetIsland); } @Override public void refreshCoops(Island island) { plugin.getProviders().getMenusProvider().refreshCoops(island); } @Override public void openCounts(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openCounts(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandCountsMenu(SuperiorPlayer superiorPlayer, Island island) { openCounts(superiorPlayer, null, island); } @Override public void refreshCounts(Island island) { plugin.getProviders().getMenusProvider().refreshCounts(island); } @Override public void openGlobalWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { plugin.getProviders().getMenusProvider().openGlobalWarps(targetPlayer, previousMenu); } @Override public void openGlobalWarpsMenu(SuperiorPlayer superiorPlayer) { openGlobalWarps(superiorPlayer, null); } @Override public void refreshGlobalWarps() { plugin.getProviders().getMenusProvider().refreshGlobalWarps(); } @Override public void openIslandBank(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openIslandBank(targetPlayer, previousMenu, targetIsland); } @Override public void refreshIslandBank(Island island) { plugin.getProviders().getMenusProvider().refreshIslandBank(island); } @Override public void openIslandBannedPlayers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openIslandBannedPlayers(targetPlayer, previousMenu, targetIsland); } @Override public void refreshIslandBannedPlayers(Island island) { plugin.getProviders().getMenusProvider().refreshIslandBannedPlayers(island); } @Override public void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openIslandChest(targetPlayer, previousMenu, targetIsland); } @Override public void refreshIslandChest(Island island) { plugin.getProviders().getMenusProvider().refreshIslandChest(island); } @Override public void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName) { plugin.getProviders().getMenusProvider().openIslandCreation(targetPlayer, previousMenu, islandName); } @Override public void openIslandCreationMenu(SuperiorPlayer superiorPlayer, String islandName) { openIslandCreation(superiorPlayer, null, islandName); } @Override public void openIslandRate(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openIslandRate(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandRateMenu(SuperiorPlayer superiorPlayer, Island island) { openIslandRate(superiorPlayer, null, island); } @Override public void openIslandRatings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openIslandRatings(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandRatingsMenu(SuperiorPlayer superiorPlayer, Island island) { openIslandRatings(superiorPlayer, null, island); } @Override public void refreshIslandRatings(Island island) { plugin.getProviders().getMenusProvider().refreshIslandRatings(island); } @Override public void openMemberManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember) { plugin.getProviders().getMenusProvider().openMemberManage(targetPlayer, previousMenu, islandMember); } @Override public void openMemberManageMenu(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { openMemberManage(superiorPlayer, null, targetPlayer); } @Override public void destroyMemberManage(SuperiorPlayer islandMember) { plugin.getProviders().getMenusProvider().destroyMemberManage(islandMember); } @Override public void openMemberRole(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember) { plugin.getProviders().getMenusProvider().openMemberRole(targetPlayer, previousMenu, islandMember); } @Override public void openMemberRoleMenu(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { openMemberRole(superiorPlayer, null, targetPlayer); } @Override public void destroyMemberRole(SuperiorPlayer islandMember) { plugin.getProviders().getMenusProvider().destroyMemberRole(islandMember); } @Override public void openMembers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openMembers(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandMembersMenu(SuperiorPlayer superiorPlayer, Island island) { openMembers(superiorPlayer, null, island); } @Override public void refreshMembers(Island island) { plugin.getProviders().getMenusProvider().refreshMembers(island); } @Override public void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { plugin.getProviders().getMenusProvider().openMissions(targetPlayer, previousMenu); } @Override public void openIslandMainMissionsMenu(SuperiorPlayer superiorPlayer) { openMissions(superiorPlayer, null); } @Override public void openMissionsCategory(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, MissionCategory missionCategory) { plugin.getProviders().getMenusProvider().openMissionsCategory(targetPlayer, previousMenu, missionCategory); } @Override public void openIslandMissionsMenu(SuperiorPlayer superiorPlayer, boolean islandMissions) { // Menu doesn't exist anymore. } @Override public void refreshMissionsCategory(MissionCategory missionCategory) { plugin.getProviders().getMenusProvider().refreshMissionsCategory(missionCategory); } @Override public void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer permissiblePlayer) { plugin.getProviders().getMenusProvider().openPermissions(targetPlayer, previousMenu, targetIsland, permissiblePlayer); } @Override public void openIslandPermissionsMenu(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) { openPermissions(superiorPlayer, null, island, targetPlayer); } @Override public void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, PlayerRole permissibleRole) { plugin.getProviders().getMenusProvider().openPermissions(targetPlayer, previousMenu, targetIsland, permissibleRole); } @Override public void openIslandPermissionsMenu(SuperiorPlayer superiorPlayer, Island island, PlayerRole playerRole) { openPermissions(superiorPlayer, null, island, playerRole); } @Override public void refreshPermissions(Island island) { plugin.getProviders().getMenusProvider().refreshPermissions(island); } @Override public void refreshPermissions(Island island, SuperiorPlayer permissiblePlayer) { plugin.getProviders().getMenusProvider().refreshPermissions(island, permissiblePlayer); } @Override public void refreshPermissions(Island island, PlayerRole permissibleRole) { plugin.getProviders().getMenusProvider().refreshPermissions(island, permissibleRole); } @Override public void updatePermission(IslandPrivilege islandPrivilege) { plugin.getProviders().getMenusProvider().updatePermission(islandPrivilege); } @Override public void openPlayerLanguage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { plugin.getProviders().getMenusProvider().openPlayerLanguage(targetPlayer, previousMenu); } @Override public void openPlayerLanguageMenu(SuperiorPlayer superiorPlayer) { openPlayerLanguage(superiorPlayer, null); } @Override public void openSettings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openSettings(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandSettingsMenu(SuperiorPlayer superiorPlayer, Island island) { openSettings(superiorPlayer, null, island); } @Override public void refreshSettings(Island island) { plugin.getProviders().getMenusProvider().refreshSettings(island); } @Override public void updateSettings(IslandFlag islandFlag) { plugin.getProviders().getMenusProvider().updateSettings(islandFlag); } @Override public void openTopIslands(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SortingType sortingType) { plugin.getProviders().getMenusProvider().openTopIslands(targetPlayer, previousMenu, sortingType); } @Override public void openIslandsTopMenu(SuperiorPlayer superiorPlayer, SortingType sortingType) { openTopIslands(superiorPlayer, null, sortingType); } @Override public void refreshTopIslands(SortingType sortingType) { plugin.getProviders().getMenusProvider().refreshTopIslands(sortingType); } @Override public void openUniqueVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openUniqueVisitors(targetPlayer, previousMenu, targetIsland); } @Override public void openUniqueVisitorsMenu(SuperiorPlayer superiorPlayer, Island island) { openUniqueVisitors(superiorPlayer, null, island); } @Override public void refreshUniqueVisitors(Island island) { plugin.getProviders().getMenusProvider().refreshUniqueVisitors(island); } @Override public void openUpgrades(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openUpgrades(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandUpgradeMenu(SuperiorPlayer superiorPlayer, Island island) { openUpgrades(superiorPlayer, null, island); } @Override public void refreshUpgrades(Island island) { plugin.getProviders().getMenusProvider().refreshUpgrades(island); } @Override public void openValues(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openValues(targetPlayer, previousMenu, targetIsland); } @Override public void openIslandValuesMenu(SuperiorPlayer superiorPlayer, Island island) { openValues(superiorPlayer, null, island); } @Override public void refreshValues(Island island) { plugin.getProviders().getMenusProvider().refreshValues(island); } @Override public void openVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openVisitors(targetPlayer, previousMenu, targetIsland); } @Override public void refreshVisitors(Island island) { plugin.getProviders().getMenusProvider().refreshVisitors(island); } @Override public void openIslandVisitorsMenu(SuperiorPlayer superiorPlayer, Island island) { openVisitors(superiorPlayer, null, island); } @Override public void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openWarpCategories(targetPlayer, previousMenu, targetIsland); } @Override public void refreshWarpCategories(Island island) { plugin.getProviders().getMenusProvider().refreshWarpCategories(island); } @Override public void destroyWarpCategories(Island island) { plugin.getProviders().getMenusProvider().destroyWarpCategories(island); } @Override public void openWarpCategoryIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) { plugin.getProviders().getMenusProvider().openWarpCategoryIconEdit(targetPlayer, previousMenu, targetCategory); } @Override public void openWarpCategoryManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) { plugin.getProviders().getMenusProvider().openWarpCategoryManage(targetPlayer, previousMenu, targetCategory); } @Override public void refreshWarpCategoryManage(WarpCategory warpCategory) { plugin.getProviders().getMenusProvider().refreshWarpCategoryManage(warpCategory); } @Override public void openWarpIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp) { plugin.getProviders().getMenusProvider().openWarpIconEdit(targetPlayer, previousMenu, targetWarp); } @Override public void openWarpManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp) { plugin.getProviders().getMenusProvider().openWarpManage(targetPlayer, previousMenu, targetWarp); } @Override public void refreshWarpManage(IslandWarp islandWarp) { plugin.getProviders().getMenusProvider().refreshWarpManage(islandWarp); } @Override public void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) { plugin.getProviders().getMenusProvider().openWarps(targetPlayer, previousMenu, targetCategory); } @Override public void openIslandWarpsMenu(SuperiorPlayer superiorPlayer, Island island) { openWarps(superiorPlayer, null, island.getWarpCategories().values() .stream().findFirst().orElseGet(() -> island.createWarpCategory("Default Category"))); } @Override public void refreshWarps(WarpCategory warpCategory) { plugin.getProviders().getMenusProvider().refreshWarps(warpCategory); } @Override public void destroyWarps(WarpCategory warpCategory) { plugin.getProviders().getMenusProvider().destroyWarps(warpCategory); } @Override public void registerMenu(Menu menu) { Preconditions.checkNotNull(menu, "menu parameter cannot be null"); Preconditions.checkState(getMenu(menu.getIdentifier()) == null, "There is already a menu with a similar identifier: " + menu.getIdentifier()); this.registeredMenus.put(menu.getIdentifier().toLowerCase(Locale.ENGLISH), menu); } public void unregisterMenus() { this.registeredMenus.clear(); } @Nullable @Override public , A extends ViewArgs> Menu getMenu(String identifier) { Preconditions.checkNotNull(identifier, "identifier parameter cannot be null"); return (Menu) this.registeredMenus.get(identifier.toLowerCase(Locale.ENGLISH)); } @Override public Map> getMenus() { return Collections.unmodifiableMap(this.registeredMenus); } @Override public Map> getCustomMenus() { Map> customMenus = new LinkedHashMap<>(); this.registeredMenus.forEach((menuName, menu) -> { if (menu instanceof MenuCustom) customMenus.put(menuName, menu); }); return customMenus.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(customMenus); } @Override public > MenuLayout.Builder createPatternBuilder() { return RegularMenuLayoutImpl.newBuilder(); } @Override public , E> PagedMenuLayout.Builder createPagedPatternBuilder() { return PagedMenuLayoutImpl.newBuilder(); } @Override public > MenuTemplateButton.Builder createButtonBuilder( Class viewButtonType, MenuTemplateButton.MenuViewButtonCreator viewButtonCreator) { return AbstractMenuTemplateButton.newBuilder(viewButtonType, viewButtonCreator); } @Override public , E> PagedMenuTemplateButton.Builder createPagedButtonBuilder( Class viewButtonType, PagedMenuTemplateButton.PagedMenuViewButtonCreator viewButtonCreator) { return PagedMenuTemplateButtonImpl.newBuilder(viewButtonType, viewButtonCreator); } @Override public MenuParser getParser() { return MenuParserImpl.getInstance(); } @Override public MenuCommands getMenuCommands() { return MenuCommandsImpl.getInstance(); } @Override @Deprecated public ISuperiorMenu getOldMenuFromView(MenuView menuView) { return MenuViewWrapper.fromView(menuView); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/TemplateItem.java ================================================ package com.bgsoftware.superiorskyblock.core.menu; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; public class TemplateItem { public static final TemplateItem AIR = new TemplateItem(new ItemBuilder(Material.AIR)); private final ItemBuilder itemBuilder; public TemplateItem(ItemBuilder itemBuilder) { this.itemBuilder = itemBuilder; } public ItemBuilder getBuilder() { return itemBuilder.copy(); } public ItemBuilder getEditableBuilder() { return itemBuilder; } public ItemStack build() { return getBuilder().build(); } public ItemStack build(SuperiorPlayer superiorPlayer) { return getBuilder().build(superiorPlayer); } public TemplateItem copy() { return new TemplateItem(this.itemBuilder.copy()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/AbstractMenuTemplateButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.List; public abstract class AbstractMenuTemplateButton> implements MenuTemplateButton { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final TemplateItem buttonItem; private final GameSound clickSound; private final List commands; private final String requiredPermission; private final GameSound lackPermissionSound; private final Class viewButtonType; public AbstractMenuTemplateButton(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Class viewButtonType) { this.buttonItem = buttonItem; this.clickSound = clickSound; this.commands = commands == null ? Collections.emptyList() : Collections.unmodifiableList(commands); this.requiredPermission = requiredPermission; this.lackPermissionSound = lackPermissionSound; this.viewButtonType = viewButtonType; } @Nullable @Override public ItemStack getButtonItem() { return this.buttonItem == null ? null : this.buttonItem.getBuilder().build(); } @Nullable public TemplateItem getButtonTemplateItem() { return buttonItem; } @Nullable @Override public GameSound getClickSound() { return this.clickSound; } @Override public List getClickCommands() { return this.commands; } @Nullable @Override public String getRequiredPermission() { return this.requiredPermission; } @Nullable @Override public GameSound getLackPermissionSound() { return this.lackPermissionSound; } @Override public Class getViewButtonType() { return this.viewButtonType; } protected > B ensureCorrectType(B button) { if (!getViewButtonType().isInstance(button)) throw new IllegalStateException("Menu template " + getClass().getSimpleName() + " expected view button of type " + getViewButtonType().getSimpleName() + ", got " + button.getClass()); return button; } public > B applyToBuilder(B buttonBuilder) { if (((AbstractBuilder) buttonBuilder).buttonItem == null) ((AbstractBuilder) buttonBuilder).buttonItem = this.buttonItem; if (this.clickSound != null) buttonBuilder.setClickSound(this.clickSound); if (this.commands != null && !this.commands.isEmpty()) buttonBuilder.setClickCommands(this.commands); if (!Text.isBlank(this.requiredPermission)) buttonBuilder.setRequiredPermission(this.requiredPermission); if (this.lackPermissionSound != null) buttonBuilder.setLackPermissionsSound(this.lackPermissionSound); return buttonBuilder; } public static > AbstractBuilder newBuilder(Class viewButtonType, MenuViewButtonCreator viewButtonCreator) { return new AbstractBuilder() { @Override public MenuTemplateButton build() { return new AbstractMenuTemplateButton(this.buttonItem, this.clickSound, this.commands, this.requiredPermission, this.lackPermissionSound, viewButtonType) { @Override public MenuViewButton createViewButton(V menuView) { return ensureCorrectType(viewButtonCreator.create(this, menuView)); } }; } }; } public static abstract class AbstractBuilder> implements MenuTemplateButton.Builder { protected TemplateItem buttonItem = null; protected GameSound clickSound = null; protected List commands = null; protected String requiredPermission = null; protected GameSound lackPermissionSound = null; public Builder setButtonItem(ItemStack buttonItem) { return this.setButtonItem(new TemplateItem(new ItemBuilder(buttonItem))); } public Builder setButtonItem(TemplateItem buttonItem) { this.buttonItem = buttonItem; return this; } public Builder setClickSound(GameSound clickSound) { this.clickSound = clickSound; return this; } public Builder setClickCommands(List commands) { this.commands = commands; return this; } public Builder setRequiredPermission(String requiredPermission) { this.requiredPermission = requiredPermission; return this; } public Builder setLackPermissionsSound(GameSound lackPermissionSound) { this.lackPermissionSound = lackPermissionSound; return this; } public abstract MenuTemplateButton build(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/AbstractMenuViewButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public abstract class AbstractMenuViewButton> implements MenuViewButton { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); protected final V menuView; private final AbstractMenuTemplateButton templateButton; protected AbstractMenuViewButton(MenuTemplateButton templateButton, V menuView) { this.templateButton = (AbstractMenuTemplateButton) templateButton; this.menuView = menuView; } @Override public MenuTemplateButton getTemplate() { return this.templateButton; } @Override public V getView() { return this.menuView; } @Override public ItemStack createViewItem() { TemplateItem templateItem = this.templateButton.getButtonTemplateItem(); return templateItem == null ? null : templateItem.getBuilder().build(menuView.getInventoryViewer()); } @Override public abstract void onButtonClick(InventoryClickEvent clickEvent); public void onButtonClickLackPermission(InventoryClickEvent clickEvent) { GameSoundImpl.playSound(clickEvent.getWhoClicked(), this.templateButton.getLackPermissionSound()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/AbstractPagedMenuButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import org.bukkit.inventory.ItemStack; public abstract class AbstractPagedMenuButton, E> extends AbstractMenuViewButton implements PagedMenuViewButton { protected E pagedObject = null; protected AbstractPagedMenuButton(MenuTemplateButton templateButton, V menuView) { super(templateButton, menuView); } @Override public void updateObject(E pagedObject) { this.pagedObject = pagedObject; } @Override public E getPagedObject() { return pagedObject; } @Override public final ItemStack createViewItem() { return modifyViewItem(super.createViewItem()); } public abstract ItemStack modifyViewItem(ItemStack buttonItem); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/MenuTemplateButtonImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import java.util.List; public class MenuTemplateButtonImpl> extends AbstractMenuTemplateButton implements MenuTemplateButton { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final ViewButtonCreator viewButtonCreator; public MenuTemplateButtonImpl(TemplateItem buttonItem, GameSound clickSound, List commands, String requiredPermission, GameSound lackPermissionSound, Class viewButtonType, ViewButtonCreator viewButtonCreator) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, viewButtonType); this.viewButtonCreator = viewButtonCreator; } @Override public MenuViewButton createViewButton(V menuView) { return ensureCorrectType(this.viewButtonCreator.create(this, menuView)); } public interface ViewButtonCreator> { MenuViewButton create(AbstractMenuTemplateButton templateButton, V menuView); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/PagedMenuTemplateButtonImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.google.common.base.Preconditions; import org.bukkit.inventory.ItemStack; import java.util.List; public class PagedMenuTemplateButtonImpl, E> extends AbstractMenuTemplateButton implements PagedMenuTemplateButton { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final TemplateItem nullItem; private final PagedMenuViewButtonCreator viewButtonCreator; private int buttonIndex; public PagedMenuTemplateButtonImpl(TemplateItem buttonItem, GameSound clickSound, List commands, String requiredPermission, GameSound lackPermissionSound, TemplateItem nullItem, int buttonIndex, Class viewButtonType, PagedMenuViewButtonCreator viewButtonCreator) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, viewButtonType); this.nullItem = nullItem; this.buttonIndex = buttonIndex; this.viewButtonCreator = viewButtonCreator; } @Override public ItemStack getNullItem() { return this.nullItem == null ? null : this.nullItem.getBuilder().build(); } public TemplateItem getNullTemplateItem() { return this.nullItem; } @Override public int getButtonIndex() { return this.buttonIndex; } @Override public void setButtonIndex(int buttonIndex) { Preconditions.checkArgument(buttonIndex >= 0, "buttonIndex cannot be negative."); this.buttonIndex = buttonIndex; } @Override public PagedMenuViewButton createViewButton(V menuView) { return ensureCorrectType(this.viewButtonCreator.create(this, menuView)); } public static , E> AbstractBuilder newBuilder(Class viewButtonType, PagedMenuViewButtonCreator viewButtonCreator) { return new AbstractBuilder() { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(this.buttonItem, this.clickSound, this.commands, this.requiredPermission, this.lackPermissionSound, this.nullItem, getButtonIndex(), viewButtonType, viewButtonCreator); } }; } public static abstract class AbstractBuilder, E> extends AbstractMenuTemplateButton.AbstractBuilder implements PagedMenuTemplateButton.Builder { private int buttonIndex = 0; protected TemplateItem nullItem = null; @Override public AbstractBuilder setNullItem(ItemStack nullItem) { return this.setNullItem(new TemplateItem(new ItemBuilder(nullItem))); } public AbstractBuilder setNullItem(TemplateItem nullItem) { this.nullItem = nullItem; return this; } protected int getButtonIndex() { return buttonIndex++; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BackButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import org.bukkit.event.inventory.InventoryClickEvent; public class BackButton, E> extends AbstractMenuViewButton { private BackButton(AbstractMenuTemplateButton templateButton, V menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { // Dummy button } public static class Builder, E> extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, BackButton.class, BackButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BanButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmBan; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; public class BanButton extends AbstractMenuViewButton { private BanButton(AbstractMenuTemplateButton templateButton, MenuConfirmBan.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); if (getTemplate().banPlayer) IslandUtils.handleBanPlayer(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer()); BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private boolean banPlayer; public Builder setBanPlayer(boolean banPlayer) { this.banPlayer = banPlayer; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, banPlayer); } } public static class Template extends MenuTemplateButtonImpl { private final boolean banPlayer; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean banPlayer) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, BanButton.class, BanButton::new); this.banPlayer = banPlayer; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankBalanceButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.Date; public class BankBalanceButton extends AbstractMenuViewButton { private BankBalanceButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public ItemStack createViewItem() { Island island = menuView.getInventoryViewer().getIsland(); SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); ItemStack buttonItem = super.createViewItem(); return new ItemBuilder(buttonItem) .replaceAll("{0}", island.getIslandBank().getBalance() + "") .replaceAll("{1}", Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance())) .replaceAll("{2}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandBank().getBalance(), inventoryViewer.getUserLocale())) .replaceAll("{3}", island.getBankLimit() + "") .replaceAll("{4}", Formatters.NUMBER_FORMATTER.format(island.getBankLimit())) .replaceAll("{5}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimit(), inventoryViewer.getUserLocale())) .replaceAll("{6}", Formatters.DATE_FORMATTER.format(new Date(island.getLastInterestTime() * 1000L))) .replaceAll("{7}", Formatters.DATE_FORMATTER.format(new Date(System.currentTimeMillis() + island.getNextInterest() * 1000L))) .build(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { // Dummy button } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, BankBalanceButton.class, BankBalanceButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.math.BigDecimal; import java.util.List; public class BankCustomDepositButton extends AbstractMenuViewButton { private BankCustomDepositButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(player); Island island = menuView.getIsland(); Message.BANK_DEPOSIT_CUSTOM.send(clickedPlayer); menuView.closeView(); PlayerChat.listen(player, message -> { try { BigDecimal newAmount = BigDecimal.valueOf(Double.parseDouble(message)); BankTransaction bankTransaction = island.getIslandBank().depositMoney(clickedPlayer, newAmount); MenuActions.handleDeposit(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, newAmount); } catch (IllegalArgumentException ex) { Message.INVALID_AMOUNT.send(clickedPlayer, message); } PlayerChat.remove(player); return true; }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private GameSound failSound; private GameSound successSound; public Builder setSuccessSound(GameSound successSound) { this.successSound = successSound; return this; } public Builder setFailSound(GameSound failSound) { this.failSound = failSound; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, successSound, failSound); } } public static class Template extends MenuTemplateButtonImpl { @Nullable private final GameSound successSound; @Nullable private final GameSound failSound; Template(@Nullable TemplateItem buttonItem, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, @Nullable GameSound successSound, @Nullable GameSound failSound) { super(buttonItem, null, commands, requiredPermission, lackPermissionSound, BankCustomDepositButton.class, BankCustomDepositButton::new); this.successSound = successSound; this.failSound = failSound; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.math.BigDecimal; import java.util.List; public class BankCustomWithdrawButton extends AbstractMenuViewButton { private BankCustomWithdrawButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(player); Island island = menuView.getIsland(); Message.BANK_WITHDRAW_CUSTOM.send(clickedPlayer); menuView.closeView(); PlayerChat.listen(player, message -> { try { BigDecimal newAmount = BigDecimal.valueOf(Double.parseDouble(message)); BankTransaction bankTransaction = island.getIslandBank().withdrawMoney(clickedPlayer, newAmount, null); MenuActions.handleWithdraw(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, newAmount); } catch (IllegalArgumentException ex) { Message.INVALID_AMOUNT.send(clickedPlayer, message); } PlayerChat.remove(player); return true; }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private GameSound successSound; private GameSound failSound; public Builder setSuccessSound(GameSound successSound) { this.successSound = successSound; return this; } public Builder setFailSound(GameSound failSound) { this.failSound = failSound; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, successSound, failSound); } } public static class Template extends MenuTemplateButtonImpl { @Nullable private final GameSound successSound; @Nullable private final GameSound failSound; Template(@Nullable TemplateItem buttonItem, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, @Nullable GameSound successSound, @Nullable GameSound failSound) { super(buttonItem, null, commands, requiredPermission, lackPermissionSound, BankCustomWithdrawButton.class, BankCustomWithdrawButton::new); this.successSound = successSound; this.failSound = failSound; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import org.bukkit.event.inventory.InventoryClickEvent; import java.math.BigDecimal; import java.util.List; public class BankDepositButton extends AbstractMenuViewButton { private BankDepositButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); Island island = menuView.getIsland(); BigDecimal amount = plugin.getProviders().getBankEconomyProvider().getBalance(clickedPlayer) .multiply(getTemplate().depositPercentage); BankTransaction bankTransaction = island.getIslandBank().depositMoney(clickedPlayer, amount); MenuActions.handleDeposit(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, amount); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private final double depositPercentage; private GameSound successSound; private GameSound failSound; public Builder(double depositPercentage) { this.depositPercentage = depositPercentage; } public Builder setSuccessSound(GameSound successSound) { this.successSound = successSound; return this; } public Builder setFailSound(GameSound failSound) { this.failSound = failSound; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, successSound, failSound, depositPercentage); } } public static class Template extends MenuTemplateButtonImpl { @Nullable private final GameSound successSound; @Nullable private final GameSound failSound; private final BigDecimal depositPercentage; Template(@Nullable TemplateItem buttonItem, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, @Nullable GameSound successSound, @Nullable GameSound failSound, double depositPercentage) { super(buttonItem, null, commands, requiredPermission, lackPermissionSound, BankDepositButton.class, BankDepositButton::new); this.successSound = successSound; this.failSound = failSound; this.depositPercentage = BigDecimal.valueOf(depositPercentage / 100D); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankLogsPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.enums.BankAction; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuBankLogs; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.UUID; public class BankLogsPagedObjectButton extends AbstractPagedMenuButton { private static final UUID CONSOLE_UUID = new UUID(0, 0); private BankLogsPagedObjectButton(MenuTemplateButton templateButton, MenuBankLogs.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { menuView.setFilteredPlayer(pagedObject.getPlayer()); menuView.refreshView(); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); return new ItemBuilder(buttonItem) .replaceAll("{0}", pagedObject.getPosition() + "") .replaceAll("{1}", getFilteredPlayerName(pagedObject.getPlayer() == null ? CONSOLE_UUID : pagedObject.getPlayer())) .replaceAll("{2}", (pagedObject.getAction() == BankAction.WITHDRAW_COMPLETED ? Message.BANK_WITHDRAW_COMPLETED : Message.BANK_DEPOSIT_COMPLETED).getMessage(inventoryViewer.getUserLocale())) .replaceAll("{3}", pagedObject.getDate()) .replaceAll("{4}", pagedObject.getAmount() + "") .replaceAll("{5}", Formatters.NUMBER_FORMATTER.format(pagedObject.getAmount())) .replaceAll("{6}", Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getAmount(), inventoryViewer.getUserLocale())) .asSkullOf(inventoryViewer) .build(inventoryViewer); } private static String getFilteredPlayerName(UUID filteredPlayer) { if (filteredPlayer == null) { return ""; } else if (filteredPlayer.equals(CONSOLE_UUID)) { return "Console"; } else { return plugin.getPlayers().getSuperiorPlayer(filteredPlayer).getName(); } } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), BankLogsPagedObjectButton.class, BankLogsPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankLogsSortButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuBankLogs; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.Comparator; import java.util.List; import java.util.Objects; public class BankLogsSortButton extends AbstractMenuViewButton { private BankLogsSortButton(AbstractMenuTemplateButton templateButton, MenuBankLogs.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { getTemplate().sortType.onButtonClick(clickEvent, menuView); menuView.refreshView(); } public enum SortType { TIME { @Override void onButtonClick(InventoryClickEvent clickEvent, MenuBankLogs.View menuView) { menuView.setSorting(Comparator.comparingLong(BankTransaction::getTime)); } }, MONEY { @Override void onButtonClick(InventoryClickEvent clickEvent, MenuBankLogs.View menuView) { menuView.setSorting((o1, o2) -> o2.getAmount().compareTo(o1.getAmount())); } }; SortType() { } abstract void onButtonClick(InventoryClickEvent clickEvent, MenuBankLogs.View menuView); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private SortType sortType; public Builder setSortType(SortType sortType) { this.sortType = sortType; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, sortType); } } public static class Template extends MenuTemplateButtonImpl { private final SortType sortType; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, SortType sortType) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, BankLogsSortButton.class, BankLogsSortButton::new); this.sortType = Objects.requireNonNull(sortType, "sortType cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import org.bukkit.event.inventory.InventoryClickEvent; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class BankWithdrawButton extends AbstractMenuViewButton { private BankWithdrawButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); Island island = menuView.getIsland(); BigDecimal amount = island.getIslandBank().getBalance() .multiply(getTemplate().withdrawValue); BankTransaction bankTransaction = island.getIslandBank().withdrawMoney(clickedPlayer, amount, getTemplate().withdrawCommands); MenuActions.handleWithdraw(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, amount); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private final double withdrawValue; private final List withdrawCommands; private GameSound successSound; private GameSound failSound; public Builder(double withdrawValue) { this.withdrawValue = withdrawValue; this.withdrawCommands = null; } public Builder(List withdrawCommands) { this.withdrawValue = 100D; this.withdrawCommands = withdrawCommands; } public BankWithdrawButton.Builder setSuccessSound(GameSound successSound) { this.successSound = successSound; return this; } public BankWithdrawButton.Builder setFailSound(GameSound failSound) { this.failSound = failSound; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, successSound, failSound, withdrawValue, withdrawCommands); } } public static class Template extends MenuTemplateButtonImpl { @Nullable private final GameSound successSound; @Nullable private final GameSound failSound; private final BigDecimal withdrawValue; private final List withdrawCommands; Template(@Nullable TemplateItem buttonItem, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, @Nullable GameSound successSound, @Nullable GameSound failSound, double withdrawValue, @Nullable List withdrawCommands) { super(buttonItem, null, commands, requiredPermission, lackPermissionSound, BankWithdrawButton.class, BankWithdrawButton::new); this.successSound = successSound; this.failSound = failSound; this.withdrawValue = BigDecimal.valueOf(withdrawValue / 100D); this.withdrawCommands = withdrawCommands == null ? Collections.emptyList() : withdrawCommands; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BannedPlayersPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandBannedPlayers; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class BannedPlayersPagedObjectButton extends AbstractPagedMenuButton { private BannedPlayersPagedObjectButton(MenuTemplateButton templateButton, MenuIslandBannedPlayers.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "unban", pagedObject.getName()); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { return new ItemBuilder(buttonItem) .replaceAll("{0}", pagedObject.getName()) .replaceAll("{1}", pagedObject.getPlayerRole() + "") .asSkullOf(pagedObject) .build(pagedObject); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), BannedPlayersPagedObjectButton.class, BannedPlayersPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.Bukkit; import org.bukkit.block.Biome; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.List; import java.util.Objects; public class BiomeButton extends AbstractMenuViewButton { private BiomeButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Nullable @Override public ItemStack createViewItem() { ItemStack buttonItem = null; SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); String requiredPermission = getTemplate().getRequiredPermission(); if (requiredPermission == null || inventoryViewer.hasPermission(requiredPermission)) { buttonItem = super.createViewItem(); } else if (getTemplate().lackPermissionItem != null) { buttonItem = getTemplate().lackPermissionItem.build(inventoryViewer); } if (buttonItem == null || !Menus.MENU_BIOMES.isCurrentBiomeGlow()) return buttonItem; Island island = inventoryViewer.getIsland(); if (island == null || island.getBiome() != getTemplate().biome) return buttonItem; return new ItemBuilder(buttonItem) .makeItemGlow() .build(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Player player = inventoryViewer.asPlayer(); PluginEvent event = PluginEventsFactory.callIslandBiomeChangeEvent( menuView.getIsland(), inventoryViewer, getTemplate().biome); if (event.isCancelled()) { GameSoundImpl.playSound(player, getTemplate().getLackPermissionSound()); return; } GameSoundImpl.playSound(player, getTemplate().accessSound); getTemplate().accessCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("%player%", inventoryViewer.getName()))); menuView.getIsland().setBiome(event.getArgs().biome); Message.CHANGED_BIOME.send(inventoryViewer, Formatters.CAPITALIZED_FORMATTER.format(event.getArgs().biome.name())); BukkitExecutor.sync(menuView::closeView, 1L); } @Override public void onButtonClickLackPermission(InventoryClickEvent clickEvent) { super.onButtonClickLackPermission(clickEvent); getTemplate().lackPermissionCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("%player%", menuView.getInventoryViewer().getName()))); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private final Biome biome; private TemplateItem noAccessItem = null; private List noAccessCommands = null; public Builder(Biome biome) { this.biome = biome; } public void setAccessItem(TemplateItem accessItem) { this.buttonItem = accessItem; } public void setNoAccessItem(TemplateItem noAccessItem) { this.noAccessItem = noAccessItem; } public void setAccessSound(GameSound accessSound) { this.clickSound = accessSound; } public void setNoAccessSound(GameSound noAccessSound) { this.lackPermissionSound = noAccessSound; } public void setAccessCommands(List accessCommands) { this.commands = accessCommands; } public void setNoAccessCommands(List noAccessCommands) { this.noAccessCommands = noAccessCommands; } @Override public MenuTemplateButton build() { return new Template(buttonItem, requiredPermission, lackPermissionSound, clickSound, commands, noAccessItem, noAccessCommands, biome); } } public static class Template extends MenuTemplateButtonImpl { @Nullable private final GameSound accessSound; private final List accessCommands; @Nullable private final TemplateItem lackPermissionItem; private final List lackPermissionCommands; private final Biome biome; Template(@Nullable TemplateItem buttonItem, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, @Nullable GameSound accessSound, @Nullable List accessCommands, @Nullable TemplateItem lackPermissionItem, @Nullable List lackPermissionCommands, Biome biome) { super(buttonItem, null, null, requiredPermission, lackPermissionSound, BiomeButton.class, BiomeButton::new); this.accessSound = accessSound; this.accessCommands = accessCommands == null ? Collections.emptyList() : accessCommands; this.lackPermissionItem = lackPermissionItem; this.lackPermissionCommands = lackPermissionCommands == null ? Collections.emptyList() : lackPermissionCommands; this.biome = Objects.requireNonNull(biome, "biome cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BorderColorButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; public class BorderColorButton extends AbstractMenuViewButton { private BorderColorButton(AbstractMenuTemplateButton templateButton, BaseMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { if (IslandUtils.handleBorderColorUpdate(menuView.getInventoryViewer(), getTemplate().borderColor)) BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private BorderColor borderColor; public Builder setBorderColor(BorderColor borderColor) { this.borderColor = borderColor; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, borderColor); } } public static class Template extends MenuTemplateButtonImpl { private final BorderColor borderColor; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, BorderColor borderColor) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, BorderColorButton.class, BorderColorButton::new); this.borderColor = Objects.requireNonNull(borderColor, "borderColor cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BorderColorToggleButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.List; public class BorderColorToggleButton extends AbstractMenuViewButton { private BorderColorToggleButton(AbstractMenuTemplateButton templateButton, BaseMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public ItemStack createViewItem() { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); TemplateItem buttonItem = inventoryViewer.hasWorldBorderEnabled() ? getTemplate().enabledItem : getTemplate().disabledItem; return buttonItem.build(inventoryViewer); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "toggle", "border"); BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private TemplateItem disabledItem; public Builder setEnabledItem(TemplateItem enabledItem) { this.buttonItem = enabledItem; return this; } public Builder setDisabledItem(TemplateItem disabledItem) { this.disabledItem = disabledItem; return this; } @Override public MenuTemplateButton build() { return new Template(clickSound, commands, requiredPermission, lackPermissionSound, buttonItem, disabledItem); } } public static class Template extends MenuTemplateButtonImpl { private final TemplateItem enabledItem; private final TemplateItem disabledItem; Template(@Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, @Nullable TemplateItem enabledItem, @Nullable TemplateItem disabledItem) { super(null, clickSound, commands, requiredPermission, lackPermissionSound, BorderColorToggleButton.class, BorderColorToggleButton::new); this.enabledItem = enabledItem == null ? TemplateItem.AIR : enabledItem; this.disabledItem = disabledItem == null ? TemplateItem.AIR : disabledItem; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ChangeSortingTypeButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.List; import java.util.Objects; public class ChangeSortingTypeButton extends AbstractMenuViewButton { private ChangeSortingTypeButton(AbstractMenuTemplateButton templateButton, MenuTopIslands.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public ItemStack createViewItem() { ItemStack buttonItem = super.createViewItem(); if (buttonItem == null || !Menus.MENU_TOP_ISLANDS.isSortGlowWhenSelected() || menuView.getSortingType() != getTemplate().sortingType) return buttonItem; return new ItemBuilder(buttonItem) .makeItemGlow() .build(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SortingType sortingType = getTemplate().sortingType; if (menuView.getSortingType() == sortingType) return; boolean notSortedAlready = menuView.setSortingType(sortingType); if (notSortedAlready) { plugin.getGrid().sortIslands(sortingType, menuView::refreshView); } else { menuView.refreshView(); } } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private SortingType sortingType; public Builder setSortingType(SortingType sortingType) { this.sortingType = sortingType; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, sortingType); } } public static class Template extends MenuTemplateButtonImpl { private final SortingType sortingType; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, SortingType sortingType) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, ChangeSortingTypeButton.class, ChangeSortingTypeButton::new); this.sortingType = Objects.requireNonNull(sortingType, "sortingType cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ConfigEditorPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuConfigEditor; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.List; public class ConfigEditorPagedObjectButton extends AbstractPagedMenuButton { private ConfigEditorPagedObjectButton(MenuTemplateButton templateButton, MenuConfigEditor.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { MenuConfigEditor.View currentView = getView(); SuperiorPlayer inventoryViewer = currentView.getInventoryViewer(); Player player = inventoryViewer.asPlayer(); if (player == null) return; try { String sectionPath = currentView.getPathSlots().get((currentView.getCurrentPage() - 1) * 36 + clickEvent.getRawSlot()); if (sectionPath == null) return; String viewPath = currentView.getPath(); String fullPath = viewPath.isEmpty() ? sectionPath : viewPath + "." + sectionPath; CommentedConfiguration config = Menus.MENU_CONFIG_EDITOR.getConfig(); if (config.isConfigurationSection(fullPath)) { currentView.setPreviousMove(false); currentView.closeView(); currentView.getMenu().createView(inventoryViewer, new MenuConfigEditor.Args(fullPath), currentView); } else if (config.isBoolean(fullPath)) { Menus.MENU_CONFIG_EDITOR.updateConfig(player, fullPath, !config.getBoolean(fullPath)); currentView.refreshView(); } else { PlayerChat.listen(player, message -> onPlayerChat(currentView, config, player, message, fullPath)); currentView.closeView(); player.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "SuperiorSkyblock" + ChatColor.GRAY + " Please enter a new value (-cancel to cancel):"); if (config.isList(fullPath)) { player.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "SuperiorSkyblock" + ChatColor.GRAY + " If you enter a value that is already in the list, it will be removed."); } } } catch (Exception ignored) { } } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { return pagedObject; } private boolean onPlayerChat(MenuView lastView, CommentedConfiguration config, Player player, Object message, String path) { if (!message.toString().equalsIgnoreCase("-cancel")) { if (config.isList(path)) { List list = config.getStringList(path); if (list.contains(message.toString())) { list.remove(message.toString()); player.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "SuperiorSkyblock" + ChatColor.GRAY + " Removed the value " + message + " from " + path); } else { list.add(message.toString()); player.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "SuperiorSkyblock" + ChatColor.GRAY + " Added the value " + message + " to " + path); } config.set(path, list); } else { boolean valid = true; if (config.isInt(path)) { try { message = Integer.valueOf(message.toString()); } catch (IllegalArgumentException ex) { player.sendMessage(ChatColor.RED + "Please specify a valid number"); valid = false; } } else if (config.isDouble(path)) { try { message = Double.valueOf(message.toString()); } catch (IllegalArgumentException ex) { player.sendMessage(ChatColor.RED + "Please specify a valid number"); valid = false; } } if (valid) { config.set(path, message); Menus.MENU_CONFIG_EDITOR.updateConfig(player, path, message); } } } PlayerChat.remove(player); lastView.refreshView(); return true; } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(null, null, null, null, null, null, getButtonIndex(), ConfigEditorPagedObjectButton.class, ConfigEditorPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ConfigEditorSaveButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuConfigEditor; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; public class ConfigEditorSaveButton extends AbstractMenuViewButton { private static final TemplateItem SAVE_BUTTON_ITEM = new TemplateItem(new ItemBuilder(Material.EMERALD).withName("&aSave Changes")); private ConfigEditorSaveButton(AbstractMenuTemplateButton templateButton, MenuConfigEditor.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); BukkitExecutor.async(() -> { Menus.MENU_CONFIG_EDITOR.saveConfig(config -> plugin.getSettings().loadData()); player.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "SuperiorSkyblock" + ChatColor.GRAY + " Saved configuration successfully."); BukkitExecutor.sync(() -> { getView().setPreviousMove(false); getView().closeView(); }); }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(SAVE_BUTTON_ITEM, null, null, null, null, ConfigEditorSaveButton.class, ConfigEditorSaveButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; public class ControlPanelButton extends AbstractMenuViewButton { private ControlPanelButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { switch (getTemplate().controlPanelAction) { case OPEN_MEMBERS: plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "members"); break; case OPEN_SETTINGS: plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "settings"); break; case OPEN_VISITORS: plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "visitors"); break; } } public enum ControlPanelAction { OPEN_MEMBERS, OPEN_SETTINGS, OPEN_VISITORS } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private ControlPanelAction controlPanelAction; public Builder setAction(ControlPanelAction controlPanelAction) { this.controlPanelAction = controlPanelAction; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, controlPanelAction); } } public static class Template extends MenuTemplateButtonImpl { private final ControlPanelAction controlPanelAction; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, ControlPanelAction controlPanelAction) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, ControlPanelButton.class, ControlPanelButton::new); this.controlPanelAction = Objects.requireNonNull(controlPanelAction, "controlPanelAction cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CoopsPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuCoops; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class CoopsPagedObjectButton extends AbstractPagedMenuButton { private CoopsPagedObjectButton(MenuTemplateButton templateButton, MenuCoops.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "uncoop", pagedObject.getName()); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { return new ItemBuilder(buttonItem) .replaceAll("{0}", pagedObject.getName()) .replaceAll("{1}", pagedObject.getPlayerRole() + "") .asSkullOf(pagedObject) .build(pagedObject); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), CoopsPagedObjectButton.class, CoopsPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuCounts; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import org.bukkit.Material; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collections; import java.util.EnumMap; import java.util.Map; import java.util.Optional; public class CountsPagedObjectButton extends AbstractPagedMenuButton { private static final BigInteger MAX_STACK = BigInteger.valueOf(64); private static final Map BLOCKS_TO_ITEMS = new MapBuilder() .put("ACACIA_DOOR", "ACACIA_DOOR_ITEM") .put("ACACIA_WALL_HANGING_SIGN", "ACACIA_HANGING_SIGN") .put("ACACIA_WALL_SIGN", "ACACIA_SIGN") .put("ATTACHED_MELON_STEM", "MELON_SEEDS") .put("ATTACHED_PUMPKIN_STEM", "PUMPKIN_SEEDS") .put("BAMBOO_SAPLING", "BAMBOO") .put("BAMBOO_WALL_HANGING_SIGN", "BAMBOO_HANGING_SIGN") .put("BAMBOO_WALL_SIGN", "BAMBOO_SIGN") .put("BED_BLOCK", "BED") .put("BEETROOT_BLOCK", "BEETROOT") .put("BEETROOTS", "BEETROOT") .put("BIG_DRIPLEAF_STEM", "BIG_DRIPLEAF") .put("BIRCH_DOOR", "BIRCH_DOOR_ITEM") .put("BIRCH_WALL_HANGING_SIGN", "BIRCH_HANGING_SIGN") .put("BIRCH_WALL_SIGN", "BIRCH_SIGN") .put("BLACK_CANDLE_CAKE", "BLACK_CANDLE") .put("BLACK_WALL_BANNER", "BLACK_BANNER") .put("BLUE_CANDLE_CAKE", "BLUE_CANDLE") .put("BLUE_WALL_BANNER", "BLUE_BANNER") .put("BRAIN_CORAL_WALL_FAN", "BRAIN_CORAL") .put("BREWING_STAND", "BREWING_STAND_ITEM") .put("BROWN_CANDLE_CAKE", "BROWN_CANDLE") .put("BROWN_WALL_BANNER", "BROWN_BANNER") .put("BUBBLE_CORAL_WALL_FAN", "BUBBLE_CORAL") .put("BURNING_FURNACE", "FURNACE") .put("CAKE_BLOCK", "CAKE") .put("CANDLE_CAKE", "CANDLE") .put("CARROT", "CARROT_ITEM") .put("CARROTS", "CARROT") .put("CAULDRON", "CAULDRON_ITEM") .put("CAVE_VINES", "GLOW_BERRIES") .put("CAVE_VINES_PLANT", "GLOW_BERRIES") .put("CHERRY_WALL_HANGING_SIGN", "CHERRY_HANGING_SIGN") .put("CHERRY_WALL_SIGN", "CHERRY_SIGN") .put("COCOA", ServerVersion.isLegacy() ? "INK_SACK:3" : "COCOA_BEANS") .put("COPPER_WALL_TORCH", "COPPER_TORCH") .put("CREEPER_WALL_HEAD", "CREEPER_HEAD") .put("CRIMSON_WALL_HANGING_SIGN", "CRIMSON_HANGING_SIGN") .put("CRIMSON_WALL_SIGN", "CRIMSON_SIGN") .put("CROPS", "SEEDS") .put("CYAN_CANDLE_CAKE", "CYAN_CANDLE") .put("CYAN_WALL_BANNER", "CYAN_BANNER") .put("DARK_OAK_DOOR", "DARK_OAK_DOOR_ITEM") .put("DARK_OAK_WALL_HANGING_SIGN", "DARK_OAK_HANGING_SIGN") .put("DARK_OAK_WALL_SIGN", "DARK_OAK_SIGN") .put("DAYLIGHT_DETECTOR_INVERTED", "DAYLIGHT_DETECTOR") .put("DEAD_BRAIN_CORAL_WALL_FAN", "DEAD_BRAIN_CORAL") .put("DEAD_BUBBLE_CORAL_WALL_FAN", "DEAD_BUBBLE_CORAL") .put("DEAD_FIRE_CORAL_WALL_FAN", "DEAD_FIRE_CORAL") .put("DEAD_HORN_CORAL_WALL_FAN", "DEAD_HORN_CORAL") .put("DEAD_TUBE_CORAL_WALL_FAN", "DEAD_TUBE_CORAL") .put("DIODE_BLOCK_OFF", "DIODE") .put("DIODE_BLOCK_ON", "DIODE") .put("DRAGON_WALL_HEAD", "DRAGON_HEAD") .put("END_GATEWAY", ServerVersion.isLegacy() ? "ENDER_PORTAL_FRAME" : "END_PORTAL_FRAME") .put("END_PORTAL", "END_PORTAL_FRAME") .put("ENDER_PORTAL", "ENDER_PORTAL_FRAME") .put("FIRE", "FIRE_CHARGE") .put("FIRE_CORAL_WALL_FAN", "FIRE_CORAL") .put("FLOWER_POT", "FLOWER_POT_ITEM") .put("FROSTED_ICE", "ICE") .put("GLOWING_REDSTONE_ORE", "REDSTONE_ORE") .put("GRAY_CANDLE_CAKE", "GRAY_CANDLE") .put("GRAY_WALL_BANNER", "GRAY_BANNER") .put("GREEN_CANDLE_CAKE", "GREEN_CANDLE") .put("GREEN_WALL_BANNER", "GREEN_BANNER") .put("HORN_CORAL_WALL_FAN", "HORN_CORAL") .put("IRON_DOOR_BLOCK", "IRON_DOOR") .put("JUNGLE_DOOR", "JUNGLE_DOOR_ITEM") .put("JUNGLE_WALL_HANGING_SIGN", "JUNGLE_HANGING_SIGN") .put("JUNGLE_WALL_SIGN", "JUNGLE_SIGN") .put("KELP_PLANT", "KELP") .put("LAVA", "LAVA_BUCKET") .put("LAVA_CAULDRON", "CAULDRON") .put("LIGHT_BLUE_CANDLE_CAKE", "LIGHT_BLUE_CANDLE") .put("LIGHT_BLUE_WALL_BANNER", "LIGHT_BLUE_BANNER") .put("LIGHT_GRAY_CANDLE_CAKE", "LIGHT_GRAY_CANDLE") .put("LIGHT_GRAY_WALL_BANNER", "LIGHT_GRAY_BANNER") .put("LIME_CANDLE_CAKE", "LIME_CANDLE") .put("LIME_WALL_BANNER", "LIME_BANNER") .put("MAGENTA_CANDLE_CAKE", "MAGENTA_CANDLE") .put("MAGENTA_WALL_BANNER", "MAGENTA_BANNER") .put("MANGROVE_WALL_HANGING_SIGN", "MANGROVE_HANGING_SIGN") .put("MANGROVE_WALL_SIGN", "MANGROVE_SIGN") .put("MELON_STEM", "MELON_SEEDS") .put("MOVING_PISTON", "PISTON") .put("NETHER_PORTAL", "OBSIDIAN") .put("NETHER_WARTS", "NETHER_STALK") .put("OAK_WALL_HANGING_SIGN", "OAK_HANGING_SIGN") .put("OAK_WALL_SIGN", "OAK_SIGN") .put("ORANGE_CANDLE_CAKE", "ORANGE_CANDLE") .put("ORANGE_WALL_BANNER", "ORANGE_BANNER") .put("PALE_OAK_WALL_HANGING_SIGN", "PALE_OAK_HANGING_SIGN") .put("PALE_OAK_WALL_SIGN", "PALE_OAK_SIGN") .put("PIGLIN_WALL_HEAD", "PIGLIN_HEAD") .put("PINK_CANDLE_CAKE", "PINK_CANDLE") .put("PINK_WALL_BANNER", "PINK_BANNER") .put("PISTON_EXTENSION", "PISTON") .put("PISTON_HEAD", "PISTON") .put("PISTON_MOVING_PIECE", "PISTON") .put("PITCHER_CROP", "PITCHER_PLANT") .put("PLAYER_WALL_HEAD", "PLAYER_HEAD") .put("PORTAL", "OBSIDIAN") .put("POTATO", "POTATO_ITEM") .put("POTATOES", "POTATO") .put("POTTED_ACACIA_SAPLING", "FLOWER_POT") .put("POTTED_ALLIUM", "FLOWER_POT") .put("POTTED_AZALEA_BUSH", "FLOWER_POT") .put("POTTED_AZURE_BLUET", "FLOWER_POT") .put("POTTED_BAMBOO", "FLOWER_POT") .put("POTTED_BIRCH_SAPLING", "FLOWER_POT") .put("POTTED_BLUE_ORCHID", "FLOWER_POT") .put("POTTED_BROWN_MUSHROOM", "FLOWER_POT") .put("POTTED_CACTUS", "FLOWER_POT") .put("POTTED_CHERRY_SAPLING", "FLOWER_POT") .put("POTTED_CLOSED_EYEBLOSSOM", "FLOWER_POT") .put("POTTED_CORNFLOWER", "FLOWER_POT") .put("POTTED_CRIMSON_FUNGUS", "FLOWER_POT") .put("POTTED_CRIMSON_ROOTS", "FLOWER_POT") .put("POTTED_DANDELION", "FLOWER_POT") .put("POTTED_DARK_OAK_SAPLING", "FLOWER_POT") .put("POTTED_DEAD_BUSH", "FLOWER_POT") .put("POTTED_FERN", "FLOWER_POT") .put("POTTED_FLOWERING_AZALEA_BUSH", "FLOWER_POT") .put("POTTED_GOLDEN_DANDELION", "GOLDEN_DANDELION") .put("POTTED_JUNGLE_SAPLING", "FLOWER_POT") .put("POTTED_LILY_OF_THE_VALLEY", "FLOWER_POT") .put("POTTED_MANGROVE_PROPAGULE", "FLOWER_POT") .put("POTTED_OAK_SAPLING", "FLOWER_POT") .put("POTTED_OPEN_EYEBLOSSOM", "FLOWER_POT") .put("POTTED_ORANGE_TULIP", "FLOWER_POT") .put("POTTED_OXEYE_DAISY", "FLOWER_POT") .put("POTTED_PALE_OAK_SAPLING", "FLOWER_POT") .put("POTTED_PINK_TULIP", "FLOWER_POT") .put("POTTED_POPPY", "FLOWER_POT") .put("POTTED_RED_MUSHROOM", "FLOWER_POT") .put("POTTED_RED_TULIP", "FLOWER_POT") .put("POTTED_SPRUCE_SAPLING", "FLOWER_POT") .put("POTTED_TORCHFLOWER", "FLOWER_POT") .put("POTTED_WARPED_FUNGUS", "FLOWER_POT") .put("POTTED_WARPED_ROOTS", "FLOWER_POT") .put("POTTED_WHITE_TULIP", "FLOWER_POT") .put("POTTED_WITHER_ROSE", "FLOWER_POT") .put("POWDER_SNOW", "POWDER_SNOW_BUCKET") .put("POWDER_SNOW_CAULDRON", "CAULDRON") .put("PUMPKIN_STEM", "PUMPKIN_SEEDS") .put("PURPLE_CANDLE_CAKE", "PURPLE_CANDLE") .put("PURPLE_WALL_BANNER", "PURPLE_BANNER") .put("RED_CANDLE_CAKE", "RED_CANDLE") .put("RED_WALL_BANNER", "RED_BANNER") .put("REDSTONE_COMPARATOR_OFF", "REDSTONE_COMPARATOR") .put("REDSTONE_COMPARATOR_ON", "REDSTONE_COMPARATOR") .put("REDSTONE_LAMP_ON", "REDSTONE_LAMP_OFF") .put("REDSTONE_TORCH_OFF", "REDSTONE_TORCH_ON") .put("REDSTONE_WALL_TORCH", "REDSTONE_TORCH") .put("REDSTONE_WIRE", "REDSTONE") .put("SIGN_POST", "SIGN") .put("SKELETON_WALL_SKULL", "SKELETON_SKULL") .put("SKULL", "SKULL_ITEM") .put("SOIL", "DIRT") .put("SOUL_FIRE", "FIRE_CHARGE") .put("SOUL_WALL_TORCH", "SOUL_TORCH") .put("SPRUCE_DOOR", "SPRUCE_DOOR_ITEM") .put("SPRUCE_WALL_HANGING_SIGN", "SPRUCE_HANGING_SIGN") .put("SPRUCE_WALL_SIGN", "SPRUCE_SIGN") .put("STANDING_BANNER", "BANNER") .put("STATIONARY_LAVA", "LAVA_BUCKET") .put("STATIONARY_WATER", "WATER_BUCKET") .put("SUGAR_CANE_BLOCK", "SUGAR_CANE") .put("SWEET_BERRY_BUSH", "SWEET_BERRIES") .put("TALL_SEAGRASS", "SEAGRASS") .put("TORCHFLOWER_CROP", "TORCHFLOWER") .put("TRIPWIRE", "TRIPWIRE_HOOK") .put("TUBE_CORAL_WALL_FAN", "TUBE_CORAL") .put("TWISTING_VINES_PLANT", "TWISTING_VINES") .put("WALL_BANNER", "BANNER") .put("WALL_SIGN", "SIGN") .put("WALL_TORCH", "TORCH") .put("WARPED_WALL_HANGING_SIGN", "WARPED_HANGING_SIGN") .put("WARPED_WALL_SIGN", "WARPED_SIGN") .put("WATER", "WATER_BUCKET") .put("WATER_CAULDRON", "CAULDRON") .put("WEEPING_VINES_PLANT", "WEEPING_VINES") .put("WHITE_CANDLE_CAKE", "WHITE_CANDLE") .put("WHITE_WALL_BANNER", "WHITE_BANNER") .put("WITHER_SKELETON_WALL_SKULL", "WITHER_SKELETON_SKULL") .put("WOODEN_DOOR", "WOOD_DOOR") .put("YELLOW_CANDLE_CAKE", "YELLOW_CANDLE") .put("YELLOW_WALL_BANNER", "YELLOW_BANNER") .put("ZOMBIE_WALL_HEAD", "ZOMBIE_HEAD") .build(); private CountsPagedObjectButton(MenuTemplateButton templateButton, MenuCounts.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { // Dummy button } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { Key rawKey = pagedObject.getBlockKey(); Pair customKeyItem = plugin.getBlockValues().convertCustomKeyItem(rawKey); BigDecimal amount = new BigDecimal(pagedObject.getAmount()); ItemMeta currentMeta = buttonItem.getItemMeta(); ItemBuilder itemBuilder; String materialName; ItemStack customItem = customKeyItem.getValue(); if (customItem != null) { itemBuilder = new ItemBuilder(customItem); materialName = Optional.ofNullable(rawKey.getSubKey()).orElseGet(rawKey::toString); } else { Key blockKey = customKeyItem.getKey(); Pair blockTypeAndData = getMaterialAndData(blockKey); Material blockMaterial = BLOCKS_TO_ITEMS.getOrDefault(blockTypeAndData.getKey(), blockTypeAndData.getKey()); short damage = blockTypeAndData.getValue(); String texture; if (blockMaterial == Materials.SPAWNER.toBukkitType() && !blockKey.getSubKey().isEmpty() && !(texture = ItemSkulls.getTexture(blockKey.getSubKey())).isEmpty()) { itemBuilder = new ItemBuilder(ItemSkulls.getPlayerHead(Materials.PLAYER_HEAD.toBukkitItem(), texture)); materialName = blockKey.getSubKey() + "_SPAWNER"; } else { itemBuilder = new ItemBuilder(blockMaterial, damage); if (blockMaterial == Materials.SPAWNER.toBukkitType()) materialName = blockKey.getSubKey() + "_SPAWNER"; else materialName = rawKey.getGlobalKey(); } } BlockValue blockValue = plugin.getBlockValues().getBlockValue(rawKey); BigDecimal worthValue = blockValue.getWorth(); BigDecimal levelValue = blockValue.getLevel(); SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); return itemBuilder .withName(currentMeta.hasDisplayName() ? currentMeta.getDisplayName() : "") .withLore(currentMeta.hasLore() ? currentMeta.getLore() : Collections.emptyList()) .withAmount(BigInteger.ONE.max(MAX_STACK.min(amount.toBigInteger())).intValue()) .replaceAll("{0}", Formatters.CAPITALIZED_FORMATTER.format(materialName)) .replaceAll("{1}", amount + "") .replaceAll("{2}", Formatters.NUMBER_FORMATTER.format(worthValue.multiply(amount))) .replaceAll("{3}", Formatters.NUMBER_FORMATTER.format(levelValue.multiply(amount))) .replaceAll("{4}", Formatters.FANCY_NUMBER_FORMATTER.format(worthValue.multiply(amount), inventoryViewer.getUserLocale())) .replaceAll("{5}", Formatters.FANCY_NUMBER_FORMATTER.format(levelValue.multiply(amount), inventoryViewer.getUserLocale())) .build(inventoryViewer); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), CountsPagedObjectButton.class, CountsPagedObjectButton::new); } } private static class MapBuilder { private final EnumMap mapper = new EnumMap<>(Material.class); public MapBuilder put(String block, String item) { Material blockMaterial = EnumHelper.getEnum(Material.class, block); Material itemMaterial = EnumHelper.getEnum(Material.class, item); if (blockMaterial != null && itemMaterial != null) mapper.put(blockMaterial, itemMaterial); return this; } public Map build() { return mapper; } } private static Pair getMaterialAndData(Key key) { if (key instanceof MaterialKey) return new Pair<>(((MaterialKey) key).getMaterial(), ((MaterialKey) key).getDurability()); try { Material blockMaterial = Material.valueOf(key.getGlobalKey()); short damage = 0; if (!key.getSubKey().isEmpty()) { try { damage = Short.parseShort(key.getSubKey()); } catch (Throwable ignored) { } } return new Pair<>(blockMaterial, damage); } catch (Exception ignored) { } return new Pair<>(Material.BEDROCK, (short) 0); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CurrentPageButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import org.bukkit.event.inventory.InventoryClickEvent; public class CurrentPageButton, E> extends AbstractMenuViewButton { private CurrentPageButton(AbstractMenuTemplateButton templateButton, V menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { // Dummy button } public static class Builder, E> extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, CurrentPageButton.class, CurrentPageButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import org.bukkit.event.inventory.InventoryClickEvent; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class DisbandButton extends AbstractMenuViewButton { private DisbandButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island targetIsland = menuView.getIsland(); if (getTemplate().disbandIsland && PluginEventsFactory.callIslandDisbandEvent(targetIsland, inventoryViewer)) { IslandUtils.sendMessage(targetIsland, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), inventoryViewer.getName()); Message.DISBANDED_ISLAND.send(inventoryViewer); if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); Message.DISBAND_ISLAND_BALANCE_REFUND.send(targetIsland.getOwner(), Formatters.NUMBER_FORMATTER.format( targetIsland.getIslandBank().getBalance().multiply(disbandRefund))); } if (plugin.getSettings().getDisbandCount() >= 0) { inventoryViewer.setDisbands(inventoryViewer.getDisbands() - 1); } targetIsland.disbandIsland(); } BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private boolean disbandIsland; public Builder setDisbandIsland(boolean disbandIsland) { this.disbandIsland = disbandIsland; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, disbandIsland); } } public static class Template extends MenuTemplateButtonImpl { private final boolean disbandIsland; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean disbandIsland) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, DisbandButton.class, DisbandButton::new); this.disbandIsland = disbandIsland; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DummyButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import org.bukkit.event.inventory.InventoryClickEvent; public class DummyButton> extends AbstractMenuViewButton { public static final MenuTemplateButton EMPTY_BUTTON = new DummyButton.Builder<>().build(); private DummyButton(AbstractMenuTemplateButton templateButton, V menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { // Dummy button } public static class Builder> extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, DummyButton.class, DummyButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuGlobalWarps; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.Locale; public class GlobalWarpsPagedObjectButton extends AbstractPagedMenuButton { private static final String[] EMPTY_STRING_ARRAY = new String[0]; private GlobalWarpsPagedObjectButton(MenuTemplateButton templateButton, MenuGlobalWarps.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { if (Menus.MENU_GLOBAL_WARPS.isVisitorWarps()) { menuView.setPreviousMove(false); plugin.getCommands().dispatchSubCommand(menuView.getInventoryViewer().asPlayer(), "visit", pagedObject.getOwner().getName()); } else { plugin.getProviders().getMenusProvider().openWarpCategories( menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject); } } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { String ownerName = pagedObject.getOwner().getName(); String islandName = pagedObject.getName().isEmpty() ? ownerName : pagedObject.getName(); Locale locale = menuView.getInventoryViewer().getUserLocale(); String[] description; if (!pagedObject.getDescription().isEmpty()) description = pagedObject.getDescription().split("\n"); else if (!Message.ISLAND_DESCRIPTION_NONE.isEmpty(locale)) description = new String[] {Message.ISLAND_DESCRIPTION_NONE.getMessage(locale)}; else description = EMPTY_STRING_ARRAY; return new ItemBuilder(buttonItem) .asSkullOf(pagedObject.getOwner()) .replaceAll("{0}", ownerName) .replaceLoreWithLines("{1}", description) .replaceAll("{2}", String.valueOf(pagedObject.getIslandWarps().size())) .replaceAll("{3}", islandName) .replaceAll("{4}", Formatters.NUMBER_FORMATTER.format(pagedObject.getIslandLevel())) .replaceAll("{5}", Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getIslandLevel(), locale)) .replaceAll("{6}", Formatters.NUMBER_FORMATTER.format(pagedObject.getWorth())) .replaceAll("{7}", Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getWorth(), locale)) .replaceAll("{8}", Formatters.NUMBER_FORMATTER.format(pagedObject.getTotalRating())) .replaceAll("{9}", Formatters.RATING_FORMATTER.format(pagedObject.getTotalRating(), locale)) .replaceAll("{10}", String.valueOf(pagedObject.getRatingAmount())) .build(pagedObject.getOwner()); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), GlobalWarpsPagedObjectButton.class, GlobalWarpsPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IconDisplayButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class IconDisplayButton extends AbstractMenuViewButton> { private IconDisplayButton(AbstractMenuTemplateButton> templateButton, AbstractIconProviderMenu.View menuView) { super(templateButton, menuView); } @Override public ItemStack createViewItem() { TemplateItem iconTemplate = menuView.getIconTemplate(); return iconTemplate == null ? null : iconTemplate.build(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { // Dummy button } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder> { @Override public MenuTemplateButton> build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, IconDisplayButton.class, IconDisplayButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IconEditLoreButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; public class IconEditLoreButton extends AbstractMenuViewButton> { private IconEditLoreButton(AbstractMenuTemplateButton> templateButton, AbstractIconProviderMenu.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); getTemplate().newLoreMessage.send(player); menuView.closeView(); PlayerChat.listen(player, message -> { if (!message.equalsIgnoreCase("-cancel")) { menuView.getIconTemplate().getEditableBuilder().withLore(message.split("\\\\n")); } PlayerChat.remove(player); menuView.refreshView(); return true; }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder> { private final Message newLoreMessage; public Builder(Message newLoreMessage) { this.newLoreMessage = newLoreMessage; } @Override public MenuTemplateButton> build() { return new Template<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newLoreMessage); } } public static class Template extends MenuTemplateButtonImpl> { private final Message newLoreMessage; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Message newLoreMessage) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, IconEditLoreButton.class, IconEditLoreButton::new); this.newLoreMessage = Objects.requireNonNull(newLoreMessage, "newLoreMessage cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IconEditTypeButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Locale; import java.util.Objects; public class IconEditTypeButton extends AbstractMenuViewButton> { private IconEditTypeButton(AbstractMenuTemplateButton> templateButton, AbstractIconProviderMenu.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); getTemplate().newLoreMessage.send(player); menuView.closeView(); PlayerChat.listen(player, message -> { if (!message.equalsIgnoreCase("-cancel")) { String[] sections = message.split(":"); Material material; try { material = Material.valueOf(sections[0].toUpperCase(Locale.ENGLISH)); if (material == Material.AIR) throw new IllegalArgumentException(); } catch (IllegalArgumentException ex) { Message.INVALID_MATERIAL.send(player, message); return true; } String rawMessage = sections.length == 2 ? sections[1] : "0"; short data; try { data = Short.parseShort(rawMessage); if (data < 0) throw new IllegalArgumentException(); } catch (IllegalArgumentException ex) { Message.INVALID_MATERIAL_DATA.send(player, rawMessage); return true; } menuView.getIconTemplate().getEditableBuilder().withType(material).withDurablity(data); } PlayerChat.remove(player); menuView.refreshView(); return true; }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder> { private final Message newLoreMessage; public Builder(Message newLoreMessage) { this.newLoreMessage = newLoreMessage; } @Override public MenuTemplateButton> build() { return new Template<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newLoreMessage); } } public static class Template extends MenuTemplateButtonImpl> { private final Message newLoreMessage; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Message newLoreMessage) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, IconEditTypeButton.class, IconEditTypeButton::new); this.newLoreMessage = Objects.requireNonNull(newLoreMessage, "newLoreMessage cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IconRenameButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; public class IconRenameButton extends AbstractMenuViewButton> { private IconRenameButton(AbstractMenuTemplateButton> templateButton, AbstractIconProviderMenu.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); getTemplate().newNameMessage.send(player); menuView.closeView(); PlayerChat.listen(player, message -> { if (!message.equalsIgnoreCase("-cancel")) { menuView.getIconTemplate().getEditableBuilder().withName(message); } PlayerChat.remove(player); menuView.refreshView(); return true; }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder> { private final Message newNameMessage; public Builder(Message newNameMessage) { this.newNameMessage = newNameMessage; } @Override public MenuTemplateButton> build() { return new Template<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newNameMessage); } } public static class Template extends MenuTemplateButtonImpl> { private final Message newNameMessage; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Message newNameMessage) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, IconRenameButton.class, IconRenameButton::new); this.newNameMessage = Objects.requireNonNull(newNameMessage, "newNameMessage cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandChestPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandChest; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class IslandChestPagedObjectButton extends AbstractPagedMenuButton { private IslandChestPagedObjectButton(MenuTemplateButton templateButton, MenuIslandChest.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); pagedObject.openChest(menuView.getInventoryViewer()); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { return new ItemBuilder(buttonItem) .replaceAll("{0}", (pagedObject.getIndex() + 1) + "") .replaceAll("{1}", (pagedObject.getRows() * 9) + "") .build(menuView.getInventoryViewer()); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), IslandChestPagedObjectButton.class, IslandChestPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.MenuConfig; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandCreation; import org.bukkit.Bukkit; import org.bukkit.block.Biome; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.math.BigDecimal; import java.util.Collections; import java.util.List; import java.util.Objects; public class IslandCreationButton extends AbstractMenuViewButton { private IslandCreationButton(AbstractMenuTemplateButton templateButton, MenuIslandCreation.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public ItemStack createViewItem() { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); String requiredPermission = getTemplate().getRequiredPermission(); return (requiredPermission == null || inventoryViewer.hasPermission(requiredPermission) ? getTemplate().getAccessItem() : getTemplate().lackPermissionItem).build(inventoryViewer); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); MenuActions.simulateIslandCreationClick(clickedPlayer, menuView.getIslandName(), getTemplate().getCreationConfig(), clickEvent.getClick().isRightClick(), menuView); } @Override public void onButtonClickLackPermission(InventoryClickEvent clickEvent) { super.onButtonClickLackPermission(clickEvent); getTemplate().lackPermissionCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("%player%", clickEvent.getWhoClicked().getName()))); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private final Schematic schematic; private TemplateItem noAccessItem = null; private List noAccessCommands = null; @Nullable private Biome biome; private BigDecimal bonusWorth; private BigDecimal bonusLevel; private boolean isOffset; private BlockOffset spawnOffset = null; public Builder(Schematic schematic) { this.schematic = schematic; } public void setAccessItem(TemplateItem accessItem) { this.buttonItem = accessItem; } public void setNoAccessItem(TemplateItem noAccessItem) { this.noAccessItem = noAccessItem; } public void setAccessSound(GameSound accessSound) { this.clickSound = accessSound; } public void setNoAccessSound(GameSound noAccessSound) { this.lackPermissionSound = noAccessSound; } public void setAccessCommands(List accessCommands) { this.commands = accessCommands; } public void setNoAccessCommands(List noAccessCommands) { this.noAccessCommands = noAccessCommands; } public void setBiome(Biome biome) { this.biome = biome; } public void setBonusWorth(BigDecimal bonusWorth) { this.bonusWorth = bonusWorth; } public void setBonusLevel(BigDecimal bonusLevel) { this.bonusLevel = bonusLevel; } public void setOffset(boolean isOffset) { this.isOffset = isOffset; } public void setSpawnOffset(BlockOffset spawnOffset) { this.spawnOffset = spawnOffset; } @Override public MenuTemplateButton build() { return new Template(requiredPermission, lackPermissionSound, clickSound, commands, noAccessItem, noAccessCommands, biome, bonusWorth, bonusLevel, isOffset, buttonItem, spawnOffset, schematic); } } public static class Template extends MenuTemplateButtonImpl { @Nullable private final GameSound accessSound; private final List accessCommands; private final TemplateItem lackPermissionItem; private final List lackPermissionCommands; @Nullable private final Biome biome; private final BigDecimal bonusWorth; private final BigDecimal bonusLevel; private final boolean isOffset; private final Schematic schematic; @Nullable private final BlockOffset spawnOffset; private final MenuIslandCreationConfig creationConfig; Template(@Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, @Nullable GameSound accessSound, @Nullable List accessCommands, @Nullable TemplateItem lackPermissionItem, @Nullable List lackPermissionCommands, @Nullable Biome biome, @Nullable BigDecimal bonusWorth, @Nullable BigDecimal bonusLevel, boolean isOffset, @Nullable TemplateItem accessItem, @Nullable BlockOffset spawnOffset, Schematic schematic) { super(accessItem == null ? TemplateItem.AIR : accessItem, null, null, requiredPermission, lackPermissionSound, IslandCreationButton.class, IslandCreationButton::new); this.accessSound = accessSound; this.accessCommands = accessCommands == null ? Collections.emptyList() : accessCommands; this.lackPermissionItem = lackPermissionItem == null ? TemplateItem.AIR : lackPermissionItem; this.lackPermissionCommands = lackPermissionCommands == null ? Collections.emptyList() : lackPermissionCommands; this.biome = biome; this.bonusWorth = bonusWorth == null ? BigDecimal.ZERO : bonusWorth; this.bonusLevel = bonusLevel == null ? BigDecimal.ZERO : bonusLevel; this.isOffset = isOffset; this.spawnOffset = spawnOffset; this.schematic = Objects.requireNonNull(schematic, "schematic cannot be null"); this.creationConfig = new MenuConfig.IslandCreation(this); } public TemplateItem getAccessItem() { return super.getButtonTemplateItem(); } @Nullable public GameSound getAccessSound() { return accessSound; } public List getAccessCommands() { return accessCommands; } @Nullable public Biome getBiome() { return biome; } public BigDecimal getBonusWorth() { return bonusWorth; } public BigDecimal getBonusLevel() { return bonusLevel; } public boolean isOffset() { return isOffset; } public Schematic getSchematic() { return schematic; } public BlockOffset getSpawnOffset() { return spawnOffset; } public MenuIslandCreationConfig getCreationConfig() { return creationConfig; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandFlagPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandFlags; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class IslandFlagPagedObjectButton extends AbstractPagedMenuButton { private IslandFlagPagedObjectButton(MenuTemplateButton templateButton, MenuIslandFlags.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island island = menuView.getIsland(); IslandFlag islandFlag = pagedObject.getIslandFlag(); if (islandFlag == null) return; if (island.hasSettingsEnabled(islandFlag)) { if (!PluginEventsFactory.callIslandDisableFlagEvent(island, inventoryViewer, islandFlag)) return; island.disableSettings(islandFlag); } else { if (!PluginEventsFactory.callIslandEnableFlagEvent(island, inventoryViewer, islandFlag)) return; island.enableSettings(islandFlag); } GameSoundImpl.playSound(clickEvent.getWhoClicked(), pagedObject.getClickSound()); Message.UPDATED_SETTINGS.send(inventoryViewer, Formatters.CAPITALIZED_FORMATTER.format(islandFlag.getName())); menuView.refreshView(); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island island = menuView.getIsland(); IslandFlag islandFlag = pagedObject.getIslandFlag(); return islandFlag != null && island.hasSettingsEnabled(islandFlag) ? pagedObject.getEnabledIslandFlagItem().build(inventoryViewer) : pagedObject.getDisabledIslandFlagItem().build(inventoryViewer); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), IslandFlagPagedObjectButton.class, IslandFlagPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PermissionNode; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandPrivileges; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import java.util.ArrayList; import java.util.List; public class IslandPrivilegePagedObjectButton extends AbstractPagedMenuButton { private final PrivilegeButtonActions actions; private IslandPrivilegePagedObjectButton(MenuTemplateButton templateButton, MenuIslandPrivileges.View menuView) { super(templateButton, menuView); if (menuView.getPermissionHolder() instanceof PlayerRole) { this.actions = RolePrivilegeButtonActions.INSTANCE; } else { this.actions = PlayerPrivilegeButtonActions.INSTANCE; } } @Override public void onButtonClick(InventoryClickEvent clickEvent) { this.actions.onButtonClick(clickEvent, this); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { return this.actions.modifyViewItem(buttonItem, this); } private static void onSuccessfulPermissionChange(IslandPrivilegePagedObjectButton button, SuperiorPlayer clickedPlayer, String permissionHolderName) { Player player = clickedPlayer.asPlayer(); if (player == null) return; Message.UPDATED_PERMISSION.send(clickedPlayer, permissionHolderName); GameSoundImpl.playSound(player, button.pagedObject.getAccessSound()); button.pagedObject.getAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("%player%", clickedPlayer.getName()))); Menus.MENU_ISLAND_PRIVILEGES.refreshViews(); } private static void onFailurePermissionChange(IslandPrivilegePagedObjectButton button, SuperiorPlayer clickedPlayer, boolean sendFailMessage) { Player player = clickedPlayer.asPlayer(); if (player == null) return; if (sendFailMessage) Message.LACK_CHANGE_PERMISSION.send(clickedPlayer); GameSoundImpl.playSound(player, button.pagedObject.getNoAccessSound()); button.pagedObject.getNoAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("%player%", clickedPlayer.getName()))); } private static boolean isRoleAllowed(@Nullable PlayerRole playerRole, @Nullable IslandPrivilege.Type islandPrivilegeType) { if (!plugin.getSettings().isCoopMembers() && playerRole == SPlayerRole.coopRole()) return false; if (islandPrivilegeType == IslandPrivilege.Type.COMMAND && playerRole != null && playerRole.isLessThan(SPlayerRole.defaultRole())) { return false; } return true; } private interface PrivilegeButtonActions { void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button); ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button); } private static class RolePrivilegeButtonActions implements PrivilegeButtonActions { private static final RolePrivilegeButtonActions INSTANCE = new RolePrivilegeButtonActions(); @Override public void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button) { IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege(); if (islandPrivilege == null) return; Island island = button.menuView.getIsland(); SuperiorPlayer clickedPlayer = button.menuView.getInventoryViewer(); IslandPrivilege.Type islandPrivilegeType = islandPrivilege.getType(); PlayerRole currentRole = island.getRequiredPlayerRole(islandPrivilege); if (clickedPlayer.getPlayerRole().isLessThan(currentRole)) { onFailurePermissionChange(button, clickedPlayer, false); return; } PlayerRole newRole = null; if (clickEvent.getClick().isLeftClick()) { newRole = currentRole; do { newRole = SPlayerRole.of(newRole.getWeight() - 1); } while (newRole != null && !isRoleAllowed(newRole, islandPrivilegeType)); if (newRole == null) newRole = clickedPlayer.getPlayerRole(); } else { if (clickedPlayer.getPlayerRole().isHigherThan(currentRole)) { newRole = currentRole; do { newRole = SPlayerRole.of(newRole.getWeight() + 1); } while (newRole != null && !isRoleAllowed(newRole, islandPrivilegeType)); } if (newRole == null) { newRole = islandPrivilegeType == IslandPrivilege.Type.COMMAND ? SPlayerRole.defaultRole() : SPlayerRole.guestRole(); } } if (PluginEventsFactory.callIslandChangeRolePrivilegeEvent(island, clickedPlayer, newRole)) { island.setPermission(newRole, islandPrivilege); onSuccessfulPermissionChange(button, clickedPlayer, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName())); } } @Override public ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button) { ItemBuilder permissionItem = button.pagedObject.getRoleIslandPrivilegeItem(); if (permissionItem == null) return new ItemStack(Material.AIR); IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege(); Island island = button.menuView.getIsland(); PlayerRole requiredRole = islandPrivilege == null ? null : island.getRequiredPlayerRole(islandPrivilege); IslandPrivilege.Type islandPrivilegeType = islandPrivilege == null ? null : islandPrivilege.getType(); permissionItem.replaceAll("{}", requiredRole == null ? "" : requiredRole.toString()); if (!Menus.MENU_ISLAND_PRIVILEGES.getNoRolePermission().isEmpty() && !Menus.MENU_ISLAND_PRIVILEGES.getExactRolePermission().isEmpty() && !Menus.MENU_ISLAND_PRIVILEGES.getHigherRolePermission().isEmpty()) { List roleString = new ArrayList<>(); int roleWeight = requiredRole == null ? Integer.MAX_VALUE : requiredRole.getWeight(); PlayerRole currentRole; for (int i = -2; (currentRole = SPlayerRole.of(i)) != null; i++) { if (!isRoleAllowed(currentRole, islandPrivilegeType)) continue; if (i < roleWeight) { roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getNoRolePermission().replace("{}", currentRole + "")); } else if (i == roleWeight) { roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getExactRolePermission().replace("{}", currentRole + "")); } else { roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getHigherRolePermission().replace("{}", currentRole + "")); } } ItemMeta itemMeta = permissionItem.getItemMeta(); if (itemMeta != null) { List lore = itemMeta.getLore(); for (int i = 0; i < lore.size(); i++) { String line = lore.get(i); if (line.equals("{0}")) { lore.set(i, roleString.get(0)); for (int j = 1; j < roleString.size(); j++) { lore.add(i + j, roleString.get(j)); } i += roleString.size(); } } permissionItem.withLore(lore); } } return permissionItem.build(button.menuView.getInventoryViewer()); } } private static class PlayerPrivilegeButtonActions implements PrivilegeButtonActions { private static final PlayerPrivilegeButtonActions INSTANCE = new PlayerPrivilegeButtonActions(); @Override public void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button) { IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege(); if (islandPrivilege == null) return; Island island = button.menuView.getIsland(); SuperiorPlayer clickedPlayer = button.menuView.getInventoryViewer(); if (!island.hasPermission(clickedPlayer, islandPrivilege)) return; SuperiorPlayer permissiblePlayer = (SuperiorPlayer) button.menuView.getPermissionHolder(); PermissionNode permissionNode = island.getPermissionNode(permissiblePlayer); String permissionHolderName = permissiblePlayer.getName(); boolean currentValue = permissionNode.hasPermission(islandPrivilege); if (!PluginEventsFactory.callIslandChangePlayerPrivilegeEvent(island, clickedPlayer, permissiblePlayer, !currentValue)) return; island.setPermission(permissiblePlayer, islandPrivilege, !currentValue); onSuccessfulPermissionChange(button, clickedPlayer, permissionHolderName); } @Override public ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button) { IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege(); Island targetIsland = button.menuView.getIsland(); SuperiorPlayer permissiblePlayer = (SuperiorPlayer) button.menuView.getPermissionHolder(); boolean hasPermission = islandPrivilege != null && targetIsland.getPermissionNode(permissiblePlayer).hasPermission(islandPrivilege); ItemBuilder permissionItem = hasPermission ? button.pagedObject.getEnabledIslandPrivilegeItem() : button.pagedObject.getDisabledIslandPrivilegeItem(); return permissionItem.build(button.menuView.getInventoryViewer()); } } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), IslandPrivilegePagedObjectButton.class, IslandPrivilegePagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/KickButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; public class KickButton extends AbstractMenuViewButton { private KickButton(AbstractMenuTemplateButton templateButton, MenuConfirmKick.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); if (getTemplate().kickPlayer) IslandUtils.handleKickPlayer(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer()); BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private boolean kickPlayer; public Builder setKickPlayer(boolean kickPlayer) { this.kickPlayer = kickPlayer; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, kickPlayer); } } public static class Template extends MenuTemplateButtonImpl { private final boolean kickPlayer; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean kickPlayer) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, KickButton.class, KickButton::new); this.kickPlayer = kickPlayer; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LanguageButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Locale; import java.util.Objects; public class LanguageButton extends AbstractMenuViewButton { private LanguageButton(AbstractMenuTemplateButton templateButton, BaseMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Locale language = getTemplate().language; if (!PluginEventsFactory.callPlayerChangeLanguageEvent(inventoryViewer, language)) return; inventoryViewer.setUserLocale(language); Message.CHANGED_LANGUAGE.send(inventoryViewer); BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private Locale language; public Builder setLanguage(Locale language) { this.language = language; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, language); } } public static class Template extends MenuTemplateButtonImpl { private final Locale language; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Locale language) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, LanguageButton.class, LanguageButton::new); this.language = Objects.requireNonNull(language, "language cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; public class LeaveButton extends AbstractMenuViewButton { private LeaveButton(AbstractMenuTemplateButton templateButton, BaseMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island island = inventoryViewer.getIsland(); if (getTemplate().leaveIsland && island != null) { IslandUtils.handleLeaveIsland(inventoryViewer, island); } BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private boolean leaveIsland; public Builder setLeaveIsland(boolean leaveIsland) { this.leaveIsland = leaveIsland; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, leaveIsland); } } public static class Template extends MenuTemplateButtonImpl { private final boolean leaveIsland; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean leaveIsland) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, LeaveButton.class, LeaveButton::new); this.leaveIsland = leaveIsland; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberManageButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; public class MemberManageButton extends AbstractMenuViewButton { private MemberManageButton(AbstractMenuTemplateButton templateButton, PlayerMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { getTemplate().manageAction.onButtonClick(menuView, clickEvent); } public enum ManageAction { SET_ROLE { @Override void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); plugin.getMenus().openMemberRole(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getSuperiorPlayer()); } }, BAN_MEMBER { @Override void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); if (plugin.getSettings().isBanConfirm()) { Island island = inventoryViewer.getIsland(); if (IslandUtils.checkBanRestrictions(inventoryViewer, island, menuView.getSuperiorPlayer())) { menuView.setPreviousMove(false); plugin.getMenus().openConfirmBan(inventoryViewer, MenuViewWrapper.fromView(menuView), island, menuView.getSuperiorPlayer()); } } else { plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "ban", menuView.getSuperiorPlayer().getName()); } } }, KICK_MEMBER { @Override void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); if (plugin.getSettings().isKickConfirm()) { Island island = inventoryViewer.getIsland(); if (island == null) return; if (IslandUtils.checkKickRestrictions(inventoryViewer, island, menuView.getSuperiorPlayer())) { menuView.setPreviousMove(false); plugin.getMenus().openConfirmKick(inventoryViewer, MenuViewWrapper.fromView(menuView), island, menuView.getSuperiorPlayer()); } } else { plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "kick", menuView.getSuperiorPlayer().getName()); } } }; ManageAction() { } abstract void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private ManageAction manageAction; public Builder setManageAction(ManageAction manageAction) { this.manageAction = manageAction; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, manageAction); } } public static class Template extends MenuTemplateButtonImpl { private final ManageAction manageAction; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, ManageAction manageAction) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, MemberManageButton.class, MemberManageButton::new); this.manageAction = Objects.requireNonNull(manageAction, "manageAction cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; public class MemberRoleButton extends AbstractMenuViewButton { private MemberRoleButton(AbstractMenuTemplateButton templateButton, PlayerMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player inventoryViewer = menuView.getInventoryViewer().asPlayer(); SuperiorPlayer targetPlayer = menuView.getSuperiorPlayer(); PlayerRole playerRole = plugin.getRoles().getPlayerRoleFromId(getTemplate().playerRoleId); if (playerRole.isLastRole()) { plugin.getCommands().dispatchSubCommand(inventoryViewer, "transfer", targetPlayer.getName()); } else { plugin.getCommands().dispatchSubCommand(inventoryViewer, "setrole", targetPlayer.getName() + " " + playerRole); } } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private int playerRoleId; public Builder setPlayerRole(PlayerRole playerRole) { this.playerRoleId = Objects.requireNonNull(playerRole, "playerRole cannot be null").getId(); return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, playerRoleId); } } public static class Template extends MenuTemplateButtonImpl { private final int playerRoleId; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, int playerRoleId) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, MemberRoleButton.class, MemberRoleButton::new); this.playerRoleId = playerRoleId; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MembersPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandMembers; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class MembersPagedObjectButton extends AbstractPagedMenuButton { private MembersPagedObjectButton(MenuTemplateButton templateButton, MenuIslandMembers.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); plugin.getMenus().openMemberManage(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { return new ItemBuilder(buttonItem) .replaceAll("{0}", pagedObject.getName()) .replaceAll("{1}", pagedObject.getPlayerRole() + "") .asSkullOf(pagedObject) .build(pagedObject); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), MembersPagedObjectButton.class, MembersPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MissionsPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissionsCategory; import com.bgsoftware.superiorskyblock.mission.MissionData; import com.bgsoftware.superiorskyblock.mission.MissionReference; import org.bukkit.Material; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.List; import java.util.Optional; public class MissionsPagedObjectButton extends AbstractPagedMenuButton { private MissionsPagedObjectButton(MenuTemplateButton templateButton, MenuMissionsCategory.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Mission mission = pagedObject.getMission(); if (mission == null) return; Optional missionDataOptional = plugin.getMissions().getMissionData(mission); if (!missionDataOptional.isPresent()) return; SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); MissionData missionData = missionDataOptional.get(); IMissionsHolder missionsHolder = mission.getIslandMission() ? inventoryViewer.getIsland() : inventoryViewer; if (missionsHolder == null) return; boolean canComplete = plugin.getMissions().canComplete(inventoryViewer, mission); GameSound gameSound; if (!missionsHolder.canCompleteMissionAgain(mission)) gameSound = getTemplate().completedSound; else if (getTemplate().lockedSound != null && missionData.hasLocked() && !plugin.getMissions().hasAllRequirements(mission, inventoryViewer)) gameSound = getTemplate().lockedSound; else if (canComplete) gameSound = getTemplate().canCompleteSound; else gameSound = getTemplate().notCompletedSound; GameSoundImpl.playSound(clickEvent.getWhoClicked(), gameSound); if (!canComplete) return; plugin.getMissions().rewardMission(mission, inventoryViewer, false, false, result -> { if (result) menuView.refreshView(); }); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { Mission mission = pagedObject.getMission(); if (mission == null) return buttonItem; Optional missionDataOptional = plugin.getMissions().getMissionData(mission); if (!missionDataOptional.isPresent()) return buttonItem; SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); MissionData missionData = missionDataOptional.get(); IMissionsHolder missionsHolder = mission.getIslandMission() ? inventoryViewer.getIsland() : inventoryViewer; if (missionsHolder == null) return new ItemStack(Material.AIR); int percentage = calculatePercentage(mission.getProgress(inventoryViewer)); int progressValue = mission.getProgressValue(inventoryViewer); int amountCompleted = missionsHolder.getAmountMissionCompleted(mission); ItemBuilder itemBuilder; if (!missionsHolder.canCompleteMissionAgain(mission)) itemBuilder = missionData.getCompleted(); else if (missionData.hasLocked() && !plugin.getMissions().hasAllRequirements(mission, inventoryViewer)) itemBuilder = missionData.getLocked(); else if (plugin.getMissions().canComplete(inventoryViewer, mission)) itemBuilder = missionData.getCanComplete(); else itemBuilder = missionData.getNotCompleted(); ItemStack itemStack = itemBuilder .replaceAll("{0}", percentage + "") .replaceAll("{1}", progressValue + "") .replaceAll("{2}", amountCompleted + "") .build(inventoryViewer); mission.formatItem(inventoryViewer, itemStack); return itemStack; } private static int calculatePercentage(double progress) { return Math.round((float) Math.min(1.0, progress) * 100); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { private GameSound notCompletedSound = null; private GameSound canCompleteSound = null; private GameSound lockedSound = null; public Builder setCompletedSound(GameSound completedSound) { this.clickSound = completedSound; return this; } public Builder setNotCompletedSound(GameSound notCompletedSound) { this.notCompletedSound = notCompletedSound; return this; } public Builder setCanCompleteSound(GameSound canCompleteSound) { this.canCompleteSound = canCompleteSound; return this; } public Builder setLockedSound(GameSound lockedSound) { this.lockedSound = lockedSound; return this; } @Override public PagedMenuTemplateButton build() { return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), clickSound, notCompletedSound, canCompleteSound, lockedSound); } } public static class Template extends PagedMenuTemplateButtonImpl { private final GameSound completedSound; private final GameSound notCompletedSound; private final GameSound canCompleteSound; private final GameSound lockedSound; Template(TemplateItem buttonItem, List commands, String requiredPermission, GameSound lackPermissionSound, TemplateItem nullItem, int buttonIndex, GameSound completedSound, GameSound notCompletedSound, GameSound canCompleteSound, GameSound lockedSound) { super(buttonItem, null, commands, requiredPermission, lackPermissionSound, nullItem, buttonIndex, MissionsPagedObjectButton.class, MissionsPagedObjectButton::new); this.completedSound = completedSound; this.notCompletedSound = notCompletedSound; this.canCompleteSound = canCompleteSound; this.lockedSound = lockedSound; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/NextPageButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import org.bukkit.event.inventory.InventoryClickEvent; public class NextPageButton, E> extends AbstractMenuViewButton { private NextPageButton(AbstractMenuTemplateButton templateButton, V menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { PagedMenuLayout pagedMenuPattern = (PagedMenuLayout) menuView.getMenu().getLayout(); if (pagedMenuPattern == null) return; int pageObjectSlotsAmount = pagedMenuPattern.getObjectsPerPageCount(); int currentPage = menuView.getCurrentPage(); int pagedObjectAmounts = menuView.getPagedObjects().size(); if (pageObjectSlotsAmount * currentPage < pagedObjectAmounts) menuView.setCurrentPage(currentPage + 1); } public static class Builder, E> extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, NextPageButton.class, NextPageButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenBankLogsButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import org.bukkit.event.inventory.InventoryClickEvent; public class OpenBankLogsButton extends AbstractMenuViewButton { private OpenBankLogsButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); plugin.getMenus().openBankLogs(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getIsland()); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, OpenBankLogsButton.class, OpenBankLogsButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; public class OpenMissionCategoryButton extends AbstractMenuViewButton { private OpenMissionCategoryButton(AbstractMenuTemplateButton templateButton, BaseMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { if (getTemplate().requireIsland && !menuView.getInventoryViewer().hasIsland()) { Message.INVALID_ISLAND.send(menuView.getInventoryViewer()); return; } menuView.setPreviousMove(false); plugin.getMenus().openMissionsCategory(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), getTemplate().missionCategory); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private MissionCategory missionCategory; public Builder setMissionsCategory(MissionCategory missionCategory) { this.missionCategory = missionCategory; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, missionCategory); } } public static class Template extends MenuTemplateButtonImpl { private final MissionCategory missionCategory; private final boolean requireIsland; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, MissionCategory missionCategory) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, OpenMissionCategoryButton.class, OpenMissionCategoryButton::new); this.missionCategory = Objects.requireNonNull(missionCategory, "missionCategory cannot be null"); this.requireIsland = !plugin.getMissions().isPlayerMissionCategory(missionCategory); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenUniqueVisitorsButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandVisitors; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import org.bukkit.event.inventory.InventoryClickEvent; public class OpenUniqueVisitorsButton extends AbstractMenuViewButton { private OpenUniqueVisitorsButton(AbstractMenuTemplateButton templateButton, MenuIslandVisitors.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); plugin.getMenus().openUniqueVisitors(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getIsland()); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, OpenUniqueVisitorsButton.class, OpenUniqueVisitorsButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/PreviousPageButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import org.bukkit.event.inventory.InventoryClickEvent; public class PreviousPageButton, E> extends AbstractMenuViewButton { private PreviousPageButton(AbstractMenuTemplateButton templateButton, V menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { int newPage = menuView.getCurrentPage() - 1; if (newPage >= 1) menuView.setCurrentPage(newPage); } public static class Builder, E> extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, PreviousPageButton.class, PreviousPageButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.Collections; import java.util.List; import java.util.Objects; public class RateIslandButton extends AbstractMenuViewButton { private RateIslandButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island island = menuView.getIsland(); Rating rating = getTemplate().rating; if (rating == Rating.UNKNOWN) { if (!PluginEventsFactory.callIslandRemoveRatingEvent(island, inventoryViewer, inventoryViewer)) return; island.removeRating(inventoryViewer); } else { if (!PluginEventsFactory.callIslandRateEvent(island, inventoryViewer, inventoryViewer, rating)) return; island.setRating(inventoryViewer, rating); } Message.RATE_SUCCESS.send(inventoryViewer, rating.getValue()); IslandUtils.sendMessage(island, Message.RATE_ANNOUNCEMENT, Collections.emptyList(), inventoryViewer.getName(), rating.getValue()); BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private Rating rating; public Builder setRating(Rating rating) { this.rating = rating; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, rating); } } public static class Template extends MenuTemplateButtonImpl { private final Rating rating; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Rating rating) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, RateIslandButton.class, RateIslandButton::new); this.rating = Objects.requireNonNull(rating, "rating cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RatingsPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandRatings; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class RatingsPagedObjectButton extends AbstractPagedMenuButton { private RatingsPagedObjectButton(MenuTemplateButton templateButton, MenuIslandRatings.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { // Dummy button } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { SuperiorPlayer ratingPlayer = plugin.getPlayers().getSuperiorPlayer(pagedObject.getPlayerUUID()); return new ItemBuilder(buttonItem) .replaceAll("{0}", ratingPlayer.getName()) .replaceAll("{1}", Formatters.RATING_FORMATTER.format(pagedObject.getRating().getValue(), ratingPlayer.getUserLocale())) .asSkullOf(ratingPlayer) .build(ratingPlayer); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), RatingsPagedObjectButton.class, RatingsPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.List; public class TopIslandsPagedObjectButton extends AbstractPagedMenuButton { private TopIslandsPagedObjectButton(MenuTemplateButton templateButton, MenuTopIslands.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { TopIslandsSelfIslandButton.onButtonClick(clickEvent, menuView, pagedObject, getTemplate().islandSound, getTemplate().islandCommands, getTemplate().noIslandSound, getTemplate().noIslandCommands); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { if (pagedObject == null) { return getTemplate().getNullTemplateItem().build(); } else { return TopIslandsSelfIslandButton.modifyViewItem(menuView, pagedObject, getTemplate().islandItem); } } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { private TemplateItem noIslandItem; private GameSound noIslandSound; private List noIslandCommands; public void setIslandItem(TemplateItem islandItem) { this.buttonItem = islandItem; } public void setNoIslandItem(TemplateItem noIslandItem) { this.noIslandItem = noIslandItem; } public void setIslandSound(GameSound islandSound) { this.clickSound = islandSound; } public void setNoIslandSound(GameSound noIslandSound) { this.noIslandSound = noIslandSound; } public void setIslandCommands(List islandCommands) { this.commands = islandCommands; } public void setNoIslandCommands(List noIslandCommands) { this.noIslandCommands = noIslandCommands; } @Override public PagedMenuTemplateButton build() { return new Template(requiredPermission, lackPermissionSound, buttonItem, clickSound, commands, noIslandItem, noIslandSound, noIslandCommands, getButtonIndex()); } } public static class Template extends PagedMenuTemplateButtonImpl { private final TemplateItem islandItem; private final GameSound islandSound; private final GameSound noIslandSound; private final List islandCommands; private final List noIslandCommands; Template(String requiredPermission, GameSound lackPermissionSound, TemplateItem islandItem, GameSound islandSound, List islandCommands, TemplateItem noIslandItem, GameSound noIslandSound, List noIslandCommands, int buttonIndex) { super(null, null, null, requiredPermission, lackPermissionSound, noIslandItem, buttonIndex, TopIslandsPagedObjectButton.class, TopIslandsPagedObjectButton::new); this.islandItem = islandItem; this.islandSound = islandSound; this.islandCommands = islandCommands == null ? Collections.emptyList() : islandCommands; this.noIslandSound = noIslandSound; this.noIslandCommands = noIslandCommands == null ? Collections.emptyList() : noIslandCommands; if (this.getNullTemplateItem() != null) this.getNullTemplateItem().getEditableBuilder().asSkullOf((SuperiorPlayer) null); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class TopIslandsSelfIslandButton extends AbstractMenuViewButton { private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; private TopIslandsSelfIslandButton(MenuTemplateButton templateButton, MenuTopIslands.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public ItemStack createViewItem() { Island island = menuView.getInventoryViewer().getIsland(); return island == null ? getTemplate().noIslandItem.build() : modifyViewItem(menuView, island, getTemplate().islandItem); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { onButtonClick(clickEvent, menuView, menuView.getInventoryViewer().getIsland(), getTemplate().islandSound, getTemplate().islandCommands, getTemplate().noIslandSound, getTemplate().noIslandCommands); } public static void onButtonClick(InventoryClickEvent clickEvent, MenuTopIslands.View menuView, @Nullable Island island, @Nullable GameSound islandSound, List islandCommands, @Nullable GameSound noIslandSound, List noIslandCommands) { Player player = (Player) clickEvent.getWhoClicked(); if (island != null) { GameSoundImpl.playSound(player, islandSound); if (islandCommands != null) { islandCommands.forEach(command -> Bukkit.dispatchCommand(command.startsWith("PLAYER:") ? player : Bukkit.getConsoleSender(), command.replace("PLAYER:", "") .replace("%player%", player.getName()) .replace("%island%", island.getName()) .replace("%owner%", island.getOwner().getName()) )); } menuView.setPreviousMove(false); if (clickEvent.getClick().isRightClick()) { if (Menus.MENU_GLOBAL_WARPS.isVisitorWarps()) { plugin.getCommands().dispatchSubCommand(player, "visit", island.getOwner().getName()); } else { plugin.getProviders().getMenusProvider().openWarpCategories( menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), island); } } else if (plugin.getSettings().isValuesMenu()) { plugin.getMenus().openValues(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), island); } return; } GameSoundImpl.playSound(player, noIslandSound); if (noIslandCommands != null) noIslandCommands.forEach(command -> Bukkit.dispatchCommand(command.startsWith("PLAYER:") ? player : Bukkit.getConsoleSender(), command.replace("PLAYER:", "").replace("%player%", player.getName()))); } public static ItemStack modifyViewItem(MenuTopIslands.View menuView, Island island, @Nullable TemplateItem islandItem) { if (islandItem == null) return null; SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); SuperiorPlayer islandOwner = island.getOwner(); int place = plugin.getGrid().getIslandPosition(island, menuView.getSortingType()) + 1; ItemBuilder itemBuilder = islandItem.getBuilder().asSkullOf(islandOwner); String islandName = !plugin.getSettings().getIslandNames().isIslandTop() || island.getName().isEmpty() ? islandOwner.getName() : island.getName(); itemBuilder.replaceName("{0}", islandName) .replaceName("{1}", String.valueOf(place)) .replaceName("{2}", Formatters.NUMBER_FORMATTER.format(island.getIslandLevel())) .replaceName("{3}", Formatters.NUMBER_FORMATTER.format(island.getWorth())) .replaceName("{5}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandLevel(), inventoryViewer.getUserLocale())) .replaceName("{6}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), inventoryViewer.getUserLocale())) .replaceName("{7}", Formatters.NUMBER_FORMATTER.format(island.getTotalRating())) .replaceName("{8}", Formatters.RATING_FORMATTER.format(island.getTotalRating(), inventoryViewer.getUserLocale())) .replaceName("{9}", Formatters.NUMBER_FORMATTER.format(island.getRatingAmount())) .replaceName("{10}", Formatters.NUMBER_FORMATTER.format(island.getAllPlayersInside().size())); ItemMeta itemMeta = itemBuilder.getItemMeta(); if (itemMeta != null && itemMeta.hasLore()) { List lore = new LinkedList<>(); for (String line : itemMeta.getLore()) { if (line.contains("{4}")) { List members = new LinkedList<>(island.getIslandMembers(plugin.getSettings().isIslandTopIncludeLeader())); String memberFormat = line.split("\\{4}:")[1]; if (members.size() == 0) { lore.add(memberFormat.replace("{}", "None")); } else { if (plugin.getSettings().getTopIslandMembersSorting() != TopIslandMembersSorting.NAMES) members.sort(plugin.getSettings().getTopIslandMembersSorting().getComparator()); members.forEach(member -> { String onlineMessage = member.isOnline() ? Message.ISLAND_TOP_STATUS_ONLINE.getMessage(inventoryViewer.getUserLocale()) : Message.ISLAND_TOP_STATUS_OFFLINE.getMessage(inventoryViewer.getUserLocale()); lore.add(placeholdersService.get().parsePlaceholders(member.asOfflinePlayer(), memberFormat .replace("{}", member.getName()) .replace("{0}", member.getName()) .replace("{1}", onlineMessage == null ? "" : onlineMessage) .replace("{2}", member.getPlayerRole().getDisplayName())) ); }); } } else { lore.add(line .replace("{0}", island.getOwner().getName()) .replace("{1}", String.valueOf(place)) .replace("{2}", Formatters.NUMBER_FORMATTER.format(island.getIslandLevel())) .replace("{3}", Formatters.NUMBER_FORMATTER.format(island.getWorth())) .replace("{5}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandLevel(), inventoryViewer.getUserLocale())) .replace("{6}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), inventoryViewer.getUserLocale())) .replace("{7}", Formatters.NUMBER_FORMATTER.format(island.getTotalRating())) .replace("{8}", Formatters.RATING_FORMATTER.format(island.getTotalRating(), inventoryViewer.getUserLocale())) .replace("{9}", Formatters.NUMBER_FORMATTER.format(island.getRatingAmount())) .replace("{10}", Formatters.NUMBER_FORMATTER.format(island.getAllPlayersInside().size()))); } } itemBuilder.withLore(lore); } return itemBuilder.build(islandOwner); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private TemplateItem noIslandItem; private GameSound noIslandSound; private List noIslandCommands; public void setIslandItem(TemplateItem islandItem) { this.buttonItem = islandItem; } public void setNoIslandItem(TemplateItem noIslandItem) { this.noIslandItem = noIslandItem; } public void setIslandSound(GameSound islandSound) { this.clickSound = islandSound; } public void setNoIslandSound(GameSound noIslandSound) { this.noIslandSound = noIslandSound; } public void setIslandCommands(List islandCommands) { this.commands = islandCommands; } public void setNoIslandCommands(List noIslandCommands) { this.noIslandCommands = noIslandCommands; } @Override public MenuTemplateButton build() { return new Template(requiredPermission, lackPermissionSound, buttonItem, clickSound, commands, noIslandItem, noIslandSound, noIslandCommands); } } public static class Template extends MenuTemplateButtonImpl { private final TemplateItem islandItem; private final TemplateItem noIslandItem; @Nullable private final GameSound islandSound; @Nullable private final GameSound noIslandSound; private final List islandCommands; private final List noIslandCommands; Template(@Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, @Nullable TemplateItem islandItem, @Nullable GameSound islandSound, @Nullable List islandCommands, @Nullable TemplateItem noIslandItem, @Nullable GameSound noIslandSound, @Nullable List noIslandCommands) { super(null, null, null, requiredPermission, lackPermissionSound, TopIslandsSelfIslandButton.class, TopIslandsSelfIslandButton::new); this.islandItem = islandItem == null ? TemplateItem.AIR : islandItem; this.noIslandItem = noIslandItem == null ? TemplateItem.AIR : noIslandItem; this.islandSound = islandSound; this.islandCommands = islandCommands == null ? Collections.emptyList() : islandCommands; this.noIslandSound = noIslandSound; this.noIslandCommands = noIslandCommands == null ? Collections.emptyList() : noIslandCommands; if (noIslandItem != null) noIslandItem.getEditableBuilder().asSkullOf((SuperiorPlayer) null); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TransferButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; public class TransferButton extends AbstractMenuViewButton { private TransferButton(AbstractMenuTemplateButton templateButton, MenuConfirmTransfer.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); if (getTemplate().newOwner) IslandUtils.handleTransferIsland(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer()); BukkitExecutor.sync(menuView::closeView, 1L); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private boolean newOwner; public Builder setNewOwner(boolean newOwner) { this.newOwner = newOwner; return this; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newOwner); } } public static class Template extends MenuTemplateButtonImpl { private final boolean newOwner; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean newOwner) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, TransferButton.class, TransferButton::new); this.newOwner = newOwner; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UniqueVisitorPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandUniqueVisitors; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.Date; import java.util.Locale; public class UniqueVisitorPagedObjectButton extends AbstractPagedMenuButton { private UniqueVisitorPagedObjectButton(MenuTemplateButton templateButton, MenuIslandUniqueVisitors.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { String subCommandToExecute; if (clickEvent.getClick().isRightClick()) subCommandToExecute = "invite"; else if (clickEvent.getClick().isLeftClick()) subCommandToExecute = "expel"; else return; plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), subCommandToExecute, pagedObject.getVisitor().getName()); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { SuperiorPlayer visitor = pagedObject.getVisitor(); Island island = visitor.getIsland(); Locale locale = menuView.getInventoryViewer().getUserLocale(); String islandOwner = island != null ? island.getOwner().getName() : Message.ISLAND_OWNER_NONE.getMessage(locale); String islandName = island != null ? island.getName().isEmpty() ? islandOwner : island.getName() : Message.ISLAND_NAME_NONE.getMessage(locale); return new ItemBuilder(buttonItem) .replaceAll("{0}", visitor.getName()) .replaceAll("{1}", islandOwner) .replaceAll("{2}", islandName) .replaceAll("{3}", Formatters.DATE_FORMATTER.format(new Date(pagedObject.getVisitTime()))) .asSkullOf(visitor) .build(visitor); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), UniqueVisitorPagedObjectButton.class, UniqueVisitorPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UpgradeButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import org.bukkit.Material; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.List; import java.util.Objects; public class UpgradeButton extends AbstractMenuViewButton { private static final TemplateItem INVALID_ITEM = new TemplateItem(new ItemBuilder(Material.BEDROCK).withName("&c&lInvalid Item")); private UpgradeButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public ItemStack createViewItem() { Upgrade upgrade = getTemplate().upgrade; UpgradeLevel upgradeLevel = menuView.getIsland().getUpgradeLevel(upgrade); SUpgradeLevel.ItemData itemData = ((SUpgradeLevel) upgradeLevel).getItemData(); if (itemData == null) return null; SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); UpgradeLevel nextUpgradeLevel = upgrade.getUpgradeLevel(upgradeLevel.getLevel() + 1); UpgradeCost levelCost = upgradeLevel.getCost(); String permission = nextUpgradeLevel == null ? "" : nextUpgradeLevel.getPermission(); String requirements = nextUpgradeLevel == null ? "" : nextUpgradeLevel.checkRequirements(inventoryViewer); boolean nextLevel = levelCost.hasEnoughBalance(inventoryViewer) && (permission.isEmpty() || inventoryViewer.hasPermission(permission)) && requirements.isEmpty(); TemplateItem buttonItem = nextLevel ? itemData.hasNextLevel : itemData.noNextLevel; return (buttonItem == null ? INVALID_ITEM : buttonItem).getBuilder() .replaceAll("{0}", levelCost.getCost() + "") .replaceAll("{1}", Formatters.NUMBER_FORMATTER.format(levelCost.getCost())) .replaceAll("{2}", Formatters.FANCY_NUMBER_FORMATTER.format(levelCost.getCost(), inventoryViewer.getUserLocale())) .build(inventoryViewer); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Upgrade upgrade = plugin.getUpgrades().getUpgrade(clickEvent.getRawSlot()); if (upgrade == null) return; plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "rankup", upgrade.getName()); menuView.refreshView(); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private final Upgrade upgrade; public Builder(Upgrade upgrade) { this.upgrade = upgrade; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, upgrade); } } public static class Template extends MenuTemplateButtonImpl { private final Upgrade upgrade; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Upgrade upgrade) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, UpgradeButton.class, UpgradeButton::new); this.upgrade = Objects.requireNonNull(upgrade, "upgrade cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ValuesButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandValues; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.math.BigDecimal; import java.math.BigInteger; import java.util.List; import java.util.Objects; public class ValuesButton extends AbstractMenuViewButton { private static final BigInteger MAX_STACK = BigInteger.valueOf(64); private ValuesButton(AbstractMenuTemplateButton templateButton, MenuIslandValues.View menuView) { super(templateButton, menuView); } @Override public Template getTemplate() { return (Template) super.getTemplate(); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { // Dummy Button } @Override public ItemStack createViewItem() { TemplateItem buttonItem = getTemplate().getButtonTemplateItem(); if (buttonItem == null) return null; SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island island = menuView.getIsland(); Key block = getTemplate().block; BigDecimal amount = new BigDecimal(block.getGlobalKey().contains("SPAWNER") ? island.getExactBlockCountAsBigInteger(block) : island.getBlockCountAsBigInteger(block)); BlockValue blockValue = plugin.getBlockValues().getBlockValue(block); BigDecimal blockWorth = blockValue.getWorth(); BigDecimal blockLevel = blockValue.getLevel(); ItemStack itemStack = buttonItem.getBuilder() .replaceAll("{0}", amount + "") .replaceAll("{1}", Formatters.NUMBER_FORMATTER.format(blockWorth.multiply(amount))) .replaceAll("{2}", Formatters.NUMBER_FORMATTER.format(blockLevel.multiply(amount))) .replaceAll("{3}", Formatters.FANCY_NUMBER_FORMATTER.format(blockWorth.multiply(amount), inventoryViewer.getUserLocale())) .replaceAll("{4}", Formatters.FANCY_NUMBER_FORMATTER.format(blockLevel.multiply(amount), inventoryViewer.getUserLocale())) .build(inventoryViewer); itemStack.setAmount(BigInteger.ONE.max(MAX_STACK.min(amount.toBigInteger())).intValue()); return itemStack; } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private final Key block; public Builder(Key block) { this.block = block; } @Override public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, block); } } public static class Template extends MenuTemplateButtonImpl { private final Key block; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, Key block) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, ValuesButton.class, ValuesButton::new); this.block = Objects.requireNonNull(block, "block cannot be null"); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/VisitorPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandVisitors; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.Locale; public class VisitorPagedObjectButton extends AbstractPagedMenuButton { private VisitorPagedObjectButton(MenuTemplateButton templateButton, MenuIslandVisitors.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { String subCommandToExecute; if (clickEvent.getClick().isRightClick()) subCommandToExecute = "invite"; else if (clickEvent.getClick().isLeftClick()) subCommandToExecute = "expel"; else return; plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), subCommandToExecute, pagedObject.getName()); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { Island island = pagedObject.getIsland(); Locale locale = menuView.getInventoryViewer().getUserLocale(); String islandOwner = island != null ? island.getOwner().getName() : Message.ISLAND_OWNER_NONE.getMessage(locale); String islandName = island != null ? island.getName().isEmpty() ? islandOwner : island.getName() : Message.ISLAND_NAME_NONE.getMessage(locale); return new ItemBuilder(buttonItem) .replaceAll("{0}", pagedObject.getName()) .replaceAll("{1}", islandOwner) .replaceAll("{2}", islandName) .asSkullOf(pagedObject) .build(pagedObject); } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), VisitorPagedObjectButton.class, VisitorPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryIconEditConfirmButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; public class WarpCategoryIconEditConfirmButton extends AbstractMenuViewButton> { private WarpCategoryIconEditConfirmButton(AbstractMenuTemplateButton> templateButton, AbstractIconProviderMenu.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); WarpCategory warpCategory = menuView.getIconProvider(); PluginEvent event = PluginEventsFactory.callIslandChangeWarpCategoryIconEvent( warpCategory.getIsland(), superiorPlayer, warpCategory, menuView.getIconTemplate().build()); if (event.isCancelled()) return; clickEvent.getWhoClicked().closeInventory(); Message.WARP_CATEGORY_ICON_UPDATED.send(superiorPlayer); warpCategory.setIcon(event.getArgs().icon); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder> { @Override public MenuTemplateButton> build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpCategoryIconEditConfirmButton.class, WarpCategoryIconEditConfirmButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageIconButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; public class WarpCategoryManageIconButton extends AbstractMenuViewButton { private WarpCategoryManageIconButton(AbstractMenuTemplateButton templateButton, MenuWarpCategoryManage.View menuView) { super(templateButton, menuView); } @Override public ItemStack createViewItem() { WarpCategory warpCategory = menuView.getWarpCategory(); ItemBuilder itemBuilder = new ItemBuilder(warpCategory.getRawIcon()); ItemStack buttonItem = super.createViewItem(); if (buttonItem != null && buttonItem.hasItemMeta()) { ItemMeta itemMeta = buttonItem.getItemMeta(); if (itemMeta.hasDisplayName()) itemBuilder.withName(itemMeta.getDisplayName()); if (itemMeta.hasLore()) itemBuilder.appendLore(itemMeta.getLore()); } return itemBuilder.build(warpCategory.getIsland().getOwner()); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); WarpCategory warpCategory = menuView.getWarpCategory(); if (clickEvent.getClick().isRightClick()) { menuView.setPreviousMove(false); plugin.getMenus().openWarpCategoryIconEdit(inventoryViewer, MenuViewWrapper.fromView(menuView), warpCategory); return; } Player player = (Player) clickEvent.getWhoClicked(); Message.WARP_CATEGORY_SLOT.send(player); menuView.closeView(); PlayerChat.listen(player, message -> { if (!message.equalsIgnoreCase("-cancel")) { int rowsSize = Menus.MENU_WARP_CATEGORIES.getRowsSize(); int slot; try { slot = Integer.parseInt(message); if (slot < 0 || slot >= rowsSize * 9) throw new IllegalArgumentException(); } catch (IllegalArgumentException ex) { Message.INVALID_SLOT.send(player, message); return true; } if (warpCategory.getIsland().getWarpCategory(slot) != null) { Message.WARP_CATEGORY_SLOT_ALREADY_TAKEN.send(player); return true; } PluginEvent event = PluginEventsFactory.callIslandChangeWarpCategorySlotEvent( warpCategory.getIsland(), inventoryViewer, warpCategory, slot, rowsSize * 9); if (!event.isCancelled()) { warpCategory.setSlot(event.getArgs().slot); Message.WARP_CATEGORY_SLOT_SUCCESS.send(player, event.getArgs().slot); GameSoundImpl.playSound(player, Menus.MENU_WARP_CATEGORY_MANAGE.getSuccessUpdateSound()); } } PlayerChat.remove(player); menuView.refreshView(); return true; }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpCategoryManageIconButton.class, WarpCategoryManageIconButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageRenameButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; public class WarpCategoryManageRenameButton extends AbstractMenuViewButton { private WarpCategoryManageRenameButton(AbstractMenuTemplateButton templateButton, MenuWarpCategoryManage.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); Message.WARP_CATEGORY_RENAME.send(player); menuView.closeView(); PlayerChat.listen(player, newName -> { WarpCategory warpCategory = menuView.getWarpCategory(); if (warpCategory.getIsland().getWarpCategory(warpCategory.getName()) != null && !newName.equalsIgnoreCase("-cancel")) { if (warpCategory.getIsland().getWarpCategory(newName) != null) { Message.WARP_CATEGORY_RENAME_ALREADY_EXIST.send(player); return true; } if (!IslandUtils.isWarpNameLengthValid(newName)) { Message.WARP_CATEGORY_NAME_TOO_LONG.send(player); return true; } PluginEvent event = PluginEventsFactory.callIslandRenameWarpCategoryEvent( warpCategory.getIsland(), plugin.getPlayers().getSuperiorPlayer(player), warpCategory, newName); if (!event.isCancelled()) { warpCategory.getIsland().renameCategory(warpCategory, event.getArgs().categoryName); Message.WARP_CATEGORY_RENAME_SUCCESS.send(player, event.getArgs().categoryName); GameSoundImpl.playSound(player, Menus.MENU_WARP_CATEGORY_MANAGE.getSuccessUpdateSound()); } } PlayerChat.remove(player); menuView.refreshView(); return true; }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpCategoryManageRenameButton.class, WarpCategoryManageRenameButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageWarpsButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import org.bukkit.event.inventory.InventoryClickEvent; public class WarpCategoryManageWarpsButton extends AbstractMenuViewButton { private WarpCategoryManageWarpsButton(AbstractMenuTemplateButton templateButton, MenuWarpCategoryManage.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); plugin.getMenus().openWarps(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getWarpCategory()); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpCategoryManageWarpsButton.class, WarpCategoryManageWarpsButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategories; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class WarpCategoryPagedObjectButton extends AbstractPagedMenuButton { private WarpCategoryPagedObjectButton(MenuTemplateButton templateButton, MenuWarpCategories.View menuView) { super(templateButton, menuView); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { if (pagedObject == null) { return TemplateItem.AIR.build(); } SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island island = menuView.getIsland(); boolean isMember = island.isMember(inventoryViewer); long accessAmount = pagedObject.getWarps().stream().filter( islandWarp -> isMember || !islandWarp.hasPrivateFlag() ).count(); if (accessAmount == 0) return null; if (!menuView.hasManagePerms() || Menus.MENU_WARP_CATEGORIES.getEditLore().isEmpty()) { return pagedObject.getIcon(island.getOwner()); } else { return new ItemBuilder(pagedObject.getIcon(null)) .appendLore(Menus.MENU_WARP_CATEGORIES.getEditLore()) .build(island.getOwner()); } } @Override public void onButtonClick(InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); if (menuView.hasManagePerms() && clickEvent.getClick().isRightClick()) { plugin.getMenus().openWarpCategoryManage(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject); } else { plugin.getMenus().openWarps(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject); } } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), WarpCategoryPagedObjectButton.class, WarpCategoryPagedObjectButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpIconEditConfirmButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; public class WarpIconEditConfirmButton extends AbstractMenuViewButton> { private WarpIconEditConfirmButton(AbstractMenuTemplateButton> templateButton, AbstractIconProviderMenu.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); IslandWarp islandWarp = menuView.getIconProvider(); PluginEvent event = PluginEventsFactory.callIslandChangeWarpIconEvent( islandWarp.getIsland(), inventoryViewer, islandWarp, menuView.getIconTemplate().build()); if (event.isCancelled()) return; clickEvent.getWhoClicked().closeInventory(); Message.WARP_ICON_UPDATED.send(inventoryViewer); islandWarp.setIcon(event.getArgs().icon); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder> { @Override public MenuTemplateButton> build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpIconEditConfirmButton.class, WarpIconEditConfirmButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageIconButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.island.warp.WarpIcons; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; public class WarpManageIconButton extends AbstractMenuViewButton { private WarpManageIconButton(AbstractMenuTemplateButton templateButton, MenuWarpManage.View menuView) { super(templateButton, menuView); } @Override public ItemStack createViewItem() { IslandWarp islandWarp = menuView.getIslandWarp(); ItemBuilder itemBuilder = islandWarp.getRawIcon() == null ? WarpIcons.DEFAULT_WARP_ICON.getBuilder() : new ItemBuilder(islandWarp.getRawIcon()); ItemStack buttonItem = super.createViewItem(); if (buttonItem != null && buttonItem.hasItemMeta()) { ItemMeta itemMeta = buttonItem.getItemMeta(); if (itemMeta.hasDisplayName()) itemBuilder.withName(itemMeta.getDisplayName()); if (itemMeta.hasLore()) itemBuilder.appendLore(itemMeta.getLore()); } return itemBuilder.build(menuView.getInventoryViewer()); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { IslandWarp islandWarp = menuView.getIslandWarp(); menuView.setPreviousMove(false); plugin.getMenus().openWarpIconEdit(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), islandWarp); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpManageIconButton.class, WarpManageIconButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.warp.SignWarp; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.Objects; public class WarpManageLocationButton extends AbstractMenuViewButton { private WarpManageLocationButton(AbstractMenuTemplateButton templateButton, MenuWarpManage.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); IslandWarp islandWarp = menuView.getIslandWarp(); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location playerLocation = player.getLocation(wrapper.getHandle()); if (!islandWarp.getIsland().isInsideRange(playerLocation)) { Message.SET_WARP_OUTSIDE.send(player); return; } PluginEvent event = PluginEventsFactory.callIslandChangeWarpLocationEvent( islandWarp.getIsland(), player, islandWarp, playerLocation); if (event.isCancelled()) return; Message.WARP_LOCATION_UPDATE.send(player); WorldPosition warpPosition = islandWarp.getPosition(); WorldInfo warpWorld = plugin.getGrid().getIslandsWorldInfo(islandWarp.getIsland(), islandWarp.getPositionDimension()); if (!isSameLocation(event.getArgs().location, warpWorld, warpPosition)) { ChunksProvider.loadChunk(ChunkPosition.of(warpWorld, warpPosition), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { SignWarp.trySignWarpBreak(islandWarp, player); }); } islandWarp.setLocation(event.getArgs().location); GameSoundImpl.playSound(player, Menus.MENU_WARP_MANAGE.getSuccessUpdateSound()); } } private static boolean isSameLocation(Location location, WorldInfo worldInfo, WorldPosition worldPosition) { if (location.getX() != worldPosition.getX() || location.getY() != worldPosition.getY() || location.getZ() != worldPosition.getZ() || location.getYaw() != worldPosition.getYaw() || location.getPitch() != worldPosition.getPitch()) return false; String worldName = LazyWorldLocation.getWorldName(location); return Objects.equals(worldName, worldInfo.getName()); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpManageLocationButton.class, WarpManageLocationButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManagePrivateButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; public class WarpManagePrivateButton extends AbstractMenuViewButton { private WarpManagePrivateButton(AbstractMenuTemplateButton templateButton, MenuWarpManage.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { IslandWarp islandWarp = menuView.getIslandWarp(); boolean openToPublic = islandWarp.hasPrivateFlag(); SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); if (openToPublic ? !PluginEventsFactory.callIslandOpenWarpEvent(islandWarp.getIsland(), superiorPlayer, islandWarp) : !PluginEventsFactory.callIslandCloseWarpEvent(islandWarp.getIsland(), superiorPlayer, islandWarp)) return; islandWarp.setPrivateFlag(!openToPublic); if (openToPublic) Message.WARP_PUBLIC_UPDATE.send(superiorPlayer); else Message.WARP_PRIVATE_UPDATE.send(superiorPlayer); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpManagePrivateButton.class, WarpManagePrivateButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageRenameButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; public class WarpManageRenameButton extends AbstractMenuViewButton { private WarpManageRenameButton(AbstractMenuTemplateButton templateButton, MenuWarpManage.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); Message.WARP_RENAME.send(player); menuView.closeView(); PlayerChat.listen(player, newName -> { IslandWarp islandWarp = menuView.getIslandWarp(); if (!newName.equalsIgnoreCase("-cancel")) { if (islandWarp.getIsland().getWarp(newName) != null) { Message.WARP_RENAME_ALREADY_EXIST.send(player); return true; } if (!IslandUtils.isWarpNameLengthValid(newName)) { Message.WARP_NAME_TOO_LONG.send(player); return true; } PluginEvent event = PluginEventsFactory.callIslandRenameWarpEvent( islandWarp.getIsland(), player, islandWarp, newName); if (!event.isCancelled()) { islandWarp.getIsland().renameWarp(islandWarp, event.getArgs().warpName); Message.WARP_RENAME_SUCCESS.send(player, event.getArgs().warpName); GameSoundImpl.playSound(player, Menus.MENU_WARP_MANAGE.getSuccessUpdateSound()); } } PlayerChat.remove(player); menuView.refreshView(); return true; }); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { @Override public MenuTemplateButton build() { return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, WarpManageRenameButton.class, WarpManageRenameButton::new); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarps; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.Location; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; public class WarpPagedObjectButton extends AbstractPagedMenuButton { private WarpPagedObjectButton(MenuTemplateButton templateButton, MenuWarps.View menuView) { super(templateButton, menuView); } @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); if (menuView.hasManagePerms() && clickEvent.getClick().isRightClick()) { menuView.setPreviousMove(false); plugin.getMenus().openWarpManage(clickedPlayer, MenuViewWrapper.fromView(menuView), pagedObject); } else { MenuActions.simulateWarpsClick(clickedPlayer, menuView.getWarpCategory().getIsland(), pagedObject); BukkitExecutor.sync(() -> menuView.setPreviousMove(false), 1L); } } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { SuperiorPlayer superiorPlayer = menuView.getInventoryViewer(); ItemStack icon = pagedObject.getIcon(superiorPlayer); ItemBuilder itemBuilder = new ItemBuilder(icon == null ? buttonItem : icon); if (menuView.hasManagePerms() && !Menus.MENU_WARPS.getEditLore().isEmpty()) itemBuilder.appendLore(Menus.MENU_WARPS.getEditLore()); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { return itemBuilder.replaceAll("{0}", pagedObject.getName()) .replaceAll("{1}", Formatters.LOCATION_FORMATTER.format(pagedObject.getLocation(wrapper.getHandle()))) .replaceAll("{2}", pagedObject.hasPrivateFlag() ? ensureNotNull(Message.ISLAND_WARP_PRIVATE.getMessage(superiorPlayer.getUserLocale())) : ensureNotNull(Message.ISLAND_WARP_PUBLIC.getMessage(superiorPlayer.getUserLocale()))) .build(superiorPlayer); } } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { @Override public PagedMenuTemplateButton build() { return new PagedMenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, nullItem, getButtonIndex(), WarpPagedObjectButton.class, WarpPagedObjectButton::new); } } private static String ensureNotNull(String check) { return check == null ? "" : check; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/converter/MenuConverter.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.converter; import com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl; import org.bukkit.configuration.ConfigurationSection; import java.util.ArrayList; import java.util.List; public class MenuConverter { private MenuConverter() { } public static int convertFillItems(ConfigurationSection fillItemsSection, int charCounter, char[] patternChars, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) { for (String itemFill : fillItemsSection.getKeys(false)) { ConfigurationSection section = fillItemsSection.getConfigurationSection(itemFill); String[] slots = section.getString("slots").split(","); section.set("slots", null); char itemChar = RegularMenuLayoutImpl.BUTTON_SYMBOLS[charCounter++]; for (String slot : slots) { patternChars[Integer.parseInt(slot)] = itemChar; } convertItem(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection); } return charCounter; } public static void convertItem(ConfigurationSection section, char[] patternChars, char itemChar, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) { if (section.contains("slot")) { patternChars[section.getInt("slot")] = itemChar; section.set("slot", null); } soundsSection.set(itemChar + "", section.get("sound")); section.set("sound", null); commandsSection.set(itemChar + "", section.get("commands")); section.set("commands", null); itemsSection.set(itemChar + "", section); } public static void convertItemAccess(ConfigurationSection section, char[] patternChars, char itemChar, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) { patternChars[section.getInt("slot")] = itemChar; section.set("slot", null); section.set("access", section.getConfigurationSection("has-access-item")); soundsSection.set(itemChar + ".access", section.get("has-access-item.sound")); commandsSection.set(itemChar + ".access", section.get("has-access-item.commands")); section.set("has-access-item.sound", null); section.set("has-access-item.commands", null); section.set("has-access-item", null); section.set("no-access", section.getConfigurationSection("no-access-item")); soundsSection.set(itemChar + ".no-access", section.get("no-access-item.sound")); commandsSection.set(itemChar + ".no-access", section.get("no-access-item.commands")); section.set("no-access-item.sound", null); section.set("no-access-item.commands", null); section.set("no-access-item", null); itemsSection.set(itemChar + "", section); } public static void convertPagedButtons(ConfigurationSection section, ConfigurationSection newMenu, char[] patternChars, char slotsChar, char previousChar, char currentChar, char nextChar, ConfigurationSection itemsSection, ConfigurationSection commandsSection, ConfigurationSection soundsSection) { convertPagedButtons(section, null, newMenu, patternChars, slotsChar, previousChar, currentChar, nextChar, itemsSection, commandsSection, soundsSection); } 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) { String slots = itemSection != null ? itemSection.getString("slots") : section.getString("slots"); if (slots != null) { for (String slot : slots.split(",")) patternChars[Integer.parseInt(slot)] = slotsChar; if (itemSection != null) itemSection.set("slots", null); else section.set("slots", null); } if (itemSection != null) { MenuConverter.convertItem(itemSection, patternChars, slotsChar, itemsSection, commandsSection, soundsSection); } MenuConverter.convertItem(section.getConfigurationSection("previous-page"), patternChars, previousChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(section.getConfigurationSection("current-page"), patternChars, currentChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(section.getConfigurationSection("next-page"), patternChars, nextChar, itemsSection, commandsSection, soundsSection); newMenu.set("slots", slotsChar + ""); newMenu.set("previous-page", previousChar + ""); newMenu.set("current-page", currentChar + ""); newMenu.set("next-page", nextChar + ""); } public static List buildPattern(int size, char[] patternChars, char replaceChar) { int lineLength = patternChars.length == 5 ? 5 : 9; int charCount = 0; List pattern = new ArrayList<>(size); StringBuilder line = new StringBuilder(); for (char ch : patternChars) { charCount++; line.append(" ").append(ch); if (charCount == lineLength) { charCount = 0; pattern.add(line.substring(1).replace('\n', replaceChar)); line = new StringBuilder(); } } return pattern; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankLogsPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankLogsSortButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.UUID; public class MenuBankLogs extends AbstractPagedMenu { private static final UUID CONSOLE_UUID = new UUID(0, 0); private MenuBankLogs(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_BANK_LOGS, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { this.refreshViews(view -> Objects.equals(view.island, island)); } @Nullable public static MenuBankLogs createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("bank-logs.yml", MenuBankLogs::convertOldGUI, new BankLogsPagedObjectButton.Builder()); if (menuParseResult == null) return null; MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "time-sort", menuPatternSlots), new BankLogsSortButton.Builder().setSortType(BankLogsSortButton.SortType.TIME)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "money-sort", menuPatternSlots), new BankLogsSortButton.Builder().setSortType(BankLogsSortButton.SortType.MONEY)); return new MenuBankLogs(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private Comparator sorting; private UUID filteredPlayer; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return this.island; } @Override public SuperiorPlayer getSuperiorPlayer() { return this.filteredPlayer == null || this.filteredPlayer.equals(CONSOLE_UUID) ? null : plugin.getPlayers().getSuperiorPlayer(filteredPlayer); } public void setSorting(Comparator sorting) { this.sorting = sorting; } public void setFilteredPlayer(UUID filteredPlayer) { this.filteredPlayer = filteredPlayer == null ? CONSOLE_UUID : filteredPlayer; this.setCurrentPage(1); } @Override public String replaceTitle(String title) { return title.replace("{0}", getFilteredPlayerName(filteredPlayer)); } @Override protected List requestObjects() { List transactions = getTransactions(); if (sorting == null) { return transactions; } transactions = new LinkedList<>(transactions); transactions.sort(sorting); return Collections.unmodifiableList(transactions); } private List getTransactions() { if (filteredPlayer == null) { return island.getIslandBank().getAllTransactions(); } else if (filteredPlayer.equals(CONSOLE_UUID)) { return island.getIslandBank().getConsoleTransactions(); } else { return island.getIslandBank().getTransactions(plugin.getPlayers().getSuperiorPlayer(filteredPlayer)); } } private static String getFilteredPlayerName(UUID filteredPlayer) { if (filteredPlayer == null) { return ""; } else if (filteredPlayer.equals(CONSOLE_UUID)) { return "Console"; } else { return plugin.getPlayers().getSuperiorPlayer(filteredPlayer).getName(); } } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/panel-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("members-panel.title")); int size = cfg.getInt("members-panel.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("members-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("members-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertPagedButtons(cfg.getConfigurationSection("members-panel"), cfg.getConfigurationSection("members-panel.member-item"), newMenu, patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], itemsSection, commandsSection, soundsSection); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BiomeButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.block.Biome; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.Locale; public class MenuBiomes extends AbstractMenu { private final boolean currentBiomeGlow; private MenuBiomes(MenuParseResult parseResult, boolean currentBiomeGlow) { super(MenuIdentifiers.MENU_BIOMES, parseResult); this.currentBiomeGlow = currentBiomeGlow; } public boolean isCurrentBiomeGlow() { return currentBiomeGlow; } @Override protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new IslandMenuView(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuBiomes createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("biomes.yml", MenuBiomes::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); boolean shouldCurrentBiomeGlow = cfg.getBoolean("current-biome-glow", false); if (cfg.isConfigurationSection("items")) { for (String itemSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemSection = cfg.getConfigurationSection("items." + itemSectionName); if (!itemSection.isString("biome")) continue; String biomeName = itemSection.getString("biome"); Biome biome = plugin.getNMSAlgorithms().getBiome(biomeName);; if (biome == null) { Log.warnFromFile("biomes.yml", "Biome '", biomeName, "' is not valid, skipping..."); continue; } ConfigurationSection soundSection = cfg.getConfigurationSection("sounds." + itemSectionName); ConfigurationSection commandSection = cfg.getConfigurationSection("commands." + itemSectionName); BiomeButton.Builder buttonBuilder = new BiomeButton.Builder(biome); if (itemSection.isConfigurationSection("access")) { buttonBuilder.setAccessItem(MenuParserImpl.getInstance().getItemStack("menus/biomes.yml", itemSection.getConfigurationSection("access"))); } if (itemSection.isConfigurationSection("no-access")) { buttonBuilder.setNoAccessItem(MenuParserImpl.getInstance().getItemStack("menus/biomes.yml", itemSection.getConfigurationSection("no-access"))); } if (soundSection != null) { if (soundSection.isConfigurationSection("access")) { buttonBuilder.setAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("access"))); } if (soundSection.isConfigurationSection("no-access")) { buttonBuilder.setNoAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("no-access"))); } } if (commandSection != null) { if (commandSection.isList("access")) { buttonBuilder.setAccessCommands(commandSection.getStringList("access")); } if (commandSection.isList("no-access")) { buttonBuilder.setNoAccessCommands(commandSection.getStringList("no-access")); } } patternBuilder.mapButtons(menuPatternSlots.getSlots(itemSectionName), buttonBuilder); } } return new MenuBiomes(menuParseResult, shouldCurrentBiomeGlow); } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/biomes-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("biomes-gui.title")); int size = cfg.getInt("biomes-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("biomes-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("biomes-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } if (cfg.isConfigurationSection("biomes-gui.biomes")) { for (String biomeName : cfg.getConfigurationSection("biomes-gui.biomes").getKeys(false)) { ConfigurationSection section = cfg.getConfigurationSection("biomes-gui.biomes." + biomeName); char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; section.set("biome", biomeName.toUpperCase(Locale.ENGLISH)); MenuConverter.convertItemAccess(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection); } } newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBorderColor.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BorderColorButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BorderColorToggleButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; public class MenuBorderColor extends AbstractMenu { private MenuBorderColor(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_BORDER_COLOR, parseResult); } @Override protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused, @Nullable MenuView previousMenuView) { return new BaseMenuView(superiorPlayer, previousMenuView, this); } @Nullable public static MenuBorderColor createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("border-color.yml", MenuBorderColor::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); if (cfg.isConfigurationSection("items")) { for (String itemsSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemsSection = cfg.getConfigurationSection("items." + itemsSectionName); if (!itemsSection.isConfigurationSection("enable-border") || !itemsSection.isConfigurationSection("disable-border")) continue; patternBuilder.setButtons(menuPatternSlots.getSlots(itemsSectionName), new BorderColorToggleButton.Builder() .setEnabledItem(MenuParserImpl.getInstance().getItemStack("menus/border-color.yml", itemsSection.getConfigurationSection("disable-border"))) .setDisabledItem(MenuParserImpl.getInstance().getItemStack("menus/border-color.yml", itemsSection.getConfigurationSection("enable-border"))) .build()); } } patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "green-color", menuPatternSlots), new BorderColorButton.Builder().setBorderColor(BorderColor.GREEN)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "red-color", menuPatternSlots), new BorderColorButton.Builder().setBorderColor(BorderColor.RED)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "blue-color", menuPatternSlots), new BorderColorButton.Builder().setBorderColor(BorderColor.BLUE)); return new MenuBorderColor(menuParseResult); } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/border-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("border-gui.title")); newMenu.set("type", "HOPPER"); char[] patternChars = new char[5]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("border-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("border-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char greenChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char blueChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char redChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertItem(cfg.getConfigurationSection("border-gui.green_color"), patternChars, greenChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("border-gui.blue_color"), patternChars, blueChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("border-gui.red_color"), patternChars, redChar, itemsSection, commandsSection, soundsSection); newMenu.set("green-color", greenChar + ""); newMenu.set("red-color", redChar + ""); newMenu.set("blue-color", blueChar + ""); newMenu.set("pattern", MenuConverter.buildPattern(1, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmBan.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BanButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.file.YamlConfiguration; public class MenuConfirmBan extends AbstractMenu { private MenuConfirmBan(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_CONFIRM_BAN, parseResult); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuConfirmBan createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("confirm-ban.yml", null); if (menuParseResult == null) return null; MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "confirm", menuPatternSlots), new BanButton.Builder().setBanPlayer(true)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "cancel", menuPatternSlots), new BanButton.Builder()); return new MenuConfirmBan(menuParseResult); } public static class Args extends IslandViewArgs { private final SuperiorPlayer targetPlayer; public Args(Island island, SuperiorPlayer targetPlayer) { super(island); this.targetPlayer = targetPlayer; } } public static class View extends AbstractMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private SuperiorPlayer targetPlayer; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); this.targetPlayer = args.targetPlayer; } @Override public Island getIsland() { return island; } @Override public SuperiorPlayer getSuperiorPlayer() { return targetPlayer; } public void setTargetPlayer(SuperiorPlayer targetPlayer) { this.targetPlayer = targetPlayer; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.DisbandButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; public class MenuConfirmDisband extends AbstractMenu { private MenuConfirmDisband(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_CONFIRM_DISBAND, parseResult); } @Override protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new IslandMenuView(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuConfirmDisband createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("confirm-disband.yml", MenuConfirmDisband::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "confirm", menuPatternSlots), new DisbandButton.Builder().setDisbandIsland(true)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "cancel", menuPatternSlots), new DisbandButton.Builder()); return new MenuConfirmDisband(menuParseResult); } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/confirm-disband.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("disband-gui.title")); newMenu.set("type", "HOPPER"); char[] patternChars = new char[5]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("disband-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("disband-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char confirmChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char cancelChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertItem(cfg.getConfigurationSection("disband-gui.confirm"), patternChars, confirmChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("disband-gui.cancel"), patternChars, cancelChar, itemsSection, commandsSection, soundsSection); newMenu.set("confirm", confirmChar + ""); newMenu.set("cancel", cancelChar + ""); newMenu.set("pattern", MenuConverter.buildPattern(1, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmKick.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.KickButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.file.YamlConfiguration; public class MenuConfirmKick extends AbstractMenu { private MenuConfirmKick(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_CONFIRM_KICK, parseResult); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuConfirmKick createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("confirm-kick.yml", null); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "confirm", menuPatternSlots), new KickButton.Builder().setKickPlayer(true)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "cancel", menuPatternSlots), new KickButton.Builder()); return new MenuConfirmKick(menuParseResult); } public static class Args extends IslandViewArgs { private final SuperiorPlayer targetPlayer; public Args(Island island, SuperiorPlayer targetPlayer) { super(island); this.targetPlayer = targetPlayer; } } public static class View extends AbstractMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private SuperiorPlayer targetPlayer; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); this.targetPlayer = args.targetPlayer; } @Override public Island getIsland() { return island; } @Override public SuperiorPlayer getSuperiorPlayer() { return targetPlayer; } public void setTargetPlayer(SuperiorPlayer targetPlayer) { this.targetPlayer = targetPlayer; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmLeave.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.LeaveButton; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import org.bukkit.configuration.file.YamlConfiguration; public class MenuConfirmLeave extends AbstractMenu { private MenuConfirmLeave(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_CONFIRM_LEAVE, parseResult); } @Override protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused, @Nullable MenuView previousMenuView) { return new BaseMenuView(superiorPlayer, previousMenuView, this); } @Nullable public static MenuConfirmLeave createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("confirm-leave.yml", null); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "confirm", menuPatternSlots), new LeaveButton.Builder().setLeaveIsland(true)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "cancel", menuPatternSlots), new LeaveButton.Builder()); return new MenuConfirmLeave(menuParseResult); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmTransfer.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.TransferButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.file.YamlConfiguration; public class MenuConfirmTransfer extends AbstractMenu { private MenuConfirmTransfer(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_CONFIRM_TRANSFER, parseResult); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuConfirmTransfer createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("confirm-transfer.yml", null); if (menuParseResult == null) return null; MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "confirm", menuPatternSlots), new TransferButton.Builder().setNewOwner(true)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "cancel", menuPatternSlots), new TransferButton.Builder()); return new MenuConfirmTransfer(menuParseResult); } public static class Args extends IslandViewArgs { private final SuperiorPlayer targetPlayer; public Args(Island island, SuperiorPlayer targetPlayer) { super(island); this.targetPlayer = targetPlayer; } } public static class View extends AbstractMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private SuperiorPlayer targetPlayer; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); this.targetPlayer = args.targetPlayer; } @Override public Island getIsland() { return island; } @Override public SuperiorPlayer getSuperiorPlayer() { return targetPlayer; } public void setTargetPlayer(SuperiorPlayer targetPlayer) { this.targetPlayer = targetPlayer; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.ControlPanelButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; public class MenuControlPanel extends AbstractMenu { private MenuControlPanel(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_CONTROL_PANEL, parseResult); } @Override protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new IslandMenuView(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuControlPanel createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("control-panel.yml", MenuControlPanel::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "members", menuPatternSlots), new ControlPanelButton.Builder().setAction(ControlPanelButton.ControlPanelAction.OPEN_MEMBERS)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "settings", menuPatternSlots), new ControlPanelButton.Builder().setAction(ControlPanelButton.ControlPanelAction.OPEN_SETTINGS)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "visitors", menuPatternSlots), new ControlPanelButton.Builder().setAction(ControlPanelButton.ControlPanelAction.OPEN_VISITORS)); return new MenuControlPanel(menuParseResult); } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/panel-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("main-panel.title")); int size = cfg.getInt("main-panel.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("main-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("main-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char membersChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char settingsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char visitorsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertItem(cfg.getConfigurationSection("main-panel.members"), patternChars, membersChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("main-panel.settings"), patternChars, settingsChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("main-panel.visitors"), patternChars, visitorsChar, itemsSection, commandsSection, soundsSection); newMenu.set("members", membersChar + ""); newMenu.set("settings", settingsChar + ""); newMenu.set("visitors", visitorsChar + ""); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuCoops.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.CoopsPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import java.util.List; public class MenuCoops extends AbstractPagedMenu { private MenuCoops(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_COOPS, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuCoops createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("coops.yml", null, new CoopsPagedObjectButton.Builder()); return menuParseResult == null ? null : new MenuCoops(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return this.island; } @Override public String replaceTitle(String title) { return title.replace("{0}", String.valueOf(this.island.getCoopPlayers().size())) .replace("{1}", String.valueOf(this.island.getCoopLimit())); } @Override protected List requestObjects() { return island.getCoopPlayers(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuCounts.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.CountsPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.Material; import java.math.BigInteger; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.function.Function; public class MenuCounts extends AbstractPagedMenu { private static final Comparator BLOCK_COUNT_COMPARATOR = (o1, o2) -> { Material firstMaterial = getMaterialFromKey(o1.getBlockKey()); Material secondMaterial = getMaterialFromKey(o2.getBlockKey()); int compare = plugin.getNMSAlgorithms().compareMaterials(firstMaterial, secondMaterial); return compare != 0 ? compare : o1.getBlockKey().compareTo(o2.getBlockKey()); }; private static final Function, MenuCounts.BlockCount> BLOCK_COUNT_MAPPER = entry -> new MenuCounts.BlockCount(entry.getKey(), entry.getValue()); private MenuCounts(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_COUNTS, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuCounts createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("counts.yml", null, new CountsPagedObjectButton.Builder()); return menuParseResult == null ? null : new MenuCounts(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return this.island; } @Override protected List requestObjects() { return new SequentialListBuilder() .sorted(BLOCK_COUNT_COMPARATOR) .build(island.getBlockCountsAsBigInteger().entrySet(), BLOCK_COUNT_MAPPER); } } private static Material getMaterialFromKey(Key key) { if (key instanceof MaterialKey) return ((MaterialKey) key).getMaterial(); return EnumHelper.getEnum(Material.class, key.getGlobalKey(), "BEDROCK"); } public static class BlockCount { private final Key blockKey; private final BigInteger amount; public BlockCount(Key blockKey, BigInteger amount) { this.blockKey = blockKey; this.amount = amount; } public Key getBlockKey() { return blockKey; } public BigInteger getAmount() { return amount; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.GlobalWarpsPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.function.Predicate; public class MenuGlobalWarps extends AbstractPagedMenu { private final boolean visitorWarps; private MenuGlobalWarps(MenuParseResult parseResult, boolean visitorWarps) { super(MenuIdentifiers.MENU_GLOBAL_WARPS, parseResult, false); this.visitorWarps = visitorWarps; } public boolean isVisitorWarps() { return visitorWarps; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this); } @Nullable public static MenuGlobalWarps createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("global-warps.yml", MenuGlobalWarps::convertOldGUI, new GlobalWarpsPagedObjectButton.Builder()); if (menuParseResult == null) return null; MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); PagedMenuLayout.Builder patternBuilder = (PagedMenuLayout.Builder) menuParseResult.getLayoutBuilder(); boolean visitorWarps = cfg.getBoolean("visitor-warps", false); List slots = new LinkedList<>(); if (cfg.isString("warps")) slots.addAll(MenuParserImpl.getInstance().parseButtonSlots(cfg, "warps", menuPatternSlots)); if (cfg.isString("slots")) slots.addAll(MenuParserImpl.getInstance().parseButtonSlots(cfg, "slots", menuPatternSlots)); if (slots.isEmpty()) slots.add(-1); patternBuilder.setPagedObjectSlots(slots, new GlobalWarpsPagedObjectButton.Builder()); return new MenuGlobalWarps(menuParseResult, visitorWarps); } public class View extends AbstractPagedMenuView { View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu) { super(inventoryViewer, previousMenuView, menu); } @Override protected List requestObjects() { return new SequentialListBuilder() .sorted(SortingTypes.getGlobalWarpsSorting().getComparator()) .filter(ISLANDS_FILTER) .build(plugin.getGrid().getIslands()); } private final Predicate ISLANDS_FILTER = island -> { if (visitorWarps) return island.getVisitorsPosition(null /* unused */) != null; else if (island.equals(getInventoryViewer().getIsland())) return !island.getIslandWarps().isEmpty(); else return island.getIslandWarps().values().stream().anyMatch(islandWarp -> !islandWarp.hasPrivateFlag()); }; } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/warps-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("global-gui.title")); int size = cfg.getInt("global-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("global-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("global-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertPagedButtons(cfg.getConfigurationSection("global-gui"), cfg.getConfigurationSection("global-gui.warp-item"), newMenu, patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], itemsSection, commandsSection, soundsSection); newMenu.set("visitor-warps", cfg.getConfigurationSection("global-gui.visitor-warps")); newMenu.set("warps", newMenu.getString("slots")); newMenu.set("slots", null); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankBalanceButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankCustomDepositButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankCustomWithdrawButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankDepositButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankWithdrawButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.OpenBankLogsButton; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.file.YamlConfiguration; import java.util.List; public class MenuIslandBank extends AbstractMenu { private MenuIslandBank(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_BANK, parseResult); } @Override protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new IslandMenuView(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.getIsland().equals(island)); } @Nullable public static MenuIslandBank createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("island-bank.yml", null); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); if (cfg.isConfigurationSection("items")) { for (String itemChar : cfg.getConfigurationSection("items").getKeys(false)) { if (cfg.isConfigurationSection("items." + itemChar + ".bank-action")) { List slots = menuPatternSlots.getSlots(itemChar); if (slots.isEmpty()) { continue; } GameSound successSound = MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection("sounds." + itemChar + ".success-sound")); GameSound failSound = MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection("sounds." + itemChar + ".fail-sound")); if (cfg.isDouble("items." + itemChar + ".bank-action.withdraw")) { double withdrawPercentage = cfg.getDouble("items." + itemChar + ".bank-action.withdraw"); if (withdrawPercentage <= 0) { patternBuilder.mapButtons(slots, new BankCustomWithdrawButton.Builder() .setFailSound(failSound).setSuccessSound(successSound)); } else { patternBuilder.mapButtons(slots, new BankWithdrawButton.Builder(withdrawPercentage) .setFailSound(failSound).setSuccessSound(successSound)); } } else if (cfg.isList("items." + itemChar + ".bank-action.withdraw")) { List withdrawCommands = cfg.getStringList("items." + itemChar + ".bank-action.withdraw"); patternBuilder.mapButtons(slots, new BankWithdrawButton.Builder(withdrawCommands) .setFailSound(failSound).setSuccessSound(successSound)); } else if (cfg.isDouble("items." + itemChar + ".bank-action.deposit")) { double depositPercentage = cfg.getDouble("items." + itemChar + ".bank-action.deposit"); if (depositPercentage <= 0) { patternBuilder.mapButtons(slots, new BankCustomDepositButton.Builder() .setFailSound(failSound).setSuccessSound(successSound)); } else { patternBuilder.mapButtons(slots, new BankDepositButton.Builder(depositPercentage) .setFailSound(failSound).setSuccessSound(successSound)); } } } } } patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "balance", menuPatternSlots), new BankBalanceButton.Builder()); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "logs", menuPatternSlots), new OpenBankLogsButton.Builder()); return new MenuIslandBank(menuParseResult); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BannedPlayersPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import java.util.List; public class MenuIslandBannedPlayers extends AbstractPagedMenu { private MenuIslandBannedPlayers(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_BANNED_PLAYERS, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuIslandBannedPlayers createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("banned-players.yml", null, new BannedPlayersPagedObjectButton.Builder()); return menuParseResult == null ? null : new MenuIslandBannedPlayers(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return this.island; } @Override public String replaceTitle(String title) { return title.replace("{0}", String.valueOf(island.getBannedPlayers().size())); } @Override protected List requestObjects() { return island.getBannedPlayers(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandChestPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.util.Arrays; import java.util.List; public class MenuIslandChest extends AbstractPagedMenu { private MenuIslandChest(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_CHEST, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuIslandChest createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("island-chest.yml", null, new IslandChestPagedObjectButton.Builder()); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); PagedMenuLayoutImpl.Builder patternBuilder = (PagedMenuLayoutImpl.Builder) menuParseResult.getLayoutBuilder(); if (cfg.isString("slots")) { for (char slotChar : cfg.getString("slots", "").toCharArray()) { List slots = menuPatternSlots.getSlots(slotChar); ConfigurationSection validPageSection = cfg.getConfigurationSection("items." + slotChar + ".valid-page"); ConfigurationSection invalidPageSection = cfg.getConfigurationSection("items." + slotChar + ".invalid-page"); if (validPageSection == null) { Log.warnFromFile("island-chest.yml", "The slot char ", slotChar, " is missing the valid-page section."); continue; } if (invalidPageSection == null) { Log.warnFromFile("island-chest.yml", "&cThe slot char ", slotChar, " is missing the invalid-page section."); continue; } IslandChestPagedObjectButton.Builder buttonBuilder = new IslandChestPagedObjectButton.Builder(); buttonBuilder.setButtonItem(MenuParserImpl.getInstance().getItemStack("menus/island-chest.yml", validPageSection)); buttonBuilder.setNullItem(MenuParserImpl.getInstance().getItemStack("menus/island-chest.yml", invalidPageSection)); patternBuilder.mapButtons(slots, buttonBuilder); } } return new MenuIslandChest(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return this.island; } @Override protected List requestObjects() { return new SequentialListBuilder() .build(Arrays.asList(island.getChest())); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import org.bukkit.block.Biome; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.math.BigDecimal; import java.util.Arrays; import java.util.Locale; public class MenuIslandCreation extends AbstractMenu { private MenuIslandCreation(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_CREATION, parseResult); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuIslandCreation createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("island-creation.yml", MenuIslandCreation::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); if (cfg.isConfigurationSection("items")) { for (String itemSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemSection = cfg.getConfigurationSection("items." + itemSectionName); if (!itemSection.isString("schematic")) continue; Schematic schematic = plugin.getSchematics().getSchematic(itemSection.getString("schematic")); if (schematic == null) { Log.warnFromFile("island-creation.yml", "Invalid schematic for item ", itemSectionName); continue; } IslandCreationButton.Builder buttonBuilder = new IslandCreationButton.Builder(schematic); { String biomeName = itemSection.getString("biome"); if (biomeName != null) { Biome biome = plugin.getNMSAlgorithms().getBiome(biomeName); if (biome == null) { Log.warnFromFile("island-creation.yml", "Invalid biome name for item ", itemSectionName, ": ", biomeName); continue; } buttonBuilder.setBiome(biome); } } { Object bonusWorth = itemSection.get("bonus", itemSection.get("bonus-worth", 0D)); if (bonusWorth instanceof Double) { buttonBuilder.setBonusWorth(BigDecimal.valueOf((double) bonusWorth)); } else if (bonusWorth instanceof String) { buttonBuilder.setBonusWorth(new BigDecimal((String) bonusWorth)); } } { Object bonusLevel = itemSection.get("bonus-level", 0D); if (bonusLevel instanceof Double) { buttonBuilder.setBonusLevel(BigDecimal.valueOf((double) bonusLevel)); } else if (bonusLevel instanceof String) { buttonBuilder.setBonusLevel(new BigDecimal((String) bonusLevel)); } } ConfigurationSection soundSection = cfg.getConfigurationSection("sounds." + itemSectionName); if (soundSection != null) { buttonBuilder.setAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("access"))); buttonBuilder.setNoAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("no-access"))); } ConfigurationSection commandSection = cfg.getConfigurationSection("commands." + itemSectionName); if (commandSection != null) { buttonBuilder.setAccessCommands(commandSection.getStringList("access")); buttonBuilder.setNoAccessCommands(commandSection.getStringList("no-access")); } buttonBuilder.setOffset(itemSection.getBoolean("offset", false)); if (itemSection.isString("spawn-offset")) buttonBuilder.setSpawnOffset(Serializers.OFFSET_SPACED_SERIALIZER.deserialize(itemSection.getString("spawn-offset"))); buttonBuilder.setAccessItem(MenuParserImpl.getInstance().getItemStack("menus/island-creation.yml", itemSection.getConfigurationSection("access"))); buttonBuilder.setNoAccessItem(MenuParserImpl.getInstance().getItemStack("menus/island-creation.yml", itemSection.getConfigurationSection("no-access"))); patternBuilder.mapButtons(menuPatternSlots.getSlots(itemSectionName), buttonBuilder); } } return new MenuIslandCreation(menuParseResult); } public static class Args implements ViewArgs { private final String islandName; public Args(String islandName) { this.islandName = islandName; } } public static class View extends AbstractMenuView { private final String islandName; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.islandName = args.islandName; } public String getIslandName() { return islandName; } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/creation-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("creation-gui.title")); int size = cfg.getInt("creation-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("creation-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("creation-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } if (cfg.isConfigurationSection("creation-gui.schematics")) { for (String schematicName : cfg.getConfigurationSection("creation-gui.schematics").getKeys(false)) { ConfigurationSection section = cfg.getConfigurationSection("creation-gui.schematics." + schematicName); char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; section.set("schematic", schematicName); MenuConverter.convertItemAccess(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection); } } newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandFlagPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.Set; public class MenuIslandFlags extends AbstractPagedMenu { private final List islandFlags; private MenuIslandFlags(MenuParseResult parseResult, List islandFlags) { super(MenuIdentifiers.MENU_ISLAND_FLAGS, parseResult, false); this.islandFlags = islandFlags; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuIslandFlags createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("settings.yml", MenuIslandFlags::convertOldGUI, new IslandFlagPagedObjectButton.Builder()); if (menuParseResult == null) { return null; } YamlConfiguration cfg = menuParseResult.getConfig(); List islandFlags = new LinkedList<>(); Set detectedFlags = new HashSet<>(); Optional.ofNullable(cfg.getConfigurationSection("settings")).ifPresent(settingsSection -> { for (String islandFlagName : settingsSection.getKeys(false)) { Optional.ofNullable(settingsSection.getConfigurationSection(islandFlagName)).ifPresent(islandFlagSection -> { if (islandFlagSection.getBoolean("display-menu", true)) { islandFlags.add(loadIslandFlagInfo(islandFlagSection, islandFlagName, islandFlags.size())); } detectedFlags.add(islandFlagName.toUpperCase(Locale.ENGLISH)); }); } }); for (IslandFlag islandFlag : IslandFlag.values()) { String islandFlagName = islandFlag.getName(); if (!detectedFlags.contains(islandFlagName)) { Log.warnFromFile("settings.yml", "Potentially missing setting ", islandFlagName); } } return new MenuIslandFlags(menuParseResult, islandFlags); } private static IslandFlagInfo loadIslandFlagInfo(ConfigurationSection islandFlagSection, String islandFlagName, int position) { TemplateItem enabledIslandFlagItem = null; TemplateItem disabledIslandFlagItem = null; GameSound clickSound = null; if (islandFlagSection != null) { enabledIslandFlagItem = MenuParserImpl.getInstance().getItemStack("menus/settings.yml", islandFlagSection.getConfigurationSection("settings-enabled")); disabledIslandFlagItem = MenuParserImpl.getInstance().getItemStack("menus/settings.yml", islandFlagSection.getConfigurationSection("settings-disabled")); clickSound = MenuParserImpl.getInstance().getSound(islandFlagSection.getConfigurationSection("sound")); } return new MenuIslandFlags.IslandFlagInfo(islandFlagName, enabledIslandFlagItem, disabledIslandFlagItem, clickSound, position); } public class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return island; } @Override protected List requestObjects() { return Collections.unmodifiableList(islandFlags); } } public static class IslandFlagInfo implements Comparable { private final LazyReference islandFlag = new LazyReference() { @Override protected IslandFlag create() { try { return IslandFlag.getByName(IslandFlagInfo.this.islandFlagName); } catch (Exception error) { return null; } } }; private final String islandFlagName; private final TemplateItem enabledIslandFlagItem; private final TemplateItem disabledIslandFlagItem; private final GameSound clickSound; private final int position; public IslandFlagInfo(String islandFlagName, TemplateItem enabledIslandFlagItem, TemplateItem disabledIslandFlagItem, GameSound clickSound, int position) { this.islandFlagName = islandFlagName; this.enabledIslandFlagItem = enabledIslandFlagItem; this.disabledIslandFlagItem = disabledIslandFlagItem; this.clickSound = clickSound; this.position = position; } @Nullable public IslandFlag getIslandFlag() { return islandFlag.get(); } public ItemBuilder getEnabledIslandFlagItem() { return enabledIslandFlagItem.getBuilder(); } public ItemBuilder getDisabledIslandFlagItem() { return disabledIslandFlagItem.getBuilder(); } public GameSound getClickSound() { return clickSound; } @Override public int compareTo(@NotNull MenuIslandFlags.IslandFlagInfo other) { return Integer.compare(position, other.position); } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/settings-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("settings-gui.title")); int size = cfg.getInt("settings-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("settings-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("settings-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertPagedButtons(cfg.getConfigurationSection("settings-gui"), newMenu, patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], itemsSection, commandsSection, soundsSection); newMenu.set("settings", cfg.getConfigurationSection("settings-gui.settings")); newMenu.set("sounds", null); newMenu.set("commands", null); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.MembersPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.List; public class MenuIslandMembers extends AbstractPagedMenu { private MenuIslandMembers(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_MEMBERS, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuIslandMembers createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("members.yml", MenuIslandMembers::convertOldGUI, new MembersPagedObjectButton.Builder()); return menuParseResult == null ? null : new MenuIslandMembers(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return this.island; } @Override public String replaceTitle(String title) { return title.replace("{0}", String.valueOf(island.getIslandMembers(true).size())). replace("{1}", String.valueOf(island.getTeamLimit())); } @Override protected List requestObjects() { return island.getIslandMembers(true); } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/panel-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("members-panel.title")); int size = cfg.getInt("members-panel.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("members-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("members-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertPagedButtons(cfg.getConfigurationSection("members-panel"), cfg.getConfigurationSection("members-panel.member-item"), newMenu, patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], itemsSection, commandsSection, soundsSection); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandPrivilegePagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.Set; public class MenuIslandPrivileges extends AbstractPagedMenu< MenuIslandPrivileges.View, MenuIslandPrivileges.Args, MenuIslandPrivileges.IslandPrivilegeInfo> { private final List islandPrivileges; private final String noRolePermission; private final String exactRolePermission; private final String higherRolePermission; private MenuIslandPrivileges(MenuParseResult parseResult, List islandPrivileges, String noRolePermission, String exactRolePermission, String higherRolePermission) { super(MenuIdentifiers.MENU_ISLAND_PRIVILEGES, parseResult, false); this.islandPrivileges = islandPrivileges; this.noRolePermission = noRolePermission; this.exactRolePermission = exactRolePermission; this.higherRolePermission = higherRolePermission; } public String getNoRolePermission() { return noRolePermission; } public String getExactRolePermission() { return exactRolePermission; } public String getHigherRolePermission() { return higherRolePermission; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } public void refreshViews(Island island, Object permissionHolder) { refreshViews(view -> view.island.equals(island) && view.permissionHolder.equals(permissionHolder)); } @Nullable public static MenuIslandPrivileges createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("permissions.yml", MenuIslandPrivileges::convertOldGUI, new IslandPrivilegePagedObjectButton.Builder()); if (menuParseResult == null) return null; YamlConfiguration cfg = menuParseResult.getConfig(); String noRolePermission = cfg.getString("messages.no-role-permission", ""); String exactRolePermission = cfg.getString("messages.exact-role-permission", ""); String higherRolePermission = cfg.getString("messages.higher-role-permission", ""); List islandPrivileges = new LinkedList<>(); Set detectedPrivileges = new HashSet<>(); Optional.ofNullable(cfg.getConfigurationSection("permissions")).ifPresent(permissionsSection -> { for (String islandPrivilegeName : permissionsSection.getKeys(false)) { Optional.ofNullable(permissionsSection.getConfigurationSection(islandPrivilegeName)).ifPresent(islandPrivilegeSection -> { if (islandPrivilegeSection.getBoolean("display-menu", true)) { islandPrivileges.add(loadIslandPrivilegeInfo(islandPrivilegeSection, islandPrivilegeName, islandPrivileges.size())); } detectedPrivileges.add(islandPrivilegeName.toUpperCase(Locale.ENGLISH)); }); } }); for (IslandPrivilege islandPrivilege : IslandPrivilege.values()) { String islandPrivilegeName = islandPrivilege.getName(); if (!detectedPrivileges.contains(islandPrivilegeName)) { Log.warnFromFile("permissions.yml", "Potentially missing permission ", islandPrivilegeName); } } return new MenuIslandPrivileges(menuParseResult, islandPrivileges, noRolePermission, exactRolePermission, higherRolePermission); } private static IslandPrivilegeInfo loadIslandPrivilegeInfo(ConfigurationSection islandPrivilegeSection, String islandPrivilegeName, int position) { TemplateItem enabledIslandPrivilegeItem = null; TemplateItem disabledIslandPrivilegeItem = null; TemplateItem rolePrivilegeItem = null; GameSound accessSound = null; GameSound noAccessSound = null; List accessCommands = null; List noAccessCommands = null; if (islandPrivilegeSection != null) { enabledIslandPrivilegeItem = MenuParserImpl.getInstance().getItemStack("menus/permissions.yml", islandPrivilegeSection.getConfigurationSection("permission-enabled")); disabledIslandPrivilegeItem = MenuParserImpl.getInstance().getItemStack("menus/permissions.yml", islandPrivilegeSection.getConfigurationSection("permission-disabled")); rolePrivilegeItem = MenuParserImpl.getInstance().getItemStack("menus/permissions.yml", islandPrivilegeSection.getConfigurationSection("role-permission")); accessSound = MenuParserImpl.getInstance().getSound(islandPrivilegeSection.getConfigurationSection("has-access.sound")); noAccessSound = MenuParserImpl.getInstance().getSound(islandPrivilegeSection.getConfigurationSection("no-access.sound")); accessCommands = islandPrivilegeSection.getStringList("has-access.commands"); noAccessCommands = islandPrivilegeSection.getStringList("no-access.commands"); } return new MenuIslandPrivileges.IslandPrivilegeInfo(islandPrivilegeName, enabledIslandPrivilegeItem, disabledIslandPrivilegeItem, rolePrivilegeItem, accessSound, noAccessSound, accessCommands, noAccessCommands, position); } public static class Args implements ViewArgs { private final Island island; private final Object permissionHolder; public Args(Island island, Object permissionHolder) { this.island = island; this.permissionHolder = permissionHolder; } } public class View extends AbstractPagedMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private final Object permissionHolder; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.island = args.island; this.permissionHolder = args.permissionHolder; } @Override public Island getIsland() { return island; } @Override @Nullable public SuperiorPlayer getSuperiorPlayer() { return this.permissionHolder instanceof SuperiorPlayer ? (SuperiorPlayer) this.permissionHolder : null; } public Object getPermissionHolder() { return permissionHolder; } @Override protected List requestObjects() { List islandPrivileges = MenuIslandPrivileges.this.islandPrivileges; if (this.permissionHolder instanceof SuperiorPlayer && !island.isMember((SuperiorPlayer) this.permissionHolder)) { islandPrivileges = new LinkedList<>(islandPrivileges); islandPrivileges.removeIf(info -> { IslandPrivilege islandPrivilege = info.getIslandPrivilege(); return islandPrivilege != null && islandPrivilege.getType() == IslandPrivilege.Type.COMMAND; }); } return Collections.unmodifiableList(islandPrivileges); } } public static class IslandPrivilegeInfo implements Comparable { private final LazyReference islandPrivilege = new LazyReference() { @Override protected IslandPrivilege create() { try { return IslandPrivilege.getByName(IslandPrivilegeInfo.this.islandPrivilegeName); } catch (Exception error) { return null; } } }; private final String islandPrivilegeName; private final TemplateItem enabledIslandPrivilegeItem; private final TemplateItem disabledIslandPrivilegeItem; private final TemplateItem roleIslandPrivilegeItem; private final GameSound accessSound; private final GameSound noAccessSound; private final List accessCommands; private final List noAccessCommands; private final int position; public IslandPrivilegeInfo(String islandPrivilegeName, TemplateItem enabledIslandPrivilegeItem, TemplateItem disabledIslandPrivilegeItem, TemplateItem roleIslandPrivilegeItem, GameSound accessSound, GameSound noAccessSound, List accessCommands, List noAccessCommands, int position) { this.islandPrivilegeName = islandPrivilegeName; this.enabledIslandPrivilegeItem = enabledIslandPrivilegeItem; this.disabledIslandPrivilegeItem = disabledIslandPrivilegeItem; this.roleIslandPrivilegeItem = roleIslandPrivilegeItem; this.accessSound = accessSound; this.noAccessSound = noAccessSound; this.accessCommands = accessCommands == null ? Collections.emptyList() : accessCommands; this.noAccessCommands = noAccessCommands == null ? Collections.emptyList() : noAccessCommands; this.position = position; } public IslandPrivilege getIslandPrivilege() { return islandPrivilege.get(); } public ItemBuilder getEnabledIslandPrivilegeItem() { return enabledIslandPrivilegeItem.getBuilder(); } public ItemBuilder getDisabledIslandPrivilegeItem() { return disabledIslandPrivilegeItem.getBuilder(); } @Nullable public ItemBuilder getRoleIslandPrivilegeItem() { return roleIslandPrivilegeItem == null ? null : roleIslandPrivilegeItem.getBuilder(); } @Nullable public GameSound getAccessSound() { return accessSound; } @Nullable public GameSound getNoAccessSound() { return noAccessSound; } public List getAccessCommands() { return accessCommands; } public List getNoAccessCommands() { return noAccessCommands; } @Override public int compareTo(@NotNull MenuIslandPrivileges.IslandPrivilegeInfo other) { return Integer.compare(position, other.position); } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/permissions-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("permissions-gui.title")); int size = cfg.getInt("permissions-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("permissions-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("permissions-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertPagedButtons(cfg.getConfigurationSection("permissions-gui"), newMenu, patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], itemsSection, commandsSection, soundsSection); newMenu.set("permissions", cfg.getConfigurationSection("permissions-gui.permissions")); newMenu.set("sounds", null); newMenu.set("commands", null); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRate.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.RateIslandButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; public class MenuIslandRate extends AbstractMenu { private MenuIslandRate(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_RATE, parseResult); } @Override protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new IslandMenuView(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuIslandRate createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("island-rate.yml", MenuIslandRate::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "zero-stars", menuPatternSlots), new RateIslandButton.Builder().setRating(Rating.ZERO_STARS)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "one-star", menuPatternSlots), new RateIslandButton.Builder().setRating(Rating.ONE_STAR)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "two-stars", menuPatternSlots), new RateIslandButton.Builder().setRating(Rating.TWO_STARS)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "three-stars", menuPatternSlots), new RateIslandButton.Builder().setRating(Rating.THREE_STARS)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "four-stars", menuPatternSlots), new RateIslandButton.Builder().setRating(Rating.FOUR_STARS)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "five-stars", menuPatternSlots), new RateIslandButton.Builder().setRating(Rating.FIVE_STARS)); return new MenuIslandRate(menuParseResult); } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/ratings-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("rate-gui.title")); newMenu.set("type", "HOPPER"); char[] patternChars = new char[5]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("rate-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("rate-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char oneStarChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char twoStarsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char threeStarsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char fourStarsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char fiveStarsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertItem(cfg.getConfigurationSection("rate-gui.one_star"), patternChars, oneStarChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("rate-gui.two_stars"), patternChars, twoStarsChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("rate-gui.three_stars"), patternChars, threeStarsChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("rate-gui.four_stars"), patternChars, fourStarsChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("rate-gui.five_stars"), patternChars, fiveStarsChar, itemsSection, commandsSection, soundsSection); newMenu.set("one-star", oneStarChar + ""); newMenu.set("two-stars", twoStarsChar + ""); newMenu.set("three-stars", threeStarsChar + ""); newMenu.set("four-stars", fourStarsChar + ""); newMenu.set("five-stars", fiveStarsChar + ""); newMenu.set("pattern", MenuConverter.buildPattern(1, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.RatingsPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Function; public class MenuIslandRatings extends AbstractPagedMenu { private static final Function, RatingInfo> RATING_INFO_MAPPER = entry -> new RatingInfo(entry.getKey(), entry.getValue()); private MenuIslandRatings(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_RATINGS, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuIslandRatings createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("island-ratings.yml", MenuIslandRatings::convertOldGUI, new RatingsPagedObjectButton.Builder()); return menuParseResult == null ? null : new MenuIslandRatings(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return this.island; } @Override public String replaceTitle(String title) { return title.replace("{0}", Formatters.NUMBER_FORMATTER.format(island.getTotalRating())); } @Override protected List requestObjects() { return new SequentialListBuilder() .build(island.getRatings().entrySet(), RATING_INFO_MAPPER); } } public static class RatingInfo { private final UUID playerUUID; private final Rating rating; public RatingInfo(UUID playerUUID, Rating rating) { this.playerUUID = playerUUID; this.rating = rating; } public UUID getPlayerUUID() { return playerUUID; } public Rating getRating() { return rating; } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/ratings-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("ratings-gui.title")); int size = cfg.getInt("ratings-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("ratings-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("ratings-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertPagedButtons(cfg.getConfigurationSection("ratings-gui"), cfg.getConfigurationSection("ratings-gui.rate-item"), newMenu, patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], itemsSection, commandsSection, soundsSection); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUniqueVisitors.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.UniqueVisitorPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import java.util.List; import java.util.function.Function; public class MenuIslandUniqueVisitors extends AbstractPagedMenu { private static final Function, UniqueVisitorInfo> VISITOR_INFO_MAPPER = visitor -> new UniqueVisitorInfo(visitor.getKey(), visitor.getValue()); private MenuIslandUniqueVisitors(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_UNIQUE_VISITORS, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuIslandUniqueVisitors createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("unique-visitors.yml", null, new UniqueVisitorPagedObjectButton.Builder()); return menuParseResult == null ? null : new MenuIslandUniqueVisitors(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return this.island; } @Override public String replaceTitle(String title) { return title.replace("{0}", island.getUniqueVisitorsWithTimes().size() + ""); } @Override protected List requestObjects() { return new SequentialListBuilder() .build(island.getUniqueVisitorsWithTimes(), VISITOR_INFO_MAPPER); } } public static class UniqueVisitorInfo { private final SuperiorPlayer visitor; private final long visitTime; public UniqueVisitorInfo(SuperiorPlayer visitor, long visitTime) { this.visitor = visitor; this.visitTime = visitTime; } public SuperiorPlayer getVisitor() { return visitor; } public long getVisitTime() { return visitTime; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUpgrades.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.impl.UpgradeButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.List; public class MenuIslandUpgrades extends AbstractMenu { private MenuIslandUpgrades(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_UPGRADES, parseResult); } @Override protected IslandMenuView createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new IslandMenuView(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.getIsland().equals(island)); } @Nullable public static MenuIslandUpgrades createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("upgrades.yml", MenuIslandUpgrades::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); if (cfg.isConfigurationSection("upgrades")) { ConfigurationSection upgradesSection = cfg.getConfigurationSection("upgrades"); for (Upgrade upgrade : plugin.getUpgrades().getUpgrades()) { ConfigurationSection upgradeSection = upgradesSection.getConfigurationSection(upgrade.getName()); if (upgradeSection == null) { continue; } List slots = MenuParserImpl.getInstance().parseButtonSlots(upgradeSection, "item", menuPatternSlots); upgrade.setSlots(slots); patternBuilder.mapButtons(slots, new UpgradeButton.Builder(upgrade)); for (String levelSectionKey : upgradeSection.getKeys(false)) { int level; try { level = Integer.parseInt(levelSectionKey); } catch (NumberFormatException error) { // Not a number, skipping. continue; } if (slots.isEmpty()) { Log.warnFromFile("upgrades.yml", "The item of the upgrade ", upgrade.getName(), " (level ", level, ") is not inside the pattern, skipping..."); continue; } SUpgradeLevel upgradeLevel = (SUpgradeLevel) upgrade.getUpgradeLevel(level); if (upgradeLevel != null) { TemplateItem hasNextLevel = MenuParserImpl.getInstance().getItemStack("menus/upgrades.yml", upgradeSection.getConfigurationSection(level + ".has-next-level")); if (hasNextLevel == null) { Log.warnFromFile("upgrades.yml", "The upgrade ", upgrade.getName(), " (level ", level, ") is missing has-next-level item."); } TemplateItem noNextLevel = MenuParserImpl.getInstance().getItemStack("menus/upgrades.yml", upgradeSection.getConfigurationSection(level + ".no-next-level")); if (noNextLevel == null) { Log.warnFromFile("upgrades.yml", "&cThe upgrade ", upgrade.getName(), " (level ", level, ") is missing no-next-level item."); } GameSound hasNextLevelSound = MenuParserImpl.getInstance().getSound(upgradeSection.getConfigurationSection(level + ".has-next-level.sound")); GameSound noNextLevelSound = MenuParserImpl.getInstance().getSound(upgradeSection.getConfigurationSection(level + ".no-next-level.sound")); List hasNextLevelCommands = upgradeSection.getStringList(level + ".has-next-level.commands"); List noNextLevelCommands = upgradeSection.getStringList(level + ".no-next-level.commands"); upgradeLevel.setItemData(hasNextLevel, noNextLevel, hasNextLevelSound, noNextLevelSound, hasNextLevelCommands, noNextLevelCommands); } } } } return new MenuIslandUpgrades(menuParseResult); } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/upgrades-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("upgrades-gui.title")); int size = cfg.getInt("upgrades-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("upgrades-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("upgrades-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } if (cfg.isConfigurationSection("upgrades-gui.upgrades")) { for (String upgradeName : cfg.getConfigurationSection("upgrades-gui.upgrades").getKeys(false)) { ConfigurationSection section = cfg.getConfigurationSection("upgrades-gui.upgrades." + upgradeName); char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; section.set("item", itemChar + ""); patternChars[section.getInt("1.slot")] = itemChar; for (String upgradeLevel : section.getKeys(false)) { section.set(upgradeLevel + ".slot", null); } } } newMenu.set("upgrades", cfg.getConfigurationSection("upgrades-gui.upgrades")); newMenu.set("sounds", null); newMenu.set("commands", null); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.ValuesButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.Locale; import java.util.function.Function; import java.util.stream.Collectors; public class MenuIslandValues extends AbstractMenu { private MenuIslandValues(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_VALUES, parseResult); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuIslandValues createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("values.yml", MenuIslandValues::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); KeySet keysToUpdate = KeySets.createHashSet(KeyIndicator.MATERIAL); if (cfg.isConfigurationSection("items")) { for (String itemsSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemsSection = cfg.getConfigurationSection("items." + itemsSectionName); String block = itemsSection.getString("block"); if (block == null) continue; Key blockKey = Keys.ofMaterialAndData(block); keysToUpdate.add(blockKey); patternBuilder.mapButtons(menuPatternSlots.getSlots(itemsSectionName), new ValuesButton.Builder(blockKey)); } } plugin.getBlockValues().registerMenuValueBlocks(keysToUpdate); return new MenuIslandValues(menuParseResult); } public static class View extends AbstractMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private SuperiorPlayer targetPlayer; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); this.targetPlayer = args.getIsland().getOwner(); } @Override public Island getIsland() { return island; } @Override public SuperiorPlayer getSuperiorPlayer() { return targetPlayer; } public void setTargetPlayer(SuperiorPlayer targetPlayer) { this.targetPlayer = targetPlayer; } @Override public String replaceTitle(String title) { return title.replace("{0}", island.getOwner().getName()) .replace("{1}", Formatters.NUMBER_FORMATTER.format(island.getWorth())) .replace("{2}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), getInventoryViewer().getUserLocale())); } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/values-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("values-gui.title")); int size = cfg.getInt("values-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("values-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("values-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } ConfigurationSection blockItemSection = cfg.getConfigurationSection("values-gui.block-item"); for (String material : cfg.getStringList("values-gui.materials")) { char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; ConfigurationSection section = itemsSection.createSection(itemChar + ""); String[] materialSections = material.split(":"); String block = materialSections.length == 2 ? materialSections[0] : materialSections[0] + ":" + materialSections[1]; int slot = Integer.parseInt(materialSections.length == 2 ? materialSections[1] : materialSections[2]); copySection(blockItemSection, section, str -> str.replace("{0}", Formatters.CAPITALIZED_FORMATTER.format(block)).replace("{1}", "{0}")); section.set("block", block); convertType(section, block); patternChars[slot] = itemChar; } newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } private static void copySection(ConfigurationSection source, ConfigurationSection destination, Function stringReplacer) { for (String key : source.getKeys(false)) { if (source.isConfigurationSection(key)) { copySection(source.getConfigurationSection(key), destination.createSection(key), stringReplacer); } else if (source.isList(key)) { destination.set(key, source.getStringList(key).stream().map(stringReplacer).collect(Collectors.toList())); } else if (source.isString(key)) { destination.set(key, stringReplacer.apply(source.getString(key))); } else { destination.set(key, source.getString(key)); } } } private static void convertType(ConfigurationSection section, String block) { String[] materialSections = block.split(":"); String spawnerType = materialSections[0], entityType = (materialSections.length >= 2 ? materialSections[1] : "PIG").toUpperCase(Locale.ENGLISH); if (spawnerType.equals(Materials.SPAWNER.toBukkitType() + "")) { String texture = ItemSkulls.getTexture(entityType); if (!texture.isEmpty()) { section.set("type", Materials.PLAYER_HEAD.toBukkitType().name()); if (section.getString("type").equalsIgnoreCase("SKULL_ITEM")) section.set("data", 3); section.set("skull", texture); return; } } section.set("type", spawnerType.equals(Materials.SPAWNER.toBukkitType() + "") ? spawnerType : block); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.OpenUniqueVisitorsButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.VisitorPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.List; public class MenuIslandVisitors extends AbstractPagedMenu { private MenuIslandVisitors(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_ISLAND_VISITORS, parseResult, false); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } @Nullable public static MenuIslandVisitors createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("visitors.yml", MenuIslandVisitors::convertOldGUI, new VisitorPagedObjectButton.Builder()); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "unique-visitors", menuPatternSlots), new OpenUniqueVisitorsButton.Builder()); return new MenuIslandVisitors(menuParseResult); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return island; } @Override public String replaceTitle(String title) { return title.replace("{0}", String.valueOf(island.getIslandVisitors(false).size())); } @Override protected List requestObjects() { return island.getIslandVisitors(false); } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/panel-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("visitors-panel.title")); int size = cfg.getInt("visitors-panel.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("visitors-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("visitors-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertPagedButtons(cfg.getConfigurationSection("visitors-panel"), cfg.getConfigurationSection("visitors-panel.visitor-item"), newMenu, patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], itemsSection, commandsSection, soundsSection); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberManage.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.MemberManageButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs; import com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; public class MenuMemberManage extends AbstractMenu { private MenuMemberManage(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_MEMBER_MANAGE, parseResult); } @Override protected PlayerMenuView createViewInternal(SuperiorPlayer superiorPlayer, PlayerViewArgs args, @Nullable MenuView previousMenuView) { return new PlayerMenuView(superiorPlayer, previousMenuView, this, args); } public void closeViews(SuperiorPlayer islandMember) { closeViews(view -> view.getSuperiorPlayer().equals(islandMember)); } @Nullable public static MenuMemberManage createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("member-manage.yml", MenuMemberManage::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "roles", menuPatternSlots), new MemberManageButton.Builder().setManageAction(MemberManageButton.ManageAction.SET_ROLE)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "ban", menuPatternSlots), new MemberManageButton.Builder().setManageAction(MemberManageButton.ManageAction.BAN_MEMBER)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "kick", menuPatternSlots), new MemberManageButton.Builder().setManageAction(MemberManageButton.ManageAction.KICK_MEMBER)); return new MenuMemberManage(menuParseResult); } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/panel-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("players-panel.title")); int size = cfg.getInt("players-panel.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("players-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("players-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char rolesChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char banChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char kickChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertItem(cfg.getConfigurationSection("players-panel.roles"), patternChars, rolesChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("players-panel.ban"), patternChars, banChar, itemsSection, commandsSection, soundsSection); MenuConverter.convertItem(cfg.getConfigurationSection("players-panel.kick"), patternChars, kickChar, itemsSection, commandsSection, soundsSection); newMenu.set("roles", rolesChar + ""); newMenu.set("ban", banChar + ""); newMenu.set("kick", kickChar + ""); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.MemberRoleButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs; import com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; public class MenuMemberRole extends AbstractMenu { private MenuMemberRole(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_MEMBER_ROLE, parseResult); } @Override protected PlayerMenuView createViewInternal(SuperiorPlayer superiorPlayer, PlayerViewArgs args, @Nullable MenuView previousMenuView) { return new PlayerMenuView(superiorPlayer, previousMenuView, this, args); } public void closeViews(SuperiorPlayer islandMember) { closeViews(view -> view.getSuperiorPlayer().equals(islandMember)); } @Nullable public static MenuMemberRole createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("member-role.yml", MenuMemberRole::convertOldGUI); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); if (cfg.isConfigurationSection("items")) { for (String itemsSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemsSection = cfg.getConfigurationSection("items." + itemsSectionName); Object roleObject = itemsSection.get("role"); PlayerRole playerRole = null; if (roleObject instanceof String) { try { playerRole = SPlayerRole.of((String) roleObject); } catch (IllegalArgumentException error) { Log.warnFromFile("member-role.yml", "Invalid role name: ", roleObject); continue; } } else if (roleObject instanceof Integer) { playerRole = SPlayerRole.of((Integer) roleObject); if (playerRole == null) { Log.warnFromFile("member-role.yml", "&cInvalid role id: ", roleObject); continue; } } if (playerRole == null) continue; patternBuilder.mapButtons(menuPatternSlots.getSlots(itemsSectionName), new MemberRoleButton.Builder().setPlayerRole(playerRole)); } } return new MenuMemberRole(menuParseResult); } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/panel-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("roles-panel.title")); int size = cfg.getInt("roles-panel.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("roles-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("roles-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } if (cfg.isConfigurationSection("roles-panel.roles")) { for (String roleName : cfg.getConfigurationSection("roles-panel.roles").getKeys(false)) { ConfigurationSection section = cfg.getConfigurationSection("roles-panel.roles." + roleName); char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; section.set("role", Formatters.CAPITALIZED_FORMATTER.format(roleName)); MenuConverter.convertItem(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection); } } newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissions.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.OpenMissionCategoryButton; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; public class MenuMissions extends AbstractMenu { private MenuMissions(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_MISSIONS, parseResult); } @Override protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused, @Nullable MenuView previousMenuView) { return new BaseMenuView(superiorPlayer, previousMenuView, this); } @Nullable public static MenuMissions createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("missions.yml", null); if (menuParseResult == null) { return null; } MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); plugin.getMissions().getMissionCategories().forEach( missionCategory -> patternBuilder.mapButton(missionCategory.getSlot(), new OpenMissionCategoryButton.Builder().setMissionsCategory(missionCategory))); return new MenuMissions(menuParseResult); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissionsCategory.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.MissionsPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.mission.MissionReference; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.util.Collections; import java.util.Comparator; import java.util.List; public class MenuMissionsCategory extends AbstractPagedMenu { private final boolean sortByCompletion; private final boolean removeCompleted; private MenuMissionsCategory(MenuParseResult parseResult, boolean sortByCompletion, boolean removeCompleted) { super(MenuIdentifiers.MENU_MISSIONS_CATEGORY, parseResult, false); this.sortByCompletion = sortByCompletion; this.removeCompleted = removeCompleted; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(MissionCategory missionCategory) { refreshViews(view -> missionCategory.equals(view.missionCategory)); } @Nullable public static MenuMissionsCategory createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("missions-category.yml", null, new MissionsPagedObjectButton.Builder()); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); PagedMenuLayout.Builder patternBuilder = (PagedMenuLayout.Builder) menuParseResult.getLayoutBuilder(); boolean sortByCompletion = cfg.getBoolean("sort-by-completion", false); boolean removeCompleted = cfg.getBoolean("remove-completed", false); ConfigurationSection soundsSection = cfg.getConfigurationSection("sounds"); if (soundsSection != null) { for (char slotChar : cfg.getString("slots", "").toCharArray()) { ConfigurationSection soundSection = soundsSection.getConfigurationSection(slotChar + ""); if (soundSection == null) continue; GameSound completedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("completed")); GameSound notCompletedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("not-completed")); GameSound canCompleteSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("can-complete")); GameSound lockedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("locked")); patternBuilder.setPagedObjectSlots(menuPatternSlots.getSlots(slotChar), new MissionsPagedObjectButton.Builder() .setCompletedSound(completedSound) .setNotCompletedSound(notCompletedSound) .setCanCompleteSound(canCompleteSound) .setLockedSound(lockedSound)); } } return new MenuMissionsCategory(menuParseResult, sortByCompletion, removeCompleted); } public static class Args implements ViewArgs { private final MissionCategory missionCategory; public Args(MissionCategory missionCategory) { this.missionCategory = missionCategory; } } public class View extends AbstractPagedMenuView { private final MissionCategory missionCategory; private final List missions; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.missionCategory = args.missionCategory; if (inventoryViewer == null) { this.missions = Collections.emptyList(); } else { SequentialListBuilder> listBuilder = new SequentialListBuilder<>(); if (sortByCompletion) listBuilder.sorted(Comparator.comparingInt(this::getCompletionStatus)); this.missions = listBuilder .filter(mission -> plugin.getMissions().canDisplayMission(mission, inventoryViewer, removeCompleted)) .map(args.missionCategory.getMissions(), MissionReference::new); } } @Override public String replaceTitle(String title) { return title.replace("{0}", missionCategory.getName()); } @Override protected List requestObjects() { return missions; } private int getCompletionStatus(Mission mission) { SuperiorPlayer inventoryViewer = getInventoryViewer(); IMissionsHolder missionsHolder = mission.getIslandMission() ? inventoryViewer.getIsland() : inventoryViewer; return missionsHolder == null ? 0 : !missionsHolder.canCompleteMissionAgain(mission) ? 2 : plugin.getMissions().canComplete(inventoryViewer, mission) ? 1 : 0; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuPlayerLanguage.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.LanguageButton; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; public class MenuPlayerLanguage extends AbstractMenu { private MenuPlayerLanguage(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_PLAYER_LANGUAGE, parseResult); } @Override protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused, @Nullable MenuView previousMenuView) { return new BaseMenuView(superiorPlayer, previousMenuView, this); } @Nullable public static MenuPlayerLanguage createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("player-language.yml", null); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); if (cfg.isConfigurationSection("items")) { for (String itemsSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemSection = cfg.getConfigurationSection("items." + itemsSectionName); String languageName = itemSection.getString("language"); if (languageName == null) continue; java.util.Locale locale = null; try { locale = PlayerLocales.getLocale(languageName); if (!PlayerLocales.isValidLocale(locale)) locale = null; } catch (IllegalArgumentException ignored) { } if (locale == null) { Log.warnFromFile("player-language.yml", "The language ", languageName, " is not valid."); continue; } patternBuilder.mapButtons(menuPatternSlots.getSlots(itemsSectionName), new LanguageButton.Builder().setLanguage(locale)); } } return new MenuPlayerLanguage(menuParseResult); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuTopIslands.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.ChangeSortingTypeButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.TopIslandsPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.TopIslandsSelfIslandButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; public class MenuTopIslands extends AbstractPagedMenu { private final boolean sortGlowWhenSelected; private MenuTopIslands(MenuParseResult parseResult, boolean sortGlowWhenSelected) { super(MenuIdentifiers.MENU_TOP_ISLANDS, parseResult, false); this.sortGlowWhenSelected = sortGlowWhenSelected; } public boolean isSortGlowWhenSelected() { return sortGlowWhenSelected; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } @Override public CompletableFuture refreshView(View view) { CompletableFuture res = new CompletableFuture<>(); plugin.getGrid().sortIslands(view.sortingType, () -> super.refreshView(view).whenComplete((v, err) -> { if (err != null) { res.completeExceptionally(err); } else { res.complete(v); } })); return res; } public void refreshViews(SortingType sortingType) { refreshViews(view -> view.sortingType.equals(sortingType)); } @Nullable public static MenuTopIslands createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("top-islands.yml", MenuTopIslands::convertOldGUI, new TopIslandsPagedObjectButton.Builder()); if (menuParseResult == null) return null; MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); boolean sortGlowWhenSelected = cfg.getBoolean("sort-glow-when-selected", false); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "worth-sort", menuPatternSlots), new ChangeSortingTypeButton.Builder().setSortingType(SortingTypes.BY_WORTH)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "level-sort", menuPatternSlots), new ChangeSortingTypeButton.Builder().setSortingType(SortingTypes.BY_LEVEL)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "rating-sort", menuPatternSlots), new ChangeSortingTypeButton.Builder().setSortingType(SortingTypes.BY_RATING)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "players-sort", menuPatternSlots), new ChangeSortingTypeButton.Builder().setSortingType(SortingTypes.BY_PLAYERS)); if (cfg.isConfigurationSection("items")) { for (String itemSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemSection = cfg.getConfigurationSection("items." + itemSectionName); if (!itemSection.isString("sorting-type")) continue; SortingType sortingType = SortingType.getByName(itemSection.getString("sorting-type")); if (sortingType == null) { Log.warnFromFile("top-islands.yml", "The sorting type is invalid for the item ", itemSectionName); continue; } patternBuilder.mapButtons(menuPatternSlots.getSlots(itemSectionName), new ChangeSortingTypeButton.Builder().setSortingType(sortingType)); } } if (cfg.isString("slots")) { boolean configuredSelfPlayerButton = false; for (char slotsChar : cfg.getString("slots", "").toCharArray()) { ConfigurationSection itemsSection = cfg.getConfigurationSection("items." + slotsChar); if (itemsSection == null) continue; TopIslandsPagedObjectButton.Builder slotsBuilder = new TopIslandsPagedObjectButton.Builder(); slotsBuilder.setIslandItem(MenuParserImpl.getInstance().getItemStack("menus/top-islands.yml", itemsSection.getConfigurationSection("island"))); slotsBuilder.setNoIslandItem(MenuParserImpl.getInstance().getItemStack("menus/top-islands.yml", itemsSection.getConfigurationSection("no-island"))); slotsBuilder.setIslandSound(MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection("sounds." + slotsChar + ".island"))); slotsBuilder.setNoIslandSound(MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection("sounds." + slotsChar + ".no-island"))); slotsBuilder.setIslandCommands(cfg.getStringList("commands." + slotsChar + ".island")); slotsBuilder.setNoIslandCommands(cfg.getStringList("commands." + slotsChar + ".no-island")); patternBuilder.mapButtons(menuPatternSlots.getSlots(slotsChar), slotsBuilder); if (!configuredSelfPlayerButton) { configuredSelfPlayerButton = true; TopIslandsSelfIslandButton.Builder selfIslandBuilder = new TopIslandsSelfIslandButton.Builder(); selfIslandBuilder.setIslandItem(MenuParserImpl.getInstance().getItemStack("menus/top-islands.yml", itemsSection.getConfigurationSection("island"))); selfIslandBuilder.setNoIslandItem(MenuParserImpl.getInstance().getItemStack("menus/top-islands.yml", itemsSection.getConfigurationSection("no-island"))); selfIslandBuilder.setIslandSound(MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection("sounds." + slotsChar + ".island"))); selfIslandBuilder.setNoIslandSound(MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection("sounds." + slotsChar + ".no-island"))); selfIslandBuilder.setIslandCommands(cfg.getStringList("commands." + slotsChar + ".island")); selfIslandBuilder.setNoIslandCommands(cfg.getStringList("commands." + slotsChar + ".no-island")); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "player-island", menuPatternSlots), selfIslandBuilder); } } } return new MenuTopIslands(menuParseResult, sortGlowWhenSelected); } public static class Args implements ViewArgs { private final SortingType sortingType; public Args(SortingType sortingType) { this.sortingType = sortingType; } } public static class View extends AbstractPagedMenuView { private final Set alreadySorted = new HashSet<>(); private SortingType sortingType; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.sortingType = args.sortingType; } public SortingType getSortingType() { return sortingType; } public boolean setSortingType(SortingType sortingType) { this.sortingType = sortingType; this.updatePagedObjects(); return this.alreadySorted.add(sortingType); } @Override protected List requestObjects() { return plugin.getGrid().getIslands(sortingType); } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/top-islands.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("top-islands.title")); int size = cfg.getInt("top-islands.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("top-islands.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("top-islands.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char worthChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char levelChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char ratingChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char playersChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; char playerIslandChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; for (String slot : cfg.getString("top-islands.slots").split(",")) patternChars[Integer.parseInt(slot)] = slotsChar; ConfigurationSection islandItemSection = cfg.getConfigurationSection("top-islands.island-item"); newMenu.set("items." + slotsChar + ".island", islandItemSection); newMenu.set("sounds." + slotsChar + ".island", islandItemSection.getConfigurationSection("sound")); islandItemSection.set("sound", null); ConfigurationSection noIslandItemSection = cfg.getConfigurationSection("top-islands.no-island-item"); newMenu.set("items." + slotsChar + ".no-island", noIslandItemSection); newMenu.set("sounds." + slotsChar + ".no-island", noIslandItemSection.getConfigurationSection("sound")); noIslandItemSection.set("sound", null); if (cfg.isConfigurationSection("top-islands.worth-sort")) { MenuConverter.convertItem(cfg.getConfigurationSection("top-islands.worth-sort"), patternChars, worthChar, itemsSection, commandsSection, soundsSection); } if (cfg.isConfigurationSection("top-islands.level-sort")) { MenuConverter.convertItem(cfg.getConfigurationSection("top-islands.level-sort"), patternChars, levelChar, itemsSection, commandsSection, soundsSection); } if (cfg.isConfigurationSection("top-islands.rating-sort")) { MenuConverter.convertItem(cfg.getConfigurationSection("top-islands.rating-sort"), patternChars, ratingChar, itemsSection, commandsSection, soundsSection); } if (cfg.isConfigurationSection("top-islands.players-sort")) { MenuConverter.convertItem(cfg.getConfigurationSection("top-islands.players-sort"), patternChars, playersChar, itemsSection, commandsSection, soundsSection); } if (cfg.isInt("player-island-slot")) patternChars[cfg.getInt("player-island-slot")] = playerIslandChar; newMenu.set("worth-sort", worthChar); newMenu.set("level-sort", levelChar); newMenu.set("rating-sort", ratingChar); newMenu.set("players-sort", playersChar); newMenu.set("player-island", playerIslandChar); newMenu.set("sort-glow-when-selected", false); char invalidChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; newMenu.set("slots", slotsChar); newMenu.set("previous-page", invalidChar); newMenu.set("current-page", invalidChar); newMenu.set("next-page", invalidChar); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.DynamicArray; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.configuration.file.YamlConfiguration; import java.util.List; public class MenuWarpCategories extends AbstractPagedMenu { private final List editLore; private final int rowsSize; private MenuWarpCategories(MenuParseResult parseResult, List editLore, int rowsSize) { super(MenuIdentifiers.MENU_WARP_CATEGORIES, parseResult, true); this.editLore = editLore; this.rowsSize = rowsSize; } public List getEditLore() { return editLore; } public int getRowsSize() { return rowsSize; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, IslandViewArgs args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } public void closeViews(Island island) { closeViews(view -> view.getIsland().equals(island)); } @Nullable public static MenuWarpCategories createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("warp-categories.yml", MenuWarpCategories::convertOldGUI, new WarpCategoryPagedObjectButton.Builder()); if (menuParseResult == null) return null; YamlConfiguration cfg = menuParseResult.getConfig(); List editLore = cfg.getStringList("edit-lore"); int rowsSize = cfg.getStringList("pattern").size(); return new MenuWarpCategories(menuParseResult, editLore, rowsSize); } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; private final boolean hasManagePerms; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); this.hasManagePerms = island.isMember(inventoryViewer) && island.hasPermission(inventoryViewer, IslandPrivileges.SET_WARP); } @Override public Island getIsland() { return island; } @Override protected List requestObjects() { DynamicArray warpCategories = new DynamicArray<>(); island.getWarpCategories().values().forEach(warpCategory -> warpCategory.getWarps() .stream() .filter(islandWarp -> island.isMember(getInventoryViewer()) || !islandWarp.hasPrivateFlag()) .findAny() .ifPresent(unused -> warpCategories.set(warpCategory.getSlot(), warpCategory))); return warpCategories.toList(); } public boolean hasManagePerms() { return hasManagePerms; } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { if (newMenu.isString("slots") || !newMenu.isConfigurationSection("items")) return false; String itemChar = newMenu.getConfigurationSection("items") .getKeys(false).stream() .findFirst() .orElse(null); if (itemChar == null) return false; newMenu.set("slots", itemChar); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryIconEdit.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IconDisplayButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IconEditLoreButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IconEditTypeButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IconRenameButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryIconEditConfirmButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.configuration.file.YamlConfiguration; public class MenuWarpCategoryIconEdit extends AbstractMenu, AbstractIconProviderMenu.Args> { private MenuWarpCategoryIconEdit(MenuParseResult> parseResult) { super(MenuIdentifiers.MENU_WARP_CATEGORIES_ICON_EDIT, parseResult); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, AbstractIconProviderMenu.Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuWarpCategoryIconEdit createInstance() { MenuParseResult> menuParseResult = MenuParserImpl.getInstance().loadMenu( "warp-category-icon-edit.yml", null); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder> patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-type", menuPatternSlots), new IconEditTypeButton.Builder<>(Message.WARP_CATEGORY_ICON_NEW_TYPE)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-rename", menuPatternSlots), new IconRenameButton.Builder<>(Message.WARP_CATEGORY_ICON_NEW_NAME)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-relore", menuPatternSlots), new IconEditLoreButton.Builder<>(Message.WARP_CATEGORY_ICON_NEW_LORE)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-confirm", menuPatternSlots), new WarpCategoryIconEditConfirmButton.Builder()); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-slots", menuPatternSlots), new IconDisplayButton.Builder<>()); return new MenuWarpCategoryIconEdit(menuParseResult); } public static class Args extends AbstractIconProviderMenu.Args { public Args(WarpCategory warpCategory) { super(warpCategory, warpCategory == null ? null : new TemplateItem(new ItemBuilder(warpCategory.getRawIcon()))); } } public static class View extends AbstractIconProviderMenu.View { View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu, AbstractIconProviderMenu.Args> menu, AbstractIconProviderMenu.Args args) { super(inventoryViewer, previousMenuView, menu, args); } @Override public Island getIsland() { return getIconProvider().getIsland(); } @Override public String replaceTitle(String title) { return title.replace("{0}", getIconProvider().getName()); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryManage.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryManageIconButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryManageRenameButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryManageWarpsButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import org.bukkit.configuration.file.YamlConfiguration; public class MenuWarpCategoryManage extends AbstractMenu { private final GameSound successUpdateSound; private MenuWarpCategoryManage(MenuParseResult parseResult, @Nullable GameSound successUpdateSound) { super(MenuIdentifiers.MENU_WARP_CATEGORIES_MANAGE, parseResult); this.successUpdateSound = successUpdateSound; } @Nullable public GameSound getSuccessUpdateSound() { return successUpdateSound; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(WarpCategory warpCategory) { refreshViews(view -> view.warpCategory.equals(warpCategory)); } @Nullable public static MenuWarpCategoryManage createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("warp-category-manage.yml", null); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); GameSound successUpdateSound = cfg.isConfigurationSection("success-update-sound") ? MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection("success-update-sound")) : null; patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "category-rename", menuPatternSlots), new WarpCategoryManageRenameButton.Builder()); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "category-icon", menuPatternSlots), new WarpCategoryManageIconButton.Builder()); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "category-warps", menuPatternSlots), new WarpCategoryManageWarpsButton.Builder()); return new MenuWarpCategoryManage(menuParseResult, successUpdateSound); } public static class Args implements ViewArgs { private final WarpCategory warpCategory; public Args(WarpCategory warpCategory) { this.warpCategory = warpCategory; } } public static class View extends AbstractMenuView implements IIslandMenuView { private final WarpCategory warpCategory; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.warpCategory = args.warpCategory; } @Override public Island getIsland() { return this.warpCategory.getIsland(); } public WarpCategory getWarpCategory() { return warpCategory; } @Override public String replaceTitle(String title) { return title.replace("{0}", warpCategory.getName()); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpIconEdit.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IconDisplayButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IconEditLoreButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IconEditTypeButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IconRenameButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpIconEditConfirmButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.warp.WarpIcons; import org.bukkit.configuration.file.YamlConfiguration; public class MenuWarpIconEdit extends AbstractMenu, AbstractIconProviderMenu.Args> { private MenuWarpIconEdit(MenuParseResult> parseResult) { super(MenuIdentifiers.MENU_WARP_ICON_EDIT, parseResult); } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, AbstractIconProviderMenu.Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } @Nullable public static MenuWarpIconEdit createInstance() { MenuParseResult> menuParseResult = MenuParserImpl.getInstance().loadMenu( "warp-icon-edit.yml", null); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder> patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-type", menuPatternSlots), new IconEditTypeButton.Builder<>(Message.WARP_ICON_NEW_TYPE)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-rename", menuPatternSlots), new IconRenameButton.Builder<>(Message.WARP_ICON_NEW_NAME)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-relore", menuPatternSlots), new IconEditLoreButton.Builder<>(Message.WARP_ICON_NEW_LORE)); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-confirm", menuPatternSlots), new WarpIconEditConfirmButton.Builder()); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "icon-slots", menuPatternSlots), new IconDisplayButton.Builder<>()); return new MenuWarpIconEdit(menuParseResult); } public static class Args extends AbstractIconProviderMenu.Args { public Args(IslandWarp islandWarp) { super(islandWarp, islandWarp == null ? null : islandWarp.getRawIcon() == null ? WarpIcons.DEFAULT_WARP_ICON : new TemplateItem(new ItemBuilder(islandWarp.getRawIcon()))); } } public static class View extends AbstractIconProviderMenu.View { View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu, AbstractIconProviderMenu.Args> menu, AbstractIconProviderMenu.Args args) { super(inventoryViewer, previousMenuView, menu, args); } @Override public Island getIsland() { return getIconProvider().getIsland(); } @Override public String replaceTitle(String title) { return title.replace("{0}", getIconProvider().getName()); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpManage.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManageIconButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManageLocationButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManagePrivateButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManageRenameButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import org.bukkit.configuration.file.YamlConfiguration; public class MenuWarpManage extends AbstractMenu { private final GameSound successUpdateSound; private MenuWarpManage(MenuParseResult parseResult, GameSound successUpdateSound) { super(MenuIdentifiers.MENU_WARP_MANAGE, parseResult); this.successUpdateSound = successUpdateSound; } public GameSound getSuccessUpdateSound() { return successUpdateSound; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenu) { return new View(superiorPlayer, previousMenu, this, args); } public void refreshViews(IslandWarp islandWarp) { refreshViews(view -> view.islandWarp.equals(islandWarp)); } @Nullable public static MenuWarpManage createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("warp-manage.yml", null); if (menuParseResult == null) { return null; } MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); GameSound successUpdateSound = cfg.isConfigurationSection("success-update-sound") ? MenuParserImpl.getInstance().getSound(cfg.getConfigurationSection("success-update-sound")) : null; patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "warp-rename", menuPatternSlots), new WarpManageRenameButton.Builder()); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "warp-icon", menuPatternSlots), new WarpManageIconButton.Builder()); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "warp-location", menuPatternSlots), new WarpManageLocationButton.Builder()); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "warp-private", menuPatternSlots), new WarpManagePrivateButton.Builder()); return new MenuWarpManage(menuParseResult, successUpdateSound); } public static class Args implements ViewArgs { private final IslandWarp islandWarp; public Args(IslandWarp islandWarp) { this.islandWarp = islandWarp; } } public static class View extends AbstractMenuView implements IIslandMenuView { private final IslandWarp islandWarp; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.islandWarp = args.islandWarp; } @Override public Island getIsland() { return this.islandWarp.getIsland(); } public IslandWarp getIslandWarp() { return islandWarp; } @Override public String replaceTitle(String title) { return title.replace("{0}", islandWarp.getName()); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.warp.WarpIcons; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.ItemStack; import java.io.File; import java.util.Arrays; import java.util.List; public class MenuWarps extends AbstractPagedMenu { private final List editLore; private MenuWarps(MenuParseResult parseResult, List editLore) { super(MenuIdentifiers.MENU_WARPS, parseResult, false); this.editLore = editLore; } public List getEditLore() { return editLore; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void refreshViews(WarpCategory warpCategory) { refreshViews(view -> view.warpCategory.equals(warpCategory)); } public void closeViews(WarpCategory warpCategory) { closeViews(view -> view.getWarpCategory().equals(warpCategory)); } @Nullable public static MenuWarps createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("warps.yml", MenuWarps::convertOldGUI, new WarpPagedObjectButton.Builder()); if (menuParseResult == null) return null; YamlConfiguration cfg = menuParseResult.getConfig(); List editLore = cfg.getStringList("edit-lore"); ItemStack defaultWarpIcon = menuParseResult.getLayoutBuilder().build().getButtons().stream() .filter(button -> button.getViewButtonType().equals(WarpPagedObjectButton.class)) .findFirst().map(MenuTemplateButton::getButtonItem) .orElse(null); WarpIcons.DEFAULT_WARP_ICON = new TemplateItem(defaultWarpIcon == null ? new ItemBuilder(Material.AIR) : new ItemBuilder(defaultWarpIcon)); return new MenuWarps(menuParseResult, editLore); } public static class Args extends IslandViewArgs { private final WarpCategory warpCategory; public Args(WarpCategory warpCategory) { super(warpCategory.getIsland()); this.warpCategory = warpCategory; } } public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; private final WarpCategory warpCategory; private final boolean hasManagePerms; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); this.warpCategory = args.warpCategory; this.hasManagePerms = warpCategory.getIsland().isMember(inventoryViewer) && warpCategory.getIsland().hasPermission(inventoryViewer, IslandPrivileges.SET_WARP); } @Override public Island getIsland() { return island; } @Override protected List requestObjects() { boolean isMember = warpCategory.getIsland().isMember(getInventoryViewer()); return new SequentialListBuilder() .filter(islandWarp -> isMember || !islandWarp.hasPrivateFlag()) .build(warpCategory.getWarps()); } public WarpCategory getWarpCategory() { return warpCategory; } public boolean hasManagePerms() { return hasManagePerms; } } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/warps-gui.yml"); if (!oldFile.exists()) return false; //We want to reset the items of newMenu. ConfigurationSection itemsSection = newMenu.createSection("items"); ConfigurationSection soundsSection = newMenu.createSection("sounds"); ConfigurationSection commandsSection = newMenu.createSection("commands"); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(oldFile); newMenu.set("title", cfg.getString("warps-gui.title")); int size = cfg.getInt("warps-gui.size"); char[] patternChars = new char[size * 9]; Arrays.fill(patternChars, '\n'); int charCounter = 0; if (cfg.isConfigurationSection("warps-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("warps-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } char slotsChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; MenuConverter.convertPagedButtons(cfg.getConfigurationSection("warps-gui"), cfg.getConfigurationSection("warps-gui.warp-item"), newMenu, patternChars, slotsChar, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++], itemsSection, commandsSection, soundsSection); newMenu.set("pattern", MenuConverter.buildPattern(size, patternChars, AbstractMenuLayout.BUTTON_SYMBOLS[charCounter])); return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuBlank.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl.internal; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton; import com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; import java.util.Arrays; public class MenuBlank extends AbstractMenu { private MenuBlank(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_BLANK, parseResult); } @Override protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused, @Nullable MenuView previousMenuView) { return new BaseMenuView(superiorPlayer, previousMenuView, this); } public static MenuBlank createInstance() { Sound sound; try { sound = Sound.valueOf("BLOCK_ANVIL_PLACE"); } catch (Throwable error) { sound = Sound.ANVIL_LAND; } RegularMenuLayoutImpl.Builder patternBuilder = RegularMenuLayoutImpl.newBuilder(); patternBuilder.setTitle("" + ChatColor.RED + ChatColor.BOLD + "ERROR"); patternBuilder.setRowsCount(3); DummyButton.Builder button = new DummyButton.Builder<>(); button.setButtonItem(new TemplateItem(new ItemBuilder(Material.BEDROCK) .withName("&cUnloaded Menu") .withLore(Arrays.asList( "&7There was an issue with loading the menu.", "&7Contact administrator to fix the issue.") ))); button.setClickSound(new GameSoundImpl(sound, 0.2f, 0.2f)); patternBuilder.setButton(13, button.build()); return new MenuBlank(new MenuParseResult<>(patternBuilder)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuConfigEditor.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl.internal; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.impl.ConfigEditorPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.ConfigEditorSaveButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton; import com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.ItemStack; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; public class MenuConfigEditor extends AbstractPagedMenu { private final File configFile; private final CommentedConfiguration config = new CommentedConfiguration(); private final String[] ignorePaths; private MenuConfigEditor(MenuParseResult parseResult, File configFile, String[] ignorePaths) { super(MenuIdentifiers.MENU_CONFIG_EDITOR, parseResult, true); this.configFile = configFile; this.ignorePaths = ignorePaths; this.reloadConfig(); } public CommentedConfiguration getConfig() { return config; } @Override protected View createViewInternal(SuperiorPlayer superiorPlayer, MenuConfigEditor.Args args, @Nullable MenuView previousMenuView) { return new View(superiorPlayer, previousMenuView, this, args); } public void saveConfig(SaveCallback onSave) { try { config.save(this.configFile); onSave.accept(this.config); } catch (Exception error) { Log.error(error, "An unexpected error occurred while saving config file:"); } } public void reloadConfig() { try { config.load(this.configFile); } catch (Exception error) { Log.error(error, "An unexpected error occurred while reloading config file:"); } } public void updateConfig(Player player, String path, Object value) { config.set(path, value); player.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "SuperiorSkyblock" + ChatColor.GRAY + " Changed value of " + path + " to " + value); } public static MenuConfigEditor createInstance() { PagedMenuLayoutImpl.Builder patternBuilder = PagedMenuLayoutImpl.newBuilder(); patternBuilder.setTitle(ChatColor.BOLD + "Settings Editor"); patternBuilder.setInventoryType(InventoryType.CHEST); patternBuilder.setRowsCount(6); patternBuilder.setButton(47, new DummyButton.Builder() .setButtonItem(new TemplateItem(new ItemBuilder(Material.PAPER).withName("{0}Previous Page"))) .build()); patternBuilder.setPreviousPageSlots(Collections.singletonList(47)); patternBuilder.setButton(49, new DummyButton.Builder() .setButtonItem(new TemplateItem(new ItemBuilder(Materials.SUNFLOWER.toBukkitType()) .withName("&aCurrent Page").withLore("&7Page {0}"))) .build()); patternBuilder.setCurrentPageSlots(Collections.singletonList(49)); patternBuilder.setButton(51, new DummyButton.Builder() .setButtonItem(new TemplateItem(new ItemBuilder(Material.PAPER).withName("{0}Next Page"))) .build()); patternBuilder.setNextPageSlots(Collections.singletonList(51)); patternBuilder.setPagedObjectSlots(IntStream.range(0, 36).boxed().collect(Collectors.toList()), new ConfigEditorPagedObjectButton.Builder()); patternBuilder.setButtons(IntStream.range(36, 45).boxed().collect(Collectors.toList()), new DummyButton.Builder().setButtonItem(new TemplateItem( new ItemBuilder(Materials.BLACK_STAINED_GLASS_PANE.toBukkitItem()).withName(" "))) .build()); patternBuilder.setButton(40, new ConfigEditorSaveButton.Builder().build()); return new MenuConfigEditor(new MenuParseResult<>(patternBuilder), new File(plugin.getDataFolder(), "config.yml"), new String[]{"database", "max-island-size", "island-roles", "worlds.normal-world", "commands-cooldown", "starter-chest", "event-commands"}); } public interface SaveCallback { void accept(CommentedConfiguration config) throws Exception; } public static class Args implements ViewArgs { public static final Args ROOT = new Args(""); private final String path; public Args(String path) { this.path = path; } } public class View extends AbstractPagedMenuView { private final List pathSlots = new LinkedList<>(); private final String path; View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.path = args.path; } public List getPathSlots() { return pathSlots; } public String getPath() { return path; } @Override public String replaceTitle(String title) { return path.isEmpty() ? title : ChatColor.BOLD + "Section: " + path; } @Override protected List requestObjects() { LinkedList itemStacks = new LinkedList<>(); buildFromSection(itemStacks, config.getConfigurationSection(this.path)); return Collections.unmodifiableList(itemStacks); } private void buildFromSection(List itemStacks, ConfigurationSection section) { pathSlots.clear(); for (String path : section.getKeys(false)) { String fullPath = section.getCurrentPath().isEmpty() ? path : section.getCurrentPath() + "." + path; if (Arrays.stream(ignorePaths).anyMatch(fullPath::contains)) continue; ItemBuilder itemBuilder = new ItemBuilder(Materials.CLOCK.toBukkitItem()).withName("&6" + Formatters.CAPITALIZED_FORMATTER.format(path.replace("-", "_") .replace(".", "_").replace(" ", "_")) ); if (section.isBoolean(path)) itemBuilder.withLore("&7Value: " + section.getBoolean(path)); else if (section.isInt(path)) itemBuilder.withLore("&7Value: " + section.getInt(path)); else if (section.isDouble(path)) itemBuilder.withLore("&7Value: " + section.getDouble(path)); else if (section.isString(path)) itemBuilder.withLore("&7Value: " + section.getString(path)); else if (section.isList(path)) itemBuilder.withLore("&7Value:", section.getStringList(path)); else if (section.isConfigurationSection(path)) itemBuilder.withLore("&7Click to edit section."); pathSlots.add(path); itemStacks.add(itemBuilder.build()); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl.internal; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; public class MenuCustom extends AbstractMenu { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference messagesService = new LazyReference() { @Override protected MessagesService create() { return plugin.getServices().getService(MessagesService.class); } }; private MenuCustom(MenuParseResult parseResult, String fileName, @Nullable CommandArgs commandArgs) { super(MenuIdentifiers.MENU_CUSTOM_PREFIX + fileName, parseResult); if (commandArgs != null) plugin.getCommands().registerCommand(new CustomMenuCommand(commandArgs)); } @Override protected BaseMenuView createViewInternal(SuperiorPlayer superiorPlayer, EmptyViewArgs unused, @Nullable MenuView previousMenuView) { return new BaseMenuView(superiorPlayer, previousMenuView, this); } public static MenuCustom createInstance(File menuFile) { String fileName = menuFile.getName(); MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadCustomMenu(fileName, null); if (menuParseResult == null) return null; YamlConfiguration cfg = menuParseResult.getConfig(); CommandArgs args = null; if (cfg.isConfigurationSection("command")) { ConfigurationSection commandsSection = cfg.getConfigurationSection("command"); if (commandsSection == null) { Log.warnFromFile(fileName, "Custom menu doesn't have it's command section configured correctly, skipping..."); return null; } List aliases = commandsSection.isList("aliases") ? commandsSection.getStringList("aliases") : Arrays.asList(commandsSection.getString("aliases", "").split(", ")); String permission = commandsSection.getString("permission", ""); Map descriptions = new ArrayMap<>(); if (commandsSection.isConfigurationSection("description")) { ConfigurationSection description = commandsSection.getConfigurationSection("description"); for (String locale : description.getKeys(false)) { descriptions.put(PlayerLocales.getLocale(locale), messagesService.get().parseComponent(cfg, description.getCurrentPath() + "." + locale)); } } boolean displayCommand = commandsSection.getBoolean("display-command", false); boolean requireIsland = commandsSection.getBoolean("require-island", false); args = new CommandArgs(aliases, permission, descriptions, displayCommand, requireIsland); } return new MenuCustom(menuParseResult, fileName, args); } private static class CommandArgs { private final List aliases; private final String permission; private final Map descriptions; private final boolean displayCommand; private final boolean requireIsland; CommandArgs(List aliases, String permission, Map descriptions, boolean displayCommand, boolean requireIsland) { this.aliases = aliases; this.permission = permission; this.descriptions = descriptions; this.displayCommand = displayCommand; this.requireIsland = requireIsland; } } private class CustomMenuCommand implements ISuperiorCommand { private final CommandArgs args; public CustomMenuCommand(CommandArgs args) { this.args = args; } @Override public List getAliases() { return this.args.aliases; } @Override public String getPermission() { return this.args.permission; } @Override public String getUsage(Locale locale) { return this.args.aliases.get(0); } @Override public String getDescription(Locale locale) { return this.args.descriptions.getOrDefault(locale, EmptyMessageComponent.getInstance()).getMessage(); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public boolean displayCommand() { return this.args.displayCommand; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (this.args.requireIsland && !superiorPlayer.hasIsland()) { Message.INVALID_ISLAND.send(superiorPlayer); return; } MenuCustom.this.createView(superiorPlayer, EmptyViewArgs.INSTANCE); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/StackedBlocksDepositMenu.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.impl.internal; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; public class StackedBlocksDepositMenu implements InventoryHolder { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference stackedBlocksInteractionService = new LazyReference() { @Override protected StackedBlocksInteractionService create() { return plugin.getServices().getService(StackedBlocksInteractionService.class); } }; private final Inventory inventory; private final Location stackedBlock; public StackedBlocksDepositMenu(Location stackedBlock) { this.inventory = Bukkit.createInventory(this, 36, plugin.getSettings().getStackedBlocks().getDepositMenu().getTitle()); this.stackedBlock = stackedBlock; } @Override public Inventory getInventory() { return inventory; } public void onInteract(InventoryClickEvent e) { ItemStack itemToDeposit = null; switch (e.getAction()) { case HOTBAR_SWAP: itemToDeposit = e.getView().getBottomInventory().getItem(e.getHotbarButton()); break; case PLACE_ALL: case PLACE_ONE: case PLACE_SOME: itemToDeposit = e.getCursor(); break; case MOVE_TO_OTHER_INVENTORY: itemToDeposit = e.getCurrentItem(); break; } if (itemToDeposit == null || itemToDeposit.getType() == Material.AIR) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getWhoClicked()); InteractionResult interactionResult = stackedBlocksInteractionService.get().checkStackedBlockInteraction( superiorPlayer, stackedBlock.getBlock(), itemToDeposit); if (interactionResult != InteractionResult.SUCCESS) e.setCancelled(true); } public void onClose(InventoryCloseEvent e) { int depositAmount = 0; ItemStack blockItem = null; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); Block block = stackedBlock.getBlock(); for (ItemStack itemStack : e.getInventory().getContents()) { if (itemStack != null && itemStack.getType() != Material.AIR) { InteractionResult interactionResult = stackedBlocksInteractionService.get() .checkStackedBlockInteraction(superiorPlayer, block, itemStack); if (interactionResult == InteractionResult.SUCCESS) { depositAmount += itemStack.getAmount(); blockItem = itemStack; } else { stackedBlock.getWorld().dropItemNaturally(stackedBlock, itemStack); } } } if (depositAmount > 0) { int finalDepositAmount = depositAmount; ItemStack finalBlockItem = blockItem; InteractionResult interactionResult = stackedBlocksInteractionService.get(). handleStackedBlockPlace(superiorPlayer, block, finalDepositAmount, amount -> { int leftOvers = finalDepositAmount - amount; if (leftOvers > 0) { ItemStack toAddBack = finalBlockItem.clone(); toAddBack.setAmount(leftOvers); BukkitItems.addItem(toAddBack, e.getPlayer().getInventory(), stackedBlock); } }); if (interactionResult == InteractionResult.SUCCESS) plugin.getNMSWorld().playPlaceSound(stackedBlock); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/AbstractMenuLayout.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.layout; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import org.bukkit.Bukkit; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import java.util.Arrays; import java.util.Collection; import java.util.List; public abstract class AbstractMenuLayout> implements MenuLayout { public static final char[] BUTTON_SYMBOLS = new char[]{ '!', '@', '#', '$', '%', '^', '&', '*', '-', '_', '+', '=', '~', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '>', '<', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; private static final ReflectField INVENTORY = new ReflectField<>( new ClassInfo("inventory.CraftInventory", ClassInfo.PackageType.CRAFTBUKKIT), Object.class, "inventory").removeFinal(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; protected final String title; protected final InventoryType inventoryType; protected final MenuTemplateButton[] buttons; protected AbstractMenuLayout(String title, InventoryType inventoryType, MenuTemplateButton[] buttons) { this.title = title; this.inventoryType = inventoryType; this.buttons = buttons; } @Override public final MenuTemplateButton getButton(int slot) { return slot < 0 || slot >= this.buttons.length ? DummyButton.EMPTY_BUTTON : this.buttons[slot]; } @Override public Collection> getButtons() { return new SequentialListBuilder>().build(Arrays.asList(buttons)); } @Override public int getRowsCount() { return this.buttons.length / 9; } @Override public final Inventory buildInventory(V menuView) { String title = placeholdersService.get().parsePlaceholders(menuView.getInventoryViewer().asOfflinePlayer(), menuView instanceof AbstractMenuView ? ((AbstractMenuView) menuView).replaceTitle(this.title) : this.title); Inventory inventory = createInventory(menuView, title); populateInventory(inventory, menuView); return inventory; } protected abstract void populateInventory(Inventory inventory, V menuView); private Inventory createInventory(InventoryHolder holder, String title) { Inventory inventory; if (this.inventoryType != InventoryType.CHEST) { inventory = Bukkit.createInventory(holder, this.inventoryType, title); } else { inventory = Bukkit.createInventory(holder, this.buttons.length, title); } if (inventory.getHolder() == null) { Object menuHolder = plugin.getNMSAlgorithms().createMenuInventoryHolder(this.inventoryType, holder, title); if (menuHolder != null) INVENTORY.set(inventory, menuHolder); } return inventory; } @SuppressWarnings("unchecked") public static abstract class AbstractBuilder> implements MenuLayout.Builder { protected String title = ""; protected InventoryType inventoryType = InventoryType.CHEST; protected MenuTemplateButton[] buttons; private int rowsSize = 6; protected AbstractBuilder() { } @Override public AbstractBuilder setTitle(String title) { this.title = title; return this; } @Override public AbstractBuilder setInventoryType(InventoryType inventoryType) { this.inventoryType = inventoryType; updateButtons(); return this; } @Override public AbstractBuilder setRowsCount(int rowsCount) { this.rowsSize = rowsCount; updateButtons(); return this; } @Override public AbstractBuilder setButton(int slot, MenuTemplateButton button) { if (slot >= 0 && slot < this.buttons.length) this.buttons[slot] = button; return this; } @Override public AbstractBuilder setButtons(MenuTemplateButton[] buttons) { setRowsCount(buttons.length / 9); for (int slot = 0; slot < this.buttons.length && slot < buttons.length; ++slot) this.buttons[slot] = buttons[slot]; return this; } @Override public AbstractBuilder setButtons(List slots, MenuTemplateButton button) { for (int slot : slots) { if (slot >= 0 && slot < this.buttons.length) this.buttons[slot] = button; } return this; } @Override public AbstractBuilder mapButton(int slot, MenuTemplateButton.Builder buttonBuilder) { if (slot >= 0 && slot < this.buttons.length) { if (this.buttons[slot] == null) { this.buttons[slot] = buttonBuilder.build(); } else { this.buttons[slot] = ((AbstractMenuTemplateButton) this.buttons[slot]).applyToBuilder(buttonBuilder).build(); } } return this; } @Override public AbstractBuilder mapButtons(List slots, MenuTemplateButton.Builder buttonBuilder) { for (int slot : slots) { if (slot >= 0 && slot < this.buttons.length) { if (this.buttons[slot] == null) { this.buttons[slot] = buttonBuilder.build(); } else { this.buttons[slot] = ((AbstractMenuTemplateButton) this.buttons[slot]).applyToBuilder(buttonBuilder).build(); } } } return this; } @Override public abstract MenuLayout build(); private void updateButtons() { switch (inventoryType) { case CHEST: rowsSize = Math.max(Math.min(rowsSize, 6), 1); this.buttons = new MenuTemplateButton[rowsSize * 9]; break; default: this.buttons = new MenuTemplateButton[inventoryType.getDefaultSize()]; break; } Arrays.fill(this.buttons, DummyButton.EMPTY_BUTTON); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/PagedMenuLayoutImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.layout; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.button.impl.CurrentPageButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.NextPageButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.PreviousPageButton; import com.bgsoftware.superiorskyblock.core.menu.layout.order.CustomPagedLayoutOrder; import com.bgsoftware.superiorskyblock.core.menu.layout.order.PagedLayoutOrder; import com.bgsoftware.superiorskyblock.core.mutable.MutableInt; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import java.util.Arrays; import java.util.List; public class PagedMenuLayoutImpl, E> extends AbstractMenuLayout implements PagedMenuLayout { @Nullable private final PagedLayoutOrder customLayoutOrder; private final int objectsPerPageCount; private PagedMenuLayoutImpl(String title, InventoryType inventoryType, MenuTemplateButton[] buttons, @Nullable PagedLayoutOrder layoutOrder) { super(title, inventoryType, buttons); this.customLayoutOrder = layoutOrder; this.objectsPerPageCount = layoutOrder == null ? countPagedButtons(buttons) : layoutOrder.getObjectsPerPageCount(); if (this.customLayoutOrder != null) { // Update button indexes with the custom layout order PagedLayoutOrder.MenuButtonsIterator buttonsIterator = this.customLayoutOrder.createIterator(this.buttons); int buttonIndex = 0; while (buttonsIterator.hasNext()) { MenuTemplateButton templateButton = buttonsIterator.next(); if (templateButton instanceof PagedMenuTemplateButton) ((PagedMenuTemplateButton) templateButton).setButtonIndex(buttonIndex++); } } } @Override public int getObjectsPerPageCount() { return this.objectsPerPageCount; } @Override protected void populateInventory(Inventory inventory, V menuView) { if (!(menuView instanceof PagedMenuView)) return; // noinspection unchecked PagedMenuView pagedMenuView = (PagedMenuView) menuView; MutableInt pagedObjectSlot = new MutableInt(0); // Set all regular buttons in the menu for (int slot = 0; slot < this.buttons.length; ++slot) { MenuViewButton button = this.buttons[slot].createViewButton(menuView); if (this.customLayoutOrder != null && button instanceof PagedMenuViewButton) continue; populateInventoryWithButton(inventory, button, slot, pagedMenuView, pagedObjectSlot); } if (this.customLayoutOrder == null) return; PagedLayoutOrder.MenuButtonsIterator buttonsIterator = this.customLayoutOrder.createIterator(this.buttons); while (buttonsIterator.hasNext()) { MenuTemplateButton templateButton = buttonsIterator.next(); if (!(templateButton instanceof PagedMenuTemplateButton)) continue; MenuViewButton button = templateButton.createViewButton(menuView); int slot = buttonsIterator.getSlot(); populateInventoryWithButton(inventory, button, slot, pagedMenuView, pagedObjectSlot); } } private void populateInventoryWithButton(Inventory inventory, MenuViewButton button, int slot, PagedMenuView menuView, MutableInt pagedObjectSlot) { int currentPage = menuView.getCurrentPage(); List pagedObjects = menuView.getPagedObjects(); if (button instanceof PagedMenuViewButton) { PagedMenuViewButton pagedMenuButton = (PagedMenuViewButton) button; int objectIndex = pagedObjectSlot.get() + (this.objectsPerPageCount * (currentPage - 1)); pagedObjectSlot.set(pagedObjectSlot.get() + 1); if (objectIndex >= pagedObjects.size()) { inventory.setItem(slot, ((PagedMenuTemplateButton) pagedMenuButton.getTemplate()).getNullItem()); return; } else { pagedMenuButton.updateObject(pagedObjects.get(objectIndex)); } } ItemStack buttonItem; try { buttonItem = button.createViewItem(); } catch (Exception error) { Log.entering("ENTER", slot); Log.error(error, "An unexpected error occurred while setting up menu:"); return; } if (buttonItem == null) return; if (button instanceof PreviousPageButton) { inventory.setItem(slot, new ItemBuilder(buttonItem) .replaceAll("{0}", (currentPage == 1 ? "&c" : "&a")) .build(menuView.getInventoryViewer())); } else if (button instanceof NextPageButton) { inventory.setItem(slot, new ItemBuilder(buttonItem) .replaceAll("{0}", (pagedObjects.size() > currentPage * this.objectsPerPageCount ? "&a" : "&c")) .build(menuView.getInventoryViewer())); } else if (button instanceof CurrentPageButton) { inventory.setItem(slot, new ItemBuilder(buttonItem) .replaceAll("{0}", currentPage + "") .build(menuView.getInventoryViewer())); } else { inventory.setItem(slot, buttonItem); } } private static int countPagedButtons(MenuTemplateButton[] buttons) { return (int) Arrays.stream(buttons).filter(button -> button instanceof PagedMenuTemplateButton).count(); } public static , E> Builder newBuilder() { return new Builder<>(); } public static class Builder, E> extends AbstractBuilder implements PagedMenuLayout.Builder { @Nullable private PagedLayoutOrder layoutOrder; @Override public Builder setPreviousPageSlots(List slots) { mapButtons(slots, new PreviousPageButton.Builder<>()); return this; } @Override public Builder setNextPageSlots(List slots) { mapButtons(slots, new NextPageButton.Builder<>()); return this; } @Override public Builder setCurrentPageSlots(List slots) { mapButtons(slots, new CurrentPageButton.Builder<>()); return this; } @Override public Builder setPagedObjectSlots(List slots, PagedMenuTemplateButton.Builder buttonBuilder) { mapButtons(slots, buttonBuilder); return this; } @Override public PagedMenuLayout.Builder setCustomLayoutOrder(List slotsOrder) { slotsOrder.removeIf(slot -> !(super.buttons[slot] instanceof PagedMenuTemplateButton)); if (!slotsOrder.isEmpty()) this.layoutOrder = new CustomPagedLayoutOrder<>(slotsOrder); return this; } @Override public PagedMenuLayoutImpl build() { return new PagedMenuLayoutImpl<>(super.title, super.inventoryType, super.buttons, this.layoutOrder); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/RegularMenuLayoutImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.layout; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.MenuViewButton; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; public class RegularMenuLayoutImpl> extends AbstractMenuLayout implements MenuLayout { private RegularMenuLayoutImpl(String title, InventoryType inventoryType, MenuTemplateButton[] buttons) { super(title, inventoryType, buttons); } @Override protected void populateInventory(Inventory inventory, V menuView) { // Set all buttons in the menu for (int slot = 0; slot < this.buttons.length; ++slot) { MenuViewButton button = this.buttons[slot].createViewButton(menuView); ItemStack buttonItem = button.createViewItem(); if (buttonItem != null) { inventory.setItem(slot, buttonItem); } } } public static > Builder newBuilder() { return new Builder<>(); } public static class Builder> extends AbstractBuilder implements MenuLayout.Builder { @Override public RegularMenuLayoutImpl build() { return new RegularMenuLayoutImpl<>(super.title, super.inventoryType, super.buttons); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/order/CustomPagedLayoutOrder.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.layout.order; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import java.util.ArrayList; import java.util.List; public class CustomPagedLayoutOrder> implements PagedLayoutOrder { private final List slotsOrder; public CustomPagedLayoutOrder(List slotsOrder) { this.slotsOrder = new ArrayList<>(slotsOrder); } @Override public int getObjectsPerPageCount() { return this.slotsOrder.size(); } @Override public MenuButtonsIterator createIterator(MenuTemplateButton[] buttons) { return new IteratorImpl(buttons); } private class IteratorImpl implements MenuButtonsIterator { private final MenuTemplateButton[] buttons; private int cursor = 0; private int currentSlot; private IteratorImpl(MenuTemplateButton[] buttons) { this.buttons = buttons; } @Override public int getSlot() { return this.currentSlot; } @Override public boolean hasNext() { if (this.cursor >= slotsOrder.size()) return false; int slot = slotsOrder.get(this.cursor); return slot >= 0 && slot < this.buttons.length; } @Override public MenuTemplateButton next() { this.currentSlot = slotsOrder.get(this.cursor++); return this.buttons[this.currentSlot]; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/order/PagedLayoutOrder.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.layout.order; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import java.util.Iterator; public interface PagedLayoutOrder> { int getObjectsPerPageCount(); MenuButtonsIterator createIterator(MenuTemplateButton[] buttons); interface MenuButtonsIterator> extends Iterator> { int getSlot(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractIconProviderMenu.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; public class AbstractIconProviderMenu { public static class Args implements ViewArgs { private final E iconProvider; private final TemplateItem iconTemplate; public Args(E iconProvider, TemplateItem iconTemplate) { this.iconProvider = iconProvider; this.iconTemplate = iconTemplate; } } public abstract static class View extends AbstractMenuView, Args> implements IIslandMenuView { private final E iconProvider; private final TemplateItem iconTemplate; protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu, Args> menu, Args args) { super(inventoryViewer, previousMenuView, menu); this.iconProvider = args.iconProvider; this.iconTemplate = args.iconTemplate; } public E getIconProvider() { return iconProvider; } public TemplateItem getIconTemplate() { return iconTemplate; } @Override public abstract Island getIsland(); @Override public abstract String replaceTitle(String title); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuBlank; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import java.util.Arrays; public abstract class AbstractMenuView, A extends ViewArgs> extends BaseMenuView { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private Inventory inventory; private boolean closeButton = false; private boolean nextMove = false; private boolean closed = false; private boolean refreshing = false; protected AbstractMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu) { super(inventoryViewer, menu, previousMenuView); } @Override @SuppressWarnings({"rawtypes", "unchecked"}) public void refreshView() { if (refreshing) return; refreshing = true; previousMove = false; ((AbstractMenu) menu).refreshView(this).whenComplete((view, error) -> { if (error != null) { ((Throwable) error).printStackTrace(); } else { refreshing = false; previousMove = true; } }); } @Override public void closeView() { inventoryViewer.runIfOnline(player -> { previousMove = false; player.closeInventory(); }); } @Override public Inventory getInventory() { return this.inventory; } public void setInventory(Inventory inventory) { if (closed || this.inventory != inventory) { this.inventory = inventory; this.openView(); } } public boolean isRefreshing() { return refreshing; } public void setClickedCloseButton() { closeButton = true; } public String replaceTitle(String title) { return title; } private void openView() { boolean success = openViewInternal(); if (!success) { AbstractMenu menu = (AbstractMenu) getMenu(); menu.removeView(this); } } @SuppressWarnings({"rawtypes", "unchecked"}) private boolean openViewInternal() { Player player = inventoryViewer.asPlayer(); if (player == null) return false; if (player.isSleeping()) { Message.OPEN_MENU_WHILE_SLEEPING.send(inventoryViewer); return false; } AbstractMenu menu = (AbstractMenu) getMenu(); if (!PluginEventsFactory.callPlayerOpenMenuEvent(inventoryViewer, this)) return false; Log.debug(Debug.OPEN_MENU, inventoryViewer.getName()); if (inventory == null || menu.getLayout() == null) { if (!(menu instanceof MenuBlank)) { Menus.MENU_BLANK.createView(inventoryViewer, EmptyViewArgs.INSTANCE, previousMenuView); } return false; } MenuView currentOpenedView = inventoryViewer.getOpenedView(); if (currentOpenedView instanceof AbstractMenuView) { ((AbstractMenuView) currentOpenedView).nextMove = true; } if (Arrays.equals(player.getOpenInventory().getTopInventory().getContents(), inventory.getContents())) return false; if (previousMenuView != null) previousMenuView.setPreviousMove(false); if (currentOpenedView != null && previousMenuView != currentOpenedView) currentOpenedView.setPreviousMove(false); player.openInventory(inventory); if (closed) { // If the view was closed before, we want to register it again. closed = false; menu.addView(this); } GameSoundImpl.playSound(player, menu.getOpeningSound()); this.previousMenuView = previousMenuView != null ? previousMenuView : previousMove ? currentOpenedView : null; return true; } public void onClose() { closed = true; if (!nextMove && !closeButton && plugin.getSettings().isOnlyBackButton()) { BukkitExecutor.sync(this::openView); } else if (this.previousMenuView != null && this.menu.isPreviousMoveAllowed()) { PluginEvent event = PluginEventsFactory.callPlayerCloseMenuEvent( this.inventoryViewer, this, previousMove ? this.previousMenuView : null); if (previousMove) { if (!event.isCancelled()) { MenuView newMenu = event.getArgs().newMenuView; if (newMenu != null) BukkitExecutor.sync(newMenu::refreshView); } } else if (event.isCancelled()) { BukkitExecutor.sync(this::openView); } else { previousMove = true; } } closeButton = false; nextMove = false; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractPagedMenuView.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import java.util.Collections; import java.util.List; public abstract class AbstractPagedMenuView, A extends ViewArgs, E> extends AbstractMenuView implements PagedMenuView { private List objects; private int currentPage = 1; public AbstractPagedMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu) { super(inventoryViewer, previousMenuView, menu); } @Override public void setCurrentPage(int currentPage) { Preconditions.checkArgument(currentPage >= 1, "invalid page " + currentPage); if (this.currentPage == currentPage) return; this.currentPage = currentPage; setPreviousMove(false); refreshView(); } @Override public int getCurrentPage() { return currentPage; } @Override public List getPagedObjects() { if (this.objects == null) updatePagedObjects(); return Collections.unmodifiableList(this.objects); } @Override public void updatePagedObjects() { this.objects = requestObjects(); } @Override public void refreshView() { updatePagedObjects(); super.refreshView(); } protected abstract List requestObjects(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/BaseMenuView.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; public class BaseMenuView extends AbstractMenuView { public BaseMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu) { super(inventoryViewer, previousMenuView, menu); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IIslandMenuView.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view; import com.bgsoftware.superiorskyblock.api.island.Island; public interface IIslandMenuView { Island getIsland(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IPlayerMenuView.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public interface IPlayerMenuView { @Nullable SuperiorPlayer getSuperiorPlayer(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/MenuViewWrapper.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.inventory.Inventory; public class MenuViewWrapper implements ISuperiorMenu { private final MenuView menuView; @SuppressWarnings("deprecation") public static ISuperiorMenu fromView(@Nullable MenuView menuView) { return menuView == null || menuView instanceof ISuperiorMenu ? (ISuperiorMenu) menuView : new MenuViewWrapper(menuView); } private MenuViewWrapper(MenuView menuView) { this.menuView = menuView; } @Override public void cloneAndOpen(@Nullable ISuperiorMenu previousMenu) { this.menuView.setPreviousMenuView(previousMenu, false); this.menuView.refreshView(); } @Nullable @Override public ISuperiorMenu getPreviousMenu() { return new MenuViewWrapper(menuView.getPreviousMenuView()); } @Override public SuperiorPlayer getInventoryViewer() { return menuView.getInventoryViewer(); } @Nullable @Override public MenuView getPreviousMenuView() { return menuView.getPreviousMenuView(); } @SuppressWarnings("rawtypes") @Override public void setPreviousMenuView(@Nullable MenuView previousMenuView, boolean keepOlderViews) { menuView.setPreviousMenuView(previousMenuView, keepOlderViews); } @Override public Menu getMenu() { return menuView.getMenu(); } @Override public void setPreviousMove(boolean previousMove) { menuView.setPreviousMove(previousMove); } @Override public boolean isPreviousMenu() { return menuView.isPreviousMenu(); } @Override public Inventory getInventory() { return menuView.getInventory(); } @Override public void refreshView() { this.menuView.refreshView(); } @Override public void closeView() { this.menuView.closeView(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/args/EmptyViewArgs.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view.args; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; public class EmptyViewArgs implements ViewArgs { public static final EmptyViewArgs INSTANCE = new EmptyViewArgs(); private EmptyViewArgs() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/args/IslandViewArgs.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view.args; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; public class IslandViewArgs implements ViewArgs { private final Island island; public IslandViewArgs(Island island) { this.island = island; } public Island getIsland() { return island; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/args/PlayerViewArgs.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view.args; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public class PlayerViewArgs implements ViewArgs { private final SuperiorPlayer superiorPlayer; public PlayerViewArgs(SuperiorPlayer superiorPlayer) { this.superiorPlayer = superiorPlayer; } public SuperiorPlayer getSuperiorPlayer() { return superiorPlayer; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/IslandMenuView.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; public class IslandMenuView extends AbstractMenuView implements IIslandMenuView { private final Island island; public IslandMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); } @Override public Island getIsland() { return island; } @Override public String replaceTitle(String title) { return title.replace("{}", this.island.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/PlayerMenuView.java ================================================ package com.bgsoftware.superiorskyblock.core.menu.view.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs; public class PlayerMenuView extends AbstractMenuView implements IPlayerMenuView { private final SuperiorPlayer superiorPlayer; public PlayerMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, Menu menu, PlayerViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.superiorPlayer = args.getSuperiorPlayer(); } @Override public SuperiorPlayer getSuperiorPlayer() { return this.superiorPlayer; } @Override public String replaceTitle(String title) { return title.replace("{}", this.superiorPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java ================================================ package com.bgsoftware.superiorskyblock.core.messages; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.component.impl.ComplexMessageComponent; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.io.File; import java.io.InputStream; import java.util.Collection; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; public enum Message { ADMIN_ADD_PLAYER, ADMIN_ADD_PLAYER_NAME, ADMIN_DEPOSIT_MONEY, ADMIN_DEPOSIT_MONEY_NAME, ADMIN_HELP_FOOTER, ADMIN_HELP_HEADER, ADMIN_HELP_LINE, ADMIN_HELP_NEXT_PAGE, ALREADY_IN_ISLAND, ALREADY_IN_ISLAND_OTHER, BANK_DEPOSIT_COMPLETED, BANK_DEPOSIT_CUSTOM, BANK_LIMIT_EXCEED, BANK_WITHDRAW_COMPLETED, BANK_WITHDRAW_CUSTOM, BANNED_FROM_ISLAND, BAN_ANNOUNCEMENT, BAN_PLAYERS_WITH_LOWER_ROLE, BLOCK_COUNTS_CHECK, BLOCK_COUNTS_CHECK_EMPTY, BLOCK_COUNTS_CHECK_MATERIAL, BLOCK_COUNT_CHECK, BLOCK_LEVEL, BLOCK_LEVEL_WORTHLESS, BLOCK_VALUE, BLOCK_VALUE_WORTHLESS, BONUS_SYNC_ALL, BONUS_SYNC_NAME, BONUS_SYNC, BORDER_PLAYER_COLOR_NAME_BLUE, BORDER_PLAYER_COLOR_NAME_GREEN, BORDER_PLAYER_COLOR_NAME_RED, BORDER_PLAYER_COLOR_UPDATED, BUILD_OUTSIDE_ISLAND, CANNOT_SET_ROLE, CHANGED_BANK_LIMIT, CHANGED_BANK_LIMIT_ALL, CHANGED_BANK_LIMIT_NAME, CHANGED_BIOME, CHANGED_BIOME_ALL, CHANGED_BIOME_NAME, CHANGED_BIOME_OTHER, CHANGED_BLOCK_AMOUNT, CHANGED_BLOCK_LIMIT, CHANGED_BLOCK_LIMIT_ALL, CHANGED_BLOCK_LIMIT_NAME, CHANGED_BONUS_LEVEL, CHANGED_BONUS_LEVEL_ALL, CHANGED_BONUS_LEVEL_NAME, CHANGED_BONUS_WORTH, CHANGED_BONUS_WORTH_ALL, CHANGED_BONUS_WORTH_NAME, CHANGED_CHEST_SIZE, CHANGED_CHEST_SIZE_ALL, CHANGED_CHEST_SIZE_NAME, CHANGED_COOP_LIMIT, CHANGED_COOP_LIMIT_ALL, CHANGED_COOP_LIMIT_NAME, CHANGED_CROP_GROWTH, CHANGED_CROP_GROWTH_ALL, CHANGED_CROP_GROWTH_NAME, CHANGED_DISCORD, CHANGED_ENTITY_LIMIT, CHANGED_ENTITY_LIMIT_ALL, CHANGED_ENTITY_LIMIT_NAME, CHANGED_ISLAND_EFFECT_LEVEL, CHANGED_ISLAND_EFFECT_LEVEL_ALL, CHANGED_ISLAND_EFFECT_LEVEL_NAME, CHANGED_ISLAND_SIZE, CHANGED_ISLAND_SIZE_ALL, CHANGED_ISLAND_SIZE_BUILD_OUTSIDE, CHANGED_ISLAND_SIZE_NAME, CHANGED_LANGUAGE, CHANGED_MOB_DROPS, CHANGED_MOB_DROPS_ALL, CHANGED_MOB_DROPS_NAME, CHANGED_NAME, CHANGED_NAME_OTHER, CHANGED_NAME_OTHER_NAME, CHANGED_PAYPAL, CHANGED_ROLE_LIMIT, CHANGED_ROLE_LIMIT_ALL, CHANGED_ROLE_LIMIT_NAME, CHANGED_SPAWNER_RATES, CHANGED_SPAWNER_RATES_ALL, CHANGED_SPAWNER_RATES_NAME, CHANGED_TEAM_LIMIT, CHANGED_TEAM_LIMIT_ALL, CHANGED_TEAM_LIMIT_NAME, CHANGED_TELEPORT_LOCATION, CHANGED_WARPS_LIMIT, CHANGED_WARPS_LIMIT_ALL, CHANGED_WARPS_LIMIT_NAME, CHANGE_PERMISSION_FOR_HIGHER_ROLE, COMMAND_ARGUMENT_ALL_ISLANDS("*"), COMMAND_ARGUMENT_ALL_MATERIALS("*"), COMMAND_ARGUMENT_ALL_MISSIONS("*"), COMMAND_ARGUMENT_ALL_PLAYERS("*"), COMMAND_ARGUMENT_AMOUNT("amount"), COMMAND_ARGUMENT_BIOME("biome"), COMMAND_ARGUMENT_BORDER_COLOR("border-color"), COMMAND_ARGUMENT_COMMAND("command..."), COMMAND_ARGUMENT_DIMENSION("dimension"), COMMAND_ARGUMENT_DISCORD("discord..."), COMMAND_ARGUMENT_EFFECT("effect"), COMMAND_ARGUMENT_EMAIL("email"), COMMAND_ARGUMENT_ENTITY("entity"), COMMAND_ARGUMENT_ISLAND_NAME("island-name"), COMMAND_ARGUMENT_ISLAND_ROLE("island-role"), COMMAND_ARGUMENT_LEADER("leader"), COMMAND_ARGUMENT_LEVEL("level"), COMMAND_ARGUMENT_LIMIT("limit"), COMMAND_ARGUMENT_MATERIAL("material"), COMMAND_ARGUMENT_MENU("menu-name"), COMMAND_ARGUMENT_MESSAGE("message..."), COMMAND_ARGUMENT_MISSION_CATEGORY("mission-category"), COMMAND_ARGUMENT_MISSION_NAME("mission-name"), COMMAND_ARGUMENT_MODULE_NAME("module-name"), COMMAND_ARGUMENT_MULTIPLIER("multiplier"), COMMAND_ARGUMENT_NEW_LEADER("new-leader"), COMMAND_ARGUMENT_PAGE("page"), COMMAND_ARGUMENT_PATH("path"), COMMAND_ARGUMENT_PERMISSION("permission"), COMMAND_ARGUMENT_PLAYER_NAME("player-name"), COMMAND_ARGUMENT_PRIVATE("private"), COMMAND_ARGUMENT_RATING("rating"), COMMAND_ARGUMENT_ROWS("rows"), COMMAND_ARGUMENT_SCHEMATIC_NAME("schematic-name"), COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR("save-air"), COMMAND_ARGUMENT_SETTINGS("settings"), COMMAND_ARGUMENT_SIZE("size"), COMMAND_ARGUMENT_TIME("time"), COMMAND_ARGUMENT_TITLE_DURATION("duration"), COMMAND_ARGUMENT_TITLE_FADE_IN("fade-in"), COMMAND_ARGUMENT_TITLE_FADE_OUT("fade-out"), COMMAND_ARGUMENT_UPGRADE_NAME("upgrade-name"), COMMAND_ARGUMENT_VALUE("value"), COMMAND_ARGUMENT_WARP_CATEGORY("warp-category"), COMMAND_ARGUMENT_WARP_NAME("warp-name"), COMMAND_ARGUMENT_WORLD("world"), COMMAND_COOLDOWN_FORMAT, COMMAND_DESCRIPTION_ACCEPT, COMMAND_DESCRIPTION_ADMIN, COMMAND_DESCRIPTION_ADMIN_ADD, COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT, COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT, COMMAND_DESCRIPTION_ADMIN_ADD_BONUS, COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT, COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH, COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT, COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT, COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR, COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS, COMMAND_DESCRIPTION_ADMIN_ADD_SIZE, COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES, COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT, COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT, COMMAND_DESCRIPTION_ADMIN_BONUS, COMMAND_DESCRIPTION_ADMIN_BYPASS, COMMAND_DESCRIPTION_ADMIN_CHEST, COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR, COMMAND_DESCRIPTION_ADMIN_CLOSE, COMMAND_DESCRIPTION_ADMIN_CMD_ALL, COMMAND_DESCRIPTION_ADMIN_COUNT, COMMAND_DESCRIPTION_ADMIN_DATA, COMMAND_DESCRIPTION_ADMIN_DEBUG, COMMAND_DESCRIPTION_ADMIN_DEL_WARP, COMMAND_DESCRIPTION_ADMIN_DEMOTE, COMMAND_DESCRIPTION_ADMIN_DEPOSIT, COMMAND_DESCRIPTION_ADMIN_DISBAND, COMMAND_DESCRIPTION_ADMIN_FLY, COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS, COMMAND_DESCRIPTION_ADMIN_IGNORE, COMMAND_DESCRIPTION_ADMIN_JOIN, COMMAND_DESCRIPTION_ADMIN_KICK, COMMAND_DESCRIPTION_ADMIN_MISSION, COMMAND_DESCRIPTION_ADMIN_MODULES, COMMAND_DESCRIPTION_ADMIN_MSG, COMMAND_DESCRIPTION_ADMIN_MSG_ALL, COMMAND_DESCRIPTION_ADMIN_NAME, COMMAND_DESCRIPTION_ADMIN_OPEN, COMMAND_DESCRIPTION_ADMIN_OPEN_MENU, COMMAND_DESCRIPTION_ADMIN_PROMOTE, COMMAND_DESCRIPTION_ADMIN_PURGE, COMMAND_DESCRIPTION_ADMIN_RANKUP, COMMAND_DESCRIPTION_ADMIN_RECALC, COMMAND_DESCRIPTION_ADMIN_RELOAD, COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT, COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT, COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS, COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS, COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS, COMMAND_DESCRIPTION_ADMIN_RESET_WORLD, COMMAND_DESCRIPTION_ADMIN_SCHEMATIC, COMMAND_DESCRIPTION_ADMIN_SETTINGS, COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT, COMMAND_DESCRIPTION_ADMIN_SET_BIOME, COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT, COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT, COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW, COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT, COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH, COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS, COMMAND_DESCRIPTION_ADMIN_SET_EFFECT, COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT, COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR, COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW, COMMAND_DESCRIPTION_ADMIN_SET_LEADER, COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS, COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION, COMMAND_DESCRIPTION_ADMIN_SET_RATE, COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT, COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS, COMMAND_DESCRIPTION_ADMIN_SET_SIZE, COMMAND_DESCRIPTION_ADMIN_SET_SPAWN, COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES, COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT, COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE, COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT, COMMAND_DESCRIPTION_ADMIN_SHOW, COMMAND_DESCRIPTION_ADMIN_SPAWN, COMMAND_DESCRIPTION_ADMIN_SPY, COMMAND_DESCRIPTION_ADMIN_STATS, COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS, COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES, COMMAND_DESCRIPTION_ADMIN_TELEPORT, COMMAND_DESCRIPTION_ADMIN_TITLE, COMMAND_DESCRIPTION_ADMIN_TITLE_ALL, COMMAND_DESCRIPTION_ADMIN_UNIGNORE, COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD, COMMAND_DESCRIPTION_ADMIN_WITHDRAW, COMMAND_DESCRIPTION_BALANCE, COMMAND_DESCRIPTION_BAN, COMMAND_DESCRIPTION_BANK, COMMAND_DESCRIPTION_BANS, COMMAND_DESCRIPTION_BIOME, COMMAND_DESCRIPTION_BORDER, COMMAND_DESCRIPTION_CHEST, COMMAND_DESCRIPTION_CLOSE, COMMAND_DESCRIPTION_COOP, COMMAND_DESCRIPTION_COOPS, COMMAND_DESCRIPTION_COUNTS, COMMAND_DESCRIPTION_CREATE, COMMAND_DESCRIPTION_DEL_WARP, COMMAND_DESCRIPTION_DEMOTE, COMMAND_DESCRIPTION_DEPOSIT, COMMAND_DESCRIPTION_DISBAND, COMMAND_DESCRIPTION_EXPEL, COMMAND_DESCRIPTION_FLY, COMMAND_DESCRIPTION_HELP, COMMAND_DESCRIPTION_INVITE, COMMAND_DESCRIPTION_KICK, COMMAND_DESCRIPTION_LANG, COMMAND_DESCRIPTION_LEAVE, COMMAND_DESCRIPTION_MEMBERS, COMMAND_DESCRIPTION_MISSION, COMMAND_DESCRIPTION_MISSIONS, COMMAND_DESCRIPTION_NAME, COMMAND_DESCRIPTION_OPEN, COMMAND_DESCRIPTION_PANEL, COMMAND_DESCRIPTION_PARDON, COMMAND_DESCRIPTION_PERMISSIONS, COMMAND_DESCRIPTION_PROMOTE, COMMAND_DESCRIPTION_RANKUP, COMMAND_DESCRIPTION_RATE, COMMAND_DESCRIPTION_RATINGS, COMMAND_DESCRIPTION_RECALC, COMMAND_DESCRIPTION_SETTINGS, COMMAND_DESCRIPTION_SET_DISCORD, COMMAND_DESCRIPTION_SET_PAYPAL, COMMAND_DESCRIPTION_SET_ROLE, COMMAND_DESCRIPTION_SET_TELEPORT, COMMAND_DESCRIPTION_SET_WARP, COMMAND_DESCRIPTION_SHOW, COMMAND_DESCRIPTION_TEAM, COMMAND_DESCRIPTION_TEAM_CHAT, COMMAND_DESCRIPTION_TELEPORT, COMMAND_DESCRIPTION_TOGGLE, COMMAND_DESCRIPTION_TOP, COMMAND_DESCRIPTION_TRANSFER, COMMAND_DESCRIPTION_UNCOOP, COMMAND_DESCRIPTION_UPGRADE, COMMAND_DESCRIPTION_VALUE, COMMAND_DESCRIPTION_VALUES, COMMAND_DESCRIPTION_VISIT, COMMAND_DESCRIPTION_VISITORS, COMMAND_DESCRIPTION_WARP, COMMAND_DESCRIPTION_WARPS, COMMAND_DESCRIPTION_WITHDRAW, COMMAND_USAGE, COOP_ANNOUNCEMENT, COOP_BANNED_PLAYER, COOP_LIMIT_EXCEED, CREATE_ISLAND, CREATE_ISLAND_FAILURE, CREATE_WORLD_FAILURE, DEBUG_MODE_DISABLED, DEBUG_MODE_ENABLED, DEBUG_MODE_FILTER_ADD, DEBUG_MODE_FILTER_CLEAR, DEBUG_MODE_FILTER_REMOVE, DELETE_WARP, DELETE_WARP_SIGN_BROKE, DEMOTED_MEMBER, DEMOTE_LEADER, DEMOTE_PLAYERS_WITH_LOWER_ROLE, DEPOSIT_ANNOUNCEMENT, DEPOSIT_ERROR, DESTROY_OUTSIDE_ISLAND, DISBANDED_ISLAND, DISBANDED_ISLAND_OTHER, DISBANDED_ISLAND_OTHER_NAME, DISBAND_ANNOUNCEMENT, DISBAND_GIVE, DISBAND_GIVE_ALL, DISBAND_GIVE_OTHER, DISBAND_ISLAND_BALANCE_REFUND, DISBAND_SET, DISBAND_SET_ALL, DISBAND_SET_OTHER, ENTER_PVP_ISLAND, EXPELLED_PLAYER, FORMAT_BILLION, FORMAT_DAYS_NAME, FORMAT_DAY_NAME, FORMAT_HOURS_NAME, FORMAT_HOUR_NAME, FORMAT_MILLION, FORMAT_MINUTES_NAME, FORMAT_MINUTE_NAME, FORMAT_QUAD, FORMAT_SECONDS_NAME, FORMAT_SECOND_NAME, FORMAT_THOUSANDS, FORMAT_TRILLION, GENERATOR_CLEARED, GENERATOR_CLEARED_ALL, GENERATOR_CLEARED_NAME, GENERATOR_UPDATED, GENERATOR_UPDATED_ALL, GENERATOR_UPDATED_NAME, GLOBAL_COMMAND_EXECUTED, GLOBAL_COMMAND_EXECUTED_NAME, GLOBAL_MESSAGE_SENT, GLOBAL_MESSAGE_SENT_NAME, GLOBAL_TITLE_SENT, GLOBAL_TITLE_SENT_NAME, GOT_BANNED, GOT_DEMOTED, GOT_EXPELLED, GOT_INVITE { @Override public void send(CommandSender sender, Locale locale, Object... args) { if (!(sender instanceof Player)) { super.send(sender, locale, args); } else { String message = getMessage(locale); if (message == null) return; BaseComponent[] baseComponents = TextComponent.fromLegacyText(message); if (!GOT_INVITE_TOOLTIP.isEmpty(locale)) { for (BaseComponent baseComponent : baseComponents) baseComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{new TextComponent(GOT_INVITE_TOOLTIP.getMessage(locale))})); } for (BaseComponent baseComponent : baseComponents) baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/" + plugin.getCommands().getLabel() + " accept " + args[0])); IMessageComponent messageComponent = ComplexMessageComponent.of(baseComponents); if (messageComponent != null) { PluginEvent event = PluginEventsFactory.callSendMessageEvent(sender, name(), messageComponent, args); if (!event.isCancelled()) event.getArgs().messageComponent.sendMessage(sender, args); } } } }, GOT_INVITE_TOOLTIP, GOT_KICKED, GOT_PROMOTED, GOT_REVOKED, GOT_UNBANNED, HIT_ISLAND_MEMBER, HIT_PLAYER_IN_ISLAND, IGNORED_ISLAND, IGNORED_ISLAND_NAME, INTERACT_OUTSIDE_ISLAND, INVALID_AMOUNT, INVALID_BIOME, INVALID_BLOCK, INVALID_BORDER_COLOR, INVALID_COMMAND, INVALID_EFFECT, INVALID_ENTITY, INVALID_ENVIRONMENT, INVALID_INTERVAL, INVALID_ISLAND, INVALID_ISLAND_LOCATION, INVALID_ISLAND_OTHER, INVALID_ISLAND_OTHER_NAME, INVALID_ISLAND_PERMISSION, INVALID_LEVEL, INVALID_LIMIT, INVALID_MATERIAL, INVALID_MATERIAL_DATA, INVALID_MENU, INVALID_MISSION, INVALID_MISSION_CATEGORY, INVALID_MODULE, INVALID_MULTIPLIER, INVALID_PAGE, INVALID_PERCENTAGE, INVALID_PLAYER, INVALID_RATE, INVALID_ROLE, INVALID_ROWS, INVALID_SCHEMATIC, INVALID_SETTINGS, INVALID_SIZE, INVALID_SLOT, INVALID_TITLE, INVALID_TOGGLE_MODE, INVALID_UPGRADE, INVALID_VISIT_LOCATION, INVALID_VISIT_LOCATION_BYPASS, INVALID_WARP, INVALID_WORLD, INVITE_ANNOUNCEMENT, INVITE_BANNED_PLAYER, INVITE_TO_FULL_ISLAND, ISLAND_ALREADY_CLOSED, ISLAND_ALREADY_EXIST, ISLAND_ALREADY_OPENED, ISLAND_BANK_EMPTY, ISLAND_BANK_SHOW, ISLAND_BANK_SHOW_OTHER, ISLAND_BANK_SHOW_OTHER_NAME, ISLAND_BEING_CALCULATED, ISLAND_CLOSED, ISLAND_CREATE_PROCCESS_REQUEST, ISLAND_CREATE_PROCESS_FAIL, ISLAND_DESCRIPTION_NONE, ISLAND_FLY_DISABLED, ISLAND_FLY_ENABLED, ISLAND_GOT_DELETED_WHILE_INSIDE, ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE, ISLAND_HELP_FOOTER, ISLAND_HELP_HEADER, ISLAND_HELP_LINE, ISLAND_HELP_NEXT_PAGE, ISLAND_INFO_ADMIN_BANK_LIMIT, ISLAND_INFO_ADMIN_BLOCKS_LIMITS, ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE, ISLAND_INFO_ADMIN_COOP_LIMIT, ISLAND_INFO_ADMIN_CROPS_MULTIPLIER, ISLAND_INFO_ADMIN_DROPS_MULTIPLIER, ISLAND_INFO_ADMIN_ENTITIES_LIMITS, ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE, ISLAND_INFO_ADMIN_GENERATOR_RATES, ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE, ISLAND_INFO_ADMIN_ISLAND_EFFECTS, ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE, ISLAND_INFO_ADMIN_ROLE_LIMITS, ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE, ISLAND_INFO_ADMIN_SIZE, ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER, ISLAND_INFO_ADMIN_TEAM_LIMIT, ISLAND_INFO_ADMIN_UPGRADES, ISLAND_INFO_ADMIN_UPGRADE_LINE, ISLAND_INFO_ADMIN_VALUE_SYNCED, ISLAND_INFO_ADMIN_WARPS_LIMIT, ISLAND_INFO_BANK, ISLAND_INFO_BONUS, ISLAND_INFO_BONUS_LEVEL, ISLAND_INFO_CREATION_TIME, ISLAND_INFO_DISCORD, ISLAND_INFO_FOOTER, ISLAND_INFO_HEADER, ISLAND_INFO_LAST_TIME_UPDATED, ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE, ISLAND_INFO_LEVEL, ISLAND_INFO_LOCATION, ISLAND_INFO_NAME, ISLAND_INFO_OWNER, ISLAND_INFO_PAYPAL, ISLAND_INFO_PLAYER_LINE, ISLAND_INFO_RATE, ISLAND_INFO_RATE_EMPTY_SYMBOL, ISLAND_INFO_RATE_FIVE_COLOR, ISLAND_INFO_RATE_FOUR_COLOR, ISLAND_INFO_RATE_ONE_COLOR, ISLAND_INFO_RATE_SYMBOL, ISLAND_INFO_RATE_THREE_COLOR, ISLAND_INFO_RATE_TWO_COLOR, ISLAND_INFO_ROLES, ISLAND_INFO_VISITORS_COUNT, ISLAND_INFO_WORTH, ISLAND_NAME_NONE, ISLAND_OPENED, ISLAND_OWNER_NONE, ISLAND_PREVIEW_BLOCK_COMMAND, ISLAND_PREVIEW_CANCEL, ISLAND_PREVIEW_CANCEL_DISTANCE, ISLAND_PREVIEW_CANCEL_TEXT, ISLAND_PREVIEW_CONFIRM_TEXT, ISLAND_PREVIEW_SET, ISLAND_PREVIEW_START, ISLAND_PROTECTED, ISLAND_PROTECTED_OPPED, ISLAND_TEAM_STATUS_FOOTER, ISLAND_TEAM_STATUS_HEADER, ISLAND_TEAM_STATUS_OFFLINE, ISLAND_TEAM_STATUS_ONLINE, ISLAND_TEAM_STATUS_ROLES, ISLAND_TOP_STATUS_OFFLINE, ISLAND_TOP_STATUS_ONLINE, ISLAND_WARP_PRIVATE, ISLAND_WARP_PUBLIC, ISLAND_WAS_CLOSED, ISLAND_WORTH_ERROR, ISLAND_WORTH_RESULT, ISLAND_WORTH_TIME_OUT, JOINED_ISLAND, JOINED_ISLAND_AS_COOP, JOINED_ISLAND_AS_COOP_NAME, JOINED_ISLAND_NAME, JOIN_ADMIN_ANNOUNCEMENT, JOIN_ANNOUNCEMENT, JOIN_FULL_ISLAND, JOIN_WHILE_IN_ISLAND, KICK_ANNOUNCEMENT, KICK_ISLAND_LEADER, KICK_PLAYERS_WITH_LOWER_ROLE, LACK_CHANGE_PERMISSION, LAST_ROLE_DEMOTE, LAST_ROLE_PROMOTE, LEAVE_ANNOUNCEMENT, LEAVE_ISLAND_AS_LEADER, LEFT_ISLAND, LEFT_ISLAND_COOP, LEFT_ISLAND_COOP_NAME, LOCK_WORLD_ANNOUNCEMENT_ALL, LOCK_WORLD_ANNOUNCEMENT_NAME, LOCK_WORLD_ANNOUNCEMENT, MATERIAL_NOT_SOLID, MAXIMUM_LEVEL, MESSAGE_SENT, MISSION_CANNOT_COMPLETE, MISSION_NOT_COMPLETE_REQUIRED_MISSIONS, MISSION_NO_AUTO_REWARD, MISSION_STATUS_COMPLETE, MISSION_STATUS_COMPLETE_ALL, MISSION_STATUS_RESET, MISSION_STATUS_RESET_ALL, MODULES_LIST, MODULES_LIST_MODULE_NAME, MODULES_LIST_SEPARATOR, MODULE_ALREADY_INITIALIZED, MODULE_INFO, MODULE_LOADED_FAILURE, MODULE_LOADED_SUCCESS, MODULE_UNLOADED_SUCCESS, NAME_ANNOUNCEMENT, NAME_ANNOUNCEMENT_OTHER, NAME_ANNOUNCEMENT_OTHER_NAME, NAME_BLACKLISTED, NAME_CHAT_FORMAT, NAME_SAME_AS_PLAYER, NAME_TOO_LONG, NAME_TOO_SHORT, NOT_ENOUGH_MONEY_TO_DEPOSIT, NOT_ENOUGH_MONEY_TO_UPGRADE, NOT_ENOUGH_MONEY_TO_WARP, NO_BAN_PERMISSION, NO_CLOSE_BYPASS, NO_CLOSE_PERMISSION, NO_COMMAND_PERMISSION, NO_COOP_PERMISSION, NO_DELETE_WARP_PERMISSION, NO_DEMOTE_PERMISSION, NO_DEPOSIT_PERMISSION, NO_DISBAND_PERMISSION, NO_EXPEL_PERMISSION, NO_INVITE_PERMISSION, NO_ISLANDS_TO_PURGE, NO_ISLAND_CHEST_PERMISSION, NO_ISLAND_INVITE, NO_KICK_PERMISSION, NO_MORE_DISBANDS, NO_MORE_WARPS, NO_NAME_PERMISSION, NO_OPEN_PERMISSION, NO_PERMISSION_CHECK_PERMISSION, NO_PROMOTE_PERMISSION, NO_RANKUP_PERMISSION, NO_RATINGS_PERMISSION, NO_SET_BIOME_PERMISSION, NO_SET_DISCORD_PERMISSION, NO_SET_HOME_PERMISSION, NO_SET_PAYPAL_PERMISSION, NO_SET_ROLE_PERMISSION, NO_SET_SETTINGS_PERMISSION, NO_SET_WARP_PERMISSION, NO_TRANSFER_PERMISSION, NO_UNCOOP_PERMISSION, NO_UPGRADE_PERMISSION, NO_WITHDRAW_PERMISSION, OPEN_MENU_WHILE_SLEEPING, PANEL_TOGGLE_OFF, PANEL_TOGGLE_ON, PERMISSIONS_RESET, PERMISSIONS_RESET_ALL, PERMISSIONS_RESET_NAME, PERMISSIONS_RESET_PLAYER, PERMISSIONS_RESET_ROLES, PERMISSION_CHANGED, PERMISSION_CHANGED_ALL, PERMISSION_CHANGED_NAME, PERSISTENT_DATA_EMPTY, PERSISTENT_DATA_MODIFY, PERSISTENT_DATA_SHOW, PERSISTENT_DATA_SHOW_PATH, PERSISTENT_DATA_SHOW_VALUE, PERSISTENT_DATA_SHOW_SPACER, PERSISTENT_DATA_REMOVED, PLACEHOLDER_NO, PLACEHOLDER_YES, PLAYER_ALREADY_BANNED, PLAYER_ALREADY_COOP, PLAYER_ALREADY_IN_ISLAND, PLAYER_ALREADY_IN_ROLE, PLAYER_EXPEL_BYPASS, PLAYER_JOIN_ANNOUNCEMENT, PLAYER_NOT_BANNED, PLAYER_NOT_COOP, PLAYER_NOT_INSIDE_ISLAND, PLAYER_NOT_ONLINE, PLAYER_QUIT_ANNOUNCEMENT, PROMOTED_MEMBER, PROMOTE_PLAYERS_WITH_LOWER_ROLE, PURGED_ISLANDS, PURGE_CLEAR, RANKUP_SUCCESS, RANKUP_SUCCESS_ALL, RANKUP_SUCCESS_NAME, RATE_ANNOUNCEMENT, RATE_ALREADY_GIVEN, RATE_CHANGE_OTHER, RATE_OWN_ISLAND, RATE_REMOVE_ALL, RATE_REMOVE_ALL_ISLANDS, RATE_SUCCESS, REACHED_BLOCK_LIMIT, REACHED_ENTITY_LIMIT, RECALC_ALL_ISLANDS, RECALC_ALL_ISLANDS_DONE, RECALC_ALREADY_RUNNING, RECALC_ALREADY_RUNNING_OTHER, RECALC_PROCCESS_REQUEST, RELOAD_COMPLETED, RELOAD_PROCCESS_REQUEST, RESET_WORLD_SUCCEED, RESET_WORLD_SUCCEED_ALL, RESET_WORLD_SUCCEED_NAME, REVOKE_INVITE_ANNOUNCEMENT, SAME_NAME_CHANGE, SCHEMATIC_LEFT_SELECT, SCHEMATIC_NOT_ADDED, SCHEMATIC_NOT_READY, SCHEMATIC_PROCCESS_REQUEST, SCHEMATIC_READY_TO_CREATE, SCHEMATIC_RIGHT_SELECT, SCHEMATIC_SAVED, SELF_ROLE_CHANGE, SETTINGS_RESET, SETTINGS_RESET_ALL, SETTINGS_RESET_NAME, SETTINGS_RESET_SELF, SETTINGS_UPDATED, SETTINGS_UPDATED_ALL, SETTINGS_UPDATED_NAME, SET_UPGRADE_LEVEL, SET_UPGRADE_LEVEL_ALL, SET_UPGRADE_LEVEL_NAME, SET_WARP, SET_WARP_OUTSIDE, SIZE_BIGGER_MAX, SPAWN_PROTECTED, SPAWN_PROTECTED_OPPED, SPAWN_SET_SUCCESS, SPAWN_TELEPORT_SUCCESS, SPY_TEAM_CHAT_FORMAT, SYNC_UPGRADES, SYNC_UPGRADES_ALL, SYNC_UPGRADES_NAME, TEAM_CHAT_FORMAT, TELEPORTED_FAILED, TELEPORTED_SUCCESS, TELEPORTED_TO_WARP, TELEPORTED_TO_WARP_ANNOUNCEMENT, TELEPORT_LOCATION_OUTSIDE_ISLAND, TELEPORT_OUTSIDE_ISLAND, TELEPORT_WARMUP, TELEPORT_WARMUP_CANCEL, TITLE_SENT, TOGGLED_BYPASS_OFF, TOGGLED_BYPASS_ON, TOGGLED_FLY_OFF, TOGGLED_FLY_ON, TOGGLED_FLY_OFF_OTHER, TOGGLED_FLY_ON_OTHER, TOGGLED_SCHEMATIC_OFF, TOGGLED_SCHEMATIC_ON, TOGGLED_SPY_OFF, TOGGLED_SPY_ON, TOGGLED_STACKED_BLOCKS_OFF, TOGGLED_STACKED_BLOCKS_ON, TOGGLED_TEAM_CHAT_OFF, TOGGLED_TEAM_CHAT_ON, TOGGLED_WORLD_BORDER_OFF, TOGGLED_WORLD_BORDER_ON, TRANSFER_ADMIN, TRANSFER_ADMIN_ALREADY_LEADER, TRANSFER_ADMIN_DIFFERENT_ISLAND, TRANSFER_ADMIN_NOT_LEADER, TRANSFER_ALREADY_LEADER, TRANSFER_BROADCAST, UNBAN_ANNOUNCEMENT, UNCOOP_ANNOUNCEMENT, UNCOOP_AUTO_ANNOUNCEMENT, UNCOOP_LEFT_ANNOUNCEMENT, UNIGNORED_ISLAND, UNIGNORED_ISLAND_NAME, UNLOCK_WORLD_ANNOUNCEMENT_ALL, UNLOCK_WORLD_ANNOUNCEMENT_NAME, UNLOCK_WORLD_ANNOUNCEMENT, UNSAFE_WARP, UPDATED_PERMISSION, UPDATED_SETTINGS, UPGRADE_COOLDOWN_FORMAT, VAULT_NOT_INSTALLED, VISITOR_BLOCK_COMMAND, WARP_ALREADY_EXIST, WARP_CATEGORY_ICON_NEW_LORE, WARP_CATEGORY_ICON_NEW_NAME, WARP_CATEGORY_ICON_NEW_TYPE, WARP_CATEGORY_ICON_UPDATED, WARP_CATEGORY_ILLEGAL_NAME, WARP_CATEGORY_NAME_TOO_LONG, WARP_CATEGORY_RENAME, WARP_CATEGORY_RENAME_ALREADY_EXIST, WARP_CATEGORY_RENAME_SUCCESS, WARP_CATEGORY_SLOT, WARP_CATEGORY_SLOT_ALREADY_TAKEN, WARP_CATEGORY_SLOT_SUCCESS, WARP_ICON_NEW_LORE, WARP_ICON_NEW_NAME, WARP_ICON_NEW_TYPE, WARP_ICON_UPDATED, WARP_ILLEGAL_NAME, WARP_LOCATION_UPDATE, WARP_NAME_TOO_LONG, WARP_PRIVATE_UPDATE, WARP_PUBLIC_UPDATE, WARP_RENAME, WARP_RENAME_ALREADY_EXIST, WARP_RENAME_SUCCESS, WITHDRAWN_MONEY, WITHDRAWN_MONEY_NAME, WITHDRAW_ALL_MONEY, WITHDRAW_ANNOUNCEMENT, WITHDRAW_ERROR, WORLD_NOT_ENABLED, WORLD_NOT_UNLOCKED, CUSTOM(true) { @Override public void send(CommandSender sender, Locale locale, Object... args) { String message = args.length == 0 ? null : args[0] == null ? null : args[0].toString(); if (Text.isBlank(message)) return; boolean translateColors = args.length >= 2 && args[1] instanceof Boolean && (boolean) args[1]; if (translateColors) { message = Formatters.COLOR_FORMATTER.format(message); } for (MessagesServiceImpl.CustomComponentParser parser : messagesService.get().getCustomComponentParsers()) { Optional component = parser.parse(message); if (component.isPresent()) { component.get().sendMessage(sender); return; } } sender.sendMessage(message); } }; private static final Object[] EMPTY_ARGS = new Object[0]; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference messagesService = new LazyReference() { @Override protected MessagesServiceImpl create() { return (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class); } }; private final String defaultMessage; private final boolean isCustom; private final Map messages = new ArrayMap<>(); @Nullable private Collection delayedMessages; Message() { this(null); } Message(boolean isCustom) { this(null, isCustom, 0L, null); } Message(String defaultMessage) { this(defaultMessage, false, 0L, null); } Message(String defaultMessage, boolean isCustom, long delay, @Nullable TimeUnit delayUnit) { this.defaultMessage = defaultMessage; this.isCustom = isCustom; if (delay > 0 && delayUnit != null) delayedMessages = AutoRemovalCollection.newHashSet(delay, delayUnit); } public static void reload() { Log.info("Loading messages started..."); long startTime = System.currentTimeMillis(); convertOldFile(); PlayerLocales.clearLocales(); File langFolder = new File(plugin.getDataFolder(), "lang"); if (!langFolder.exists()) { plugin.saveResource("lang/de-DE.yml", false); plugin.saveResource("lang/en-US.yml", false); plugin.saveResource("lang/es-ES.yml", false); plugin.saveResource("lang/fr-FR.yml", false); plugin.saveResource("lang/it-IT.yml", false); plugin.saveResource("lang/iw-IL.yml", false); plugin.saveResource("lang/pl-PL.yml", false); plugin.saveResource("lang/pt-BR.yml", false); plugin.saveResource("lang/ru-RU.yml", false); plugin.saveResource("lang/tr-TR.yml", false); plugin.saveResource("lang/vi-VN.yml", false); plugin.saveResource("lang/zh-CN.yml", false); } int messagesAmount = 0; boolean countMessages = true; for (File langFile : Files.listFolderFiles(langFolder, false)) { String fileName = langFile.getName().split("\\.")[0]; Locale fileLocale; try { fileLocale = PlayerLocales.getLocale(fileName); } catch (IllegalArgumentException ex) { Log.warn("The language ", fileName, " is invalid, skipping..."); continue; } PlayerLocales.registerLocale(fileLocale); if (plugin.getSettings().getDefaultLanguage().equalsIgnoreCase(fileName)) PlayerLocales.setDefaultLocale(fileLocale); CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(langFile); try (InputStream langResourceStream = plugin.getResource("lang/" + langFile.getName())) { cfg.syncWithConfig(langFile, langResourceStream == null ? plugin.getResource("lang/en-US.yml") : langResourceStream, "lang/en-US.yml"); } catch (Exception error) { Log.error(error, "An unexpected error occurred while saving lang file ", langFile.getName(), ":"); } for (Message locale : values()) { if (!locale.isCustom()) { locale.setMessage(fileLocale, messagesService.get().parseComponent(cfg, locale.name())); if (countMessages) messagesAmount++; } } countMessages = false; } Log.info(" - Found " + messagesAmount + " messages in the language files."); Log.info("Loading messages done (Took " + (System.currentTimeMillis() - startTime) + "ms)"); } public boolean isCustom() { return isCustom; } public boolean isEmpty(Locale locale) { IMessageComponent messageContainer = getComponent(locale); return messageContainer == null || messageContainer.getType() == IMessageComponent.Type.EMPTY || messageContainer.getMessage().isEmpty(); } @Nullable public IMessageComponent getComponent(Locale locale) { return messages.get(locale); } @Nullable public String getMessage(Locale locale) { return getMessage(locale, EMPTY_ARGS); } @Nullable public String getMessage(Locale locale, Object... args) { return isEmpty(locale) ? defaultMessage : messages.get(locale).getMessage(args); } public final void send(SuperiorPlayer superiorPlayer) { send(superiorPlayer, EMPTY_ARGS); } public final void send(SuperiorPlayer superiorPlayer, Object... args) { if (PluginEventsFactory.callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args)) superiorPlayer.runIfOnline(player -> send(player, superiorPlayer.getUserLocale(), args)); } public final void send(CommandSender sender) { send(sender, EMPTY_ARGS); } public final void send(CommandSender sender, Object... args) { if (sender instanceof Player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (!PluginEventsFactory.callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args)) return; } send(sender, PlayerLocales.getLocale(sender), args); } public void send(CommandSender sender, Locale locale) { send(sender, locale, EMPTY_ARGS); } public void send(CommandSender sender, Locale locale, Object... args) { IMessageComponent messageComponent = getComponent(locale); if (messageComponent == null) return; if (sender instanceof Player) { UUID playerUUID = ((Player) sender).getUniqueId(); if (delayedMessages != null && !delayedMessages.add(playerUUID)) return; } PluginEvent event = PluginEventsFactory.callSendMessageEvent(sender, name(), messageComponent, args); if (!event.isCancelled()) { event.getArgs().messageComponent.sendMessage(sender, args); if (!(sender instanceof Player) && Log.isDebugged(Debug.SHOW_STACKTRACE)) { Thread.dumpStack(); } } } private void setMessage(Locale locale, IMessageComponent messageComponent) { messages.put(locale, messageComponent); } @SuppressWarnings("ResultOfMethodCallIgnored") private static void convertOldFile() { File file = new File(plugin.getDataFolder(), "lang.yml"); if (file.exists()) { File dest = new File(plugin.getDataFolder(), "lang/en-US.yml"); dest.getParentFile().mkdirs(); file.renameTo(dest); } } public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, Message::onSettingsUpdate); } private static void onSettingsUpdate() { for (Message message : values()) { long delay = plugin.getSettings().getMessageDelays().getOrDefault(message.name(), 0L); if (delay > 0L) message.delayedMessages = AutoRemovalCollection.newHashSet(delay, TimeUnit.MILLISECONDS); else message.delayedMessages = null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java ================================================ package com.bgsoftware.superiorskyblock.core.messages; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import org.bukkit.OfflinePlayer; import java.math.BigDecimal; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MessageContent { public static final MessageContent EMPTY = new MessageContent(Collections.emptyList()) { @Override public Optional getContent(@Nullable OfflinePlayer unused, Object... unused2) { return Optional.empty(); } }; private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); } }; private static final Pattern DEFAULT_PLACEHOLDER_PATTERN = Pattern.compile("\\{(\\d+)}"); private final List contentParts = new LinkedList<>(); public static List parse(List contents) { List messageContentsList = new LinkedList<>(); for (String content : contents) messageContentsList.add(parse(content)); return messageContentsList; } public static MessageContent parse(String content) { Matcher matcher = DEFAULT_PLACEHOLDER_PATTERN.matcher(content); List parts = new LinkedList<>(); int lastPartIdx = 0; while (matcher.find()) { StringBuilder previousPart = new StringBuilder(content.substring(lastPartIdx, matcher.start())); ArgumentPart argumentPart = null; try { int argumentIndex = Integer.parseInt(matcher.group(1)); argumentPart = ArgumentPart.fromIndex(argumentIndex); } catch (NumberFormatException error) { previousPart.append(matcher.group()); } if (previousPart.length() > 0) parts.add(new StaticPart(previousPart.toString())); if (argumentPart != null) parts.add(argumentPart); lastPartIdx = matcher.end(); } if (lastPartIdx < content.length()) parts.add(new StaticPart(content.substring(lastPartIdx))); return new MessageContent(parts); } private MessageContent(List contentParts) { this.contentParts.addAll(contentParts); } public Optional getContent(@Nullable OfflinePlayer offlinePlayer, Object... arguments) { StringBuilder content = new StringBuilder(); for (IPart part : contentParts) { if (part instanceof StaticPart) { content.append(((StaticPart) part).content); } else { int argumentIndex = ((ArgumentPart) part).argumentIndex; if (argumentIndex >= 0 && argumentIndex < arguments.length) { content.append(getArgumentString(arguments[argumentIndex])); } else { content.append("{").append(argumentIndex).append("}"); } } } if (content.length() == 0) return Optional.empty(); return Optional.of(placeholdersService.get().parsePlaceholders(offlinePlayer, content.toString())); } public static String getArgumentString(Object argument) { return argument instanceof BigDecimal ? Formatters.NUMBER_FORMATTER.format((BigDecimal) argument) : String.valueOf(argument); } private interface IPart { } private static class StaticPart implements IPart { private final String content; StaticPart(String content) { this.content = content; } } private static class ArgumentPart implements IPart { private static final ArgumentPart[] CACHED_PARTS = new ArgumentPart[]{ new ArgumentPart(0), new ArgumentPart(1), new ArgumentPart(2), new ArgumentPart(3) }; private final int argumentIndex; static ArgumentPart fromIndex(int index) { return index >= 0 && index < CACHED_PARTS.length ? CACHED_PARTS[index] : new ArgumentPart(index); } ArgumentPart(int argumentIndex) { this.argumentIndex = argumentIndex; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/EmptyMessageComponent.java ================================================ package com.bgsoftware.superiorskyblock.core.messages.component; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import org.bukkit.command.CommandSender; public class EmptyMessageComponent implements IMessageComponent { private static final EmptyMessageComponent INSTANCE = new EmptyMessageComponent(); public static EmptyMessageComponent getInstance() { return INSTANCE; } private EmptyMessageComponent() { } @Override public Type getType() { return Type.EMPTY; } @Override public String getMessage() { return ""; } @Override public void sendMessage(CommandSender sender, Object... args) { // Do nothing. } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java ================================================ package com.bgsoftware.superiorskyblock.core.messages.component; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.messages.component.impl.ActionBarComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.BossBarComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.ComplexMessageComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.SoundComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.TitleComponent; import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; import java.util.LinkedList; import java.util.List; import java.util.Optional; public class MultipleComponents implements IMessageComponent { private final List messageComponents; public static IMessageComponent parseSection(ConfigurationSection section, List customComponentParsers) { List messageComponents = new LinkedList<>(); keysLoop: for (String key : section.getKeys(false)) { if (key.equals("action-bar")) { messageComponents.add(ActionBarComponent.of(Formatters.COLOR_FORMATTER.format(section.getString(key + ".text")))); } else if (key.equals("title")) { messageComponents.add(TitleComponent.of( Formatters.COLOR_FORMATTER.format(section.getString(key + ".title")), Formatters.COLOR_FORMATTER.format(section.getString(key + ".sub-title")), section.getInt(key + ".fade-in"), section.getInt(key + ".duration"), section.getInt(key + ".fade-out") )); } else if (key.equals("sound")) { messageComponents.add(SoundComponent.of(MenuParserImpl.getInstance().getSound(section.getConfigurationSection("sound")))); } else if (key.equals("bossbar")) { BossBar.Color color; try { color = BossBar.Color.valueOf(section.getString(key + ".color").toUpperCase()); } catch (Exception error) { color = BossBar.Color.PINK; } messageComponents.add(BossBarComponent.of( Formatters.COLOR_FORMATTER.format(section.getString(key + ".message")), color, section.getInt(key + ".ticks"))); } else { String text = section.getString(key + ".text"); for (MessagesServiceImpl.CustomComponentParser parser : customComponentParsers) { Optional res = parser.parse(text); if (res.isPresent()) { messageComponents.add(res.get()); continue keysLoop; } } BaseComponent[] baseComponents = TextComponent.fromLegacyText(Formatters.COLOR_FORMATTER.format(text)); String toolTipMessage = section.getString(key + ".tooltip"); if (toolTipMessage != null) { for (BaseComponent baseComponent : baseComponents) baseComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new BaseComponent[]{new TextComponent(Formatters.COLOR_FORMATTER.format(toolTipMessage))})); } String commandMessage = section.getString(key + ".command"); if (commandMessage != null) { for (BaseComponent baseComponent : baseComponents) baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, commandMessage)); } String suggestMessage = section.getString(key + ".suggest"); if (suggestMessage != null) { for (BaseComponent baseComponent : baseComponents) baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestMessage)); } messageComponents.add(ComplexMessageComponent.of(baseComponents)); } } messageComponents.removeIf(component -> component.getType() == Type.EMPTY); return of(messageComponents); } public static IMessageComponent of(List messageComponents) { return messageComponents.isEmpty() ? EmptyMessageComponent.getInstance() : messageComponents.size() == 1 ? messageComponents.get(0) : new MultipleComponents(messageComponents); } private MultipleComponents(List messageComponents) { this.messageComponents = messageComponents; } @Override public Type getType() { return Type.MULTIPLE; } @Override @Deprecated public String getMessage() { return messageComponents.isEmpty() ? "" : messageComponents.get(0).getMessage(); } @Override public String getMessage(Object... args) { return messageComponents.isEmpty() ? "" : messageComponents.get(0).getMessage(args); } @Override public void sendMessage(CommandSender sender, Object... args) { this.messageComponents.forEach(messageComponent -> messageComponent.sendMessage(sender, args)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java ================================================ package com.bgsoftware.superiorskyblock.core.messages.component.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; public class ActionBarComponent implements IMessageComponent { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final MessageContent content; public static IMessageComponent of(@Nullable String message) { return Text.isBlank(message) ? EmptyMessageComponent.getInstance() : new ActionBarComponent(message); } private ActionBarComponent(String content) { this.content = MessageContent.parse(content); } @Override public Type getType() { return Type.ACTION_BAR; } @Override public String getMessage() { return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { this.content.getContent((Player) sender, args).ifPresent(message -> plugin.getNMSPlayers().sendActionBar((Player) sender, message)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java ================================================ package com.bgsoftware.superiorskyblock.core.messages.component.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBarsService; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.apache.logging.log4j.util.Strings; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; public class BossBarComponent implements IMessageComponent { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference bossBarsService = new LazyReference() { @Override protected BossBarsService create() { return plugin.getServices().getService(BossBarsService.class); } }; private final MessageContent content; private final BossBar.Color color; private final int ticksToRun; public static IMessageComponent of(@Nullable String message, BossBar.Color color, int ticks) { return ticks <= 0 || Strings.isBlank(message) ? EmptyMessageComponent.getInstance() : new BossBarComponent(message, color, ticks); } private BossBarComponent(String content, BossBar.Color color, int ticks) { this.content = MessageContent.parse(content); this.color = color; this.ticksToRun = ticks; } @Override public Type getType() { return Type.BOSS_BAR; } @Override public String getMessage() { return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { if (sender instanceof Player) { this.content.getContent((Player) sender, args).ifPresent(message -> bossBarsService.get().createBossBar((Player) sender, message, this.color, this.ticksToRun)); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java ================================================ package com.bgsoftware.superiorskyblock.core.messages.component.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; public class ComplexMessageComponent implements IMessageComponent { private final IWrappedComponent[] components; private final MessageContent content; public static IMessageComponent of(@Nullable BaseComponent[] baseComponents) { if (baseComponents == null || baseComponents.length == 0) return EmptyMessageComponent.getInstance(); boolean isTextEmpty = true; for (BaseComponent baseComponent : baseComponents) { if (baseComponent instanceof TextComponent && !Text.isBlank(((TextComponent) baseComponent).getText())) { isTextEmpty = false; break; } } return isTextEmpty ? EmptyMessageComponent.getInstance() : new ComplexMessageComponent(baseComponents); } private ComplexMessageComponent(BaseComponent[] baseComponents) { this.components = parseComponents(baseComponents); this.content = findTextComponentContent(baseComponents); } private static IWrappedComponent[] parseComponents(BaseComponent[] baseComponents) { IWrappedComponent[] components = new IWrappedComponent[baseComponents.length]; for (int i = 0; i < components.length; ++i) { BaseComponent curr = baseComponents[i]; IWrappedComponent wrappedComponent; if (curr instanceof TextComponent) { wrappedComponent = new ContentComponent((TextComponent) curr); } else if (curr.getHoverEvent() != null) { wrappedComponent = new HoverEventComponent(curr); } else { wrappedComponent = new ComponentHolder(curr); } components[i] = wrappedComponent; } return components; } private static MessageContent findTextComponentContent(BaseComponent[] baseComponents) { for (BaseComponent baseComponent : baseComponents) { if (baseComponent instanceof TextComponent) return MessageContent.parse(baseComponent.toLegacyText()); } return MessageContent.EMPTY; } @Override public Type getType() { return Type.COMPLEX_MESSAGE; } @Override public String getMessage() { return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { if (!(sender instanceof Player)) { this.content.getContent(null, args).ifPresent(sender::sendMessage); } else if (components.length > 0) { BaseComponent[] components = new BaseComponent[this.components.length]; for (int i = 0; i < this.components.length; ++i) components[i] = this.components[i].parse((Player) sender, args); ((Player) sender).spigot().sendMessage(components); } } private interface IWrappedComponent { BaseComponent parse(OfflinePlayer offlinePlayer, Object... args); } private static class ComponentHolder implements IWrappedComponent { private final BaseComponent handle; ComponentHolder(BaseComponent handle) { this.handle = handle; } @Override public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) { return this.handle; } } private static class ContentComponent implements IWrappedComponent { private final MessageContent content; @Nullable private final HoverEventContents hoverEventContents; @Nullable private final ClickEvent.Action clickEventAction; @Nullable private final MessageContent clickEventContent; ContentComponent(TextComponent textComponent) { this.content = MessageContent.parse(textComponent.toLegacyText()); this.hoverEventContents = textComponent.getHoverEvent() == null ? null : new HoverEventContents(textComponent.getHoverEvent()); ClickEvent clickEvent = textComponent.getClickEvent(); if (clickEvent != null) { this.clickEventAction = clickEvent.getAction(); this.clickEventContent = MessageContent.parse(clickEvent.getValue()); } else { this.clickEventAction = null; this.clickEventContent = null; } } @Override public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) { TextComponent textComponent = (TextComponent) TextComponent.fromLegacyText( this.content.getContent(offlinePlayer, args).orElse(""))[0]; if (this.hoverEventContents != null) textComponent.setHoverEvent(this.hoverEventContents.parse(offlinePlayer, args)); if (this.clickEventAction != null && this.clickEventContent != null) { textComponent.setClickEvent(new ClickEvent(this.clickEventAction, this.clickEventContent.getContent(offlinePlayer, args).orElse(""))); } return textComponent; } } private static class HoverEventComponent implements IWrappedComponent { private final BaseComponent baseComponent; private final HoverEventContents hoverEventContents; HoverEventComponent(BaseComponent baseComponent) { this.baseComponent = baseComponent; this.hoverEventContents = new HoverEventContents(baseComponent.getHoverEvent()); } @Override public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) { BaseComponent newComponent = this.baseComponent.duplicate(); newComponent.setHoverEvent(this.hoverEventContents.parse(offlinePlayer, args)); return newComponent; } } private static class HoverEventContents { private final HoverEvent.Action action; private final IWrappedComponent[] components; HoverEventContents(HoverEvent hoverEvent) { this.action = hoverEvent.getAction(); this.components = parseComponents(hoverEvent.getValue()); } HoverEvent parse(OfflinePlayer offlinePlayer, Object... args) { BaseComponent[] components = new BaseComponent[this.components.length]; for (int i = 0; i < components.length; ++i) components[i] = this.components[i].parse(offlinePlayer, args); return new HoverEvent(this.action, components); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java ================================================ package com.bgsoftware.superiorskyblock.core.messages.component.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; public class RawMessageComponent implements IMessageComponent { private final MessageContent content; public static IMessageComponent of(@Nullable String message) { return Text.isBlank(message) ? EmptyMessageComponent.getInstance() : new RawMessageComponent(message); } private RawMessageComponent(String message) { this.content = MessageContent.parse(message); } @Override public Type getType() { return Type.RAW_MESSAGE; } @Override public String getMessage() { return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { Player player = sender instanceof Player ? (Player) sender : null; this.content.getContent(player, args).ifPresent(sender::sendMessage); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/SoundComponent.java ================================================ package com.bgsoftware.superiorskyblock.core.messages.component.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; public class SoundComponent implements IMessageComponent { private final GameSound gameSound; public static IMessageComponent of(@Nullable GameSound gameSound) { return GameSoundImpl.isEmpty(gameSound) ? EmptyMessageComponent.getInstance() : new SoundComponent(gameSound); } private SoundComponent(GameSound gameSound) { this.gameSound = gameSound; } @Override public Type getType() { return Type.SOUND; } @Override public String getMessage() { return ""; } @Override public void sendMessage(CommandSender sender, Object... args) { if (sender instanceof Player) GameSoundImpl.playSound((Player) sender, gameSound); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java ================================================ package com.bgsoftware.superiorskyblock.core.messages.component.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; public class TitleComponent implements IMessageComponent { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final MessageContent titleMessage; private final MessageContent subtitleMessage; private final int fadeIn; private final int duration; private final int fadeOut; public static IMessageComponent of(@Nullable String titleMessage, @Nullable String subtitleMessage, int fadeIn, int duration, int fadeOut) { return duration <= 0 || (Text.isBlank(titleMessage) && Text.isBlank(subtitleMessage)) ? EmptyMessageComponent.getInstance() : new TitleComponent(titleMessage, subtitleMessage, fadeIn, duration, fadeOut); } private TitleComponent(@Nullable String titleMessage, @Nullable String subtitleMessage, int fadeIn, int duration, int fadeOut) { this.titleMessage = Text.isBlank(titleMessage) ? MessageContent.EMPTY : MessageContent.parse(titleMessage); this.subtitleMessage = Text.isBlank(subtitleMessage) ? MessageContent.EMPTY : MessageContent.parse(subtitleMessage); this.fadeIn = fadeIn; this.duration = duration; this.fadeOut = fadeOut; } @Override public Type getType() { return Type.TITLE; } @Override public String getMessage() { return this.titleMessage.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { return this.titleMessage.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { String titleMessage = this.titleMessage.getContent((Player) sender, args).orElse(null); String subtitleMessage = this.subtitleMessage.getContent((Player) sender, args).orElse(null); if (titleMessage != null && subtitleMessage != null) plugin.getNMSPlayers().sendTitle((Player) sender, titleMessage, subtitleMessage, this.fadeIn, this.duration, this.fadeOut); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/mutable/MutableBoolean.java ================================================ package com.bgsoftware.superiorskyblock.core.mutable; public class MutableBoolean { private boolean value; public MutableBoolean(boolean value) { this.value = value; } public boolean get() { return this.value; } public void set(boolean value) { this.value = value; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/mutable/MutableInt.java ================================================ package com.bgsoftware.superiorskyblock.core.mutable; public class MutableInt { private int value; public MutableInt(int value) { this.value = value; } public int get() { return this.value; } public void set(int value) { this.value = value; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/mutable/MutableLong.java ================================================ package com.bgsoftware.superiorskyblock.core.mutable; public class MutableLong { private long value; public MutableLong(long value) { this.value = value; } public long get() { return this.value; } public void set(long value) { this.value = value; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/mutable/MutableObject.java ================================================ package com.bgsoftware.superiorskyblock.core.mutable; public class MutableObject { private E value; public MutableObject(E value) { this.value = value; } public E getValue() { return value; } public void setValue(E value) { this.value = value; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/persistence/EmptyPersistentDataContainer.java ================================================ package com.bgsoftware.superiorskyblock.core.persistence; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType; import java.util.function.BiConsumer; public class EmptyPersistentDataContainer implements PersistentDataContainer { private static final EmptyPersistentDataContainer INSTANCE = new EmptyPersistentDataContainer(); public static EmptyPersistentDataContainer getInstance() { return INSTANCE; } private EmptyPersistentDataContainer() { } @Override public boolean has(String key) { return false; } @Override public boolean hasKeyOfType(String key, PersistentDataType type) { return false; } @Nullable @Override public T put(String key, PersistentDataType type, T value) { return null; } @Nullable @Override public R put(String key, PersistentDataType type, T value, PersistentDataType returnType) throws IllegalArgumentException, IllegalStateException { return null; } @Nullable @Override public Object remove(String key) { return null; } @Nullable @Override public T removeKeyOfType(String key, PersistentDataType type) { return null; } @Nullable @Override public T get(String key, PersistentDataType type) throws IllegalArgumentException { return null; } @Nullable @Override public Object get(String key) { return null; } @Override public T getOrDefault(String key, PersistentDataType type, T def) throws IllegalArgumentException { return def; } @Override public Object getOrDefault(String key, Object def) { return def; } @Override public boolean isEmpty() { return true; } @Override public int size() { return 0; } @Override public void forEach(BiConsumer action) { // Do nothing. } @Override public byte[] serialize() { return new byte[0]; } @Override public void load(byte[] data) { // Do nothing. } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistenceDataTypeSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.persistence; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataTypeContext; import com.bgsoftware.superiorskyblock.tag.BigDecimalTag; import com.bgsoftware.superiorskyblock.tag.ByteArrayTag; import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.DoubleTag; import com.bgsoftware.superiorskyblock.tag.FloatTag; import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.IntTag; import com.bgsoftware.superiorskyblock.tag.LongTag; import com.bgsoftware.superiorskyblock.tag.PersistentDataTag; import com.bgsoftware.superiorskyblock.tag.PersistentDataTagSerialized; import com.bgsoftware.superiorskyblock.tag.ShortTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.tag.UUIDTag; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import java.math.BigDecimal; import java.util.Map; import java.util.UUID; import java.util.function.Function; public class PersistenceDataTypeSerializer { private static final Map, Function>> CLASS_TO_NBT = new ImmutableMap.Builder, Function>>() .put(BigDecimal.class, value -> BigDecimalTag.of((BigDecimal) value)) .put(byte[].class, value -> ByteArrayTag.of((byte[]) value)) .put(Byte.class, value -> ByteTag.of((byte) value)) .put(Double.class, value -> DoubleTag.of((double) value)) .put(Float.class, value -> FloatTag.of((float) value)) .put(int[].class, value -> IntArrayTag.of((int[]) value)) .put(Integer.class, value -> IntTag.of((int) value)) .put(Long.class, value -> LongTag.of((long) value)) .put(Short.class, value -> ShortTag.of((short) value)) .put(String.class, value -> StringTag.of((String) value)) .put(UUID.class, value -> UUIDTag.of((UUID) value)) .build(); private PersistenceDataTypeSerializer() { } @Nullable public static T deserialize(Tag tag, PersistentDataType type) throws IllegalArgumentException { if (tag instanceof PersistentDataTagSerialized) { tag = ((PersistentDataTagSerialized) tag).getPersistentDataTag(type); } checkTagType(tag, type); return type.getType().cast(tag.getValue()); } public static Tag serialize(T value, PersistentDataType type) { PersistentDataTypeContext serializer = type.getContext(); if (serializer != null) return PersistentDataTag.of(value, serializer); Tag serializedTag = primitiveSerialize(value); Preconditions.checkState(serializedTag != null, "value " + value.getClass() + " doesnt have a valid serializer."); return serializedTag; } public static boolean isTagOfType(Tag tag, PersistentDataType type) { return tag instanceof PersistentDataTagSerialized ? type.getContext() != null : tag.getValue().getClass().isAssignableFrom(type.getType()); } private static void checkTagType(Tag tag, PersistentDataType type) { if (!isTagOfType(tag, type)) throw new IllegalArgumentException("Expected: " + type.getType().getName() + ", actual: " + tag.getValue().getClass()); } private static Tag primitiveSerialize(Object value) { Function> tagFunction = CLASS_TO_NBT.get(value.getClass()); return tagFunction == null ? null : tagFunction.apply(value); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistentDataContainerImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.persistence; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.PersistentDataTagSerialized; import com.bgsoftware.superiorskyblock.tag.Tag; import com.google.common.base.Preconditions; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.function.BiConsumer; import java.util.function.Consumer; public class PersistentDataContainerImpl implements PersistentDataContainer { private final E holder; private final Consumer saveFunction; private final CompoundTag innerTag = CompoundTag.of(); public PersistentDataContainerImpl(E holder, Consumer saveFunction) { this.holder = holder; this.saveFunction = saveFunction; } @Override public boolean has(String key) { return innerTag.containsKey(key); } @Override public boolean hasKeyOfType(String key, PersistentDataType type) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(type, "type parameter cannot be null"); Tag tag = innerTag.getTag(key).orElse(null); return tag != null && PersistenceDataTypeSerializer.isTagOfType(tag, type); } @Nullable @Override public T put(String key, PersistentDataType type, T value) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(type, "type parameter cannot be null"); Preconditions.checkNotNull(value, "value parameter cannot be null"); return put(key, type, value, type); } @Nullable @Override public R put(String key, PersistentDataType type, T value, PersistentDataType returnType) throws IllegalArgumentException, IllegalStateException { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(type, "type parameter cannot be null"); Preconditions.checkNotNull(value, "value parameter cannot be null"); Preconditions.checkNotNull(returnType, "returnType parameter cannot be null"); Tag oldValue = innerTag.setTag(key, PersistenceDataTypeSerializer.serialize(value, type)); this.saveFunction.accept(holder); return oldValue == null ? null : PersistenceDataTypeSerializer.deserialize(oldValue, returnType); } @Nullable @Override public Object remove(String key) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Tag oldValue = innerTag.remove(key); this.saveFunction.accept(holder); return oldValue == null ? null : oldValue.getValue(); } @Nullable @Override public T removeKeyOfType(String key, PersistentDataType type) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(type, "type parameter cannot be null"); if (!hasKeyOfType(key, type)) return null; Tag oldValue = innerTag.remove(key); this.saveFunction.accept(holder); return PersistenceDataTypeSerializer.deserialize(oldValue, type); } @Nullable @Override public T get(String key, PersistentDataType type) throws IllegalArgumentException { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(type, "type parameter cannot be null"); return _getOfType(key, type, null); } @Nullable @Override public Object get(String key) { Preconditions.checkNotNull(key, "key parameter cannot be null"); return _get(key, null); } @Override public T getOrDefault(String key, PersistentDataType type, T def) throws IllegalArgumentException { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(type, "type parameter cannot be null"); return _getOfType(key, type, def); } @Override public Object getOrDefault(String key, Object def) { Preconditions.checkNotNull(key, "key parameter cannot be null"); return _get(key, def); } @Override public boolean isEmpty() { return innerTag.isEmpty(); } @Override public int size() { return innerTag.size(); } @Override public void forEach(BiConsumer action) { innerTag.getValue().forEach((key, value) -> { action.accept(key, value.getValue()); }); } @Override public byte[] serialize() { ByteArrayOutputStream byteArrayDataOutput = new ByteArrayOutputStream(); try { innerTag.write(new DataOutputStream(byteArrayDataOutput)); } catch (IOException ignored) { } return byteArrayDataOutput.toByteArray(); } @Override public void load(byte[] data) { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data); try { this.innerTag.putAll((CompoundTag) Tag.fromStream(new DataInputStream(byteArrayInputStream), 0)); } catch (Exception error) { throw new IllegalArgumentException(error); } } @Nullable private T _getOfType(String key, PersistentDataType type, @Nullable T def) { Tag tag = innerTag.getTag(key).orElse(null); if (tag == null) { return def; } if (tag instanceof PersistentDataTagSerialized) { tag = ((PersistentDataTagSerialized) tag).getPersistentDataTag(type); innerTag.setTag(key, tag); } return PersistenceDataTypeSerializer.deserialize(tag, type); } @Nullable private Object _get(String key, @Nullable Object def) { Tag tag = innerTag.getTag(key).orElse(null); return tag == null ? def : tag.getValue(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/profiler/ProfileType.java ================================================ package com.bgsoftware.superiorskyblock.core.profiler; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; public enum ProfileType { CALCULATE_ISLAND, CREATE_ISLAND, DISBAND_ISLAND, LOAD_CHUNK, SCHEMATIC_BLOCKS_PLACE, SCHEMATIC_PLACE; private final LazyReference prettyName = new LazyReference() { @Override protected String create() { return Formatters.CAPITALIZED_FORMATTER.format(ProfileType.this.name()); } }; ProfileType() { } public String getPrettyName() { return this.prettyName.get(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/profiler/Profiler.java ================================================ package com.bgsoftware.superiorskyblock.core.profiler; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.stats.StatsProfilers; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; public class Profiler { private Profiler() { } private static final long INVALID_PROFILE_ID = -1; private static final Map profilerSessions = new ConcurrentHashMap<>(); private static final AtomicLong lastProfilerId = new AtomicLong(0); public static long start(ProfileType profileType) { return start(profileType, null); } public static long start(ProfileType profileType, @Nullable Object extra) { return start(profileType, 1, extra); } public static long start(ProfileType profileType, int stopCount) { return start(profileType, stopCount, null); } public static long start(ProfileType profileType, int stopCount, @Nullable Object extra) { ProfilerSession profilerSession; try { profilerSession = new ProfilerSession(lastProfilerId.incrementAndGet(), stopCount, profileType, extra); profilerSessions.put(profilerSession.getId(), profilerSession); return profilerSession.getId(); } catch (Throwable error) { error.printStackTrace(); return INVALID_PROFILE_ID; } } public static void end(long id) { if (id == INVALID_PROFILE_ID) return; ProfilerSession profilerSession = profilerSessions.get(id); if (profilerSession == null) return; if (profilerSession.end()) { profilerSessions.remove(id); String[] profiledData = profilerSession.dump(); Log.profile(profiledData); StatsProfilers.INSTANCE.submitProfiler(profilerSession); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/profiler/ProfilerSession.java ================================================ package com.bgsoftware.superiorskyblock.core.profiler; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class ProfilerSession { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final long id; private final AtomicInteger stopCount; private final ProfileType profileType; @Nullable private final Object extra; private final Data startData; private Data endData; public ProfilerSession(long id, int stopCount, ProfileType profileType, @Nullable Object extra) { this.id = id; this.stopCount = new AtomicInteger(stopCount); this.profileType = profileType; this.extra = extra; this.startData = new Data(); } public long getId() { return id; } public ProfileType getProfileType() { return profileType; } @Nullable public Object getExtra() { return extra; } public Data getStartData() { return startData; } public Data getEndData() { return Objects.requireNonNull(endData); } public boolean end() { boolean ended = this.stopCount.decrementAndGet() <= 0; if (ended) this.endData = new Data(); return ended; } public String[] dump() { List dump = new ArrayList<>(); dump.add("Profiler #" + this.id); dump.add(" Type: " + this.profileType.getPrettyName()); dump.add(" Time elapsed: " + TimeUnit.NANOSECONDS.toMillis(this.endData.time - this.startData.time) + "ms"); dump.add(" TPS: " + this.startData.tps + " -> " + this.endData.tps); return dump.toArray(new String[0]); } public static class Data { public final long time = System.nanoTime(); public final double tps = plugin.getNMSAlgorithms().getCurrentTps(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java ================================================ package com.bgsoftware.superiorskyblock.core.schematic; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.NumberTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.google.gson.Gson; import com.google.gson.JsonObject; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.event.inventory.InventoryType; import java.util.Collections; import java.util.Map; public class SchematicBlock { private static final ListTag EMPTY_LIST_TAG = ListTag.of(Collections.emptyList()); private static final Gson GSON = new Gson(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Location location; private final int blockId; @Nullable private final Extra extra; @Nullable private CompoundTag tileEntityData = null; public SchematicBlock(Location location, int blockId, @Nullable Extra extra) { this.location = location; this.blockId = blockId; this.extra = extra; } public int getX() { return location.getBlockX(); } public int getY() { return location.getBlockY(); } public int getZ() { return location.getBlockZ(); } public World getWorld() { return location.getWorld(); } public Location getLocation() { return location; } public int getCombinedId() { return this.blockId; } @Nullable public CompoundTag getStatesTag() { return this.extra == null ? null : this.extra.statesTag; } @Nullable public CompoundTag getOriginalTileEntity() { CompoundTag tileEntity = this.extra == null ? null : this.extra.tileEntity; return tileEntity == null ? null : tileEntity.copy(); } @Nullable public CompoundTag getTileEntityData() { return this.tileEntityData; } public void doPrePlace(Island island) { CompoundTag originalTileEntity = getOriginalTileEntity(); if (originalTileEntity == null) return; this.tileEntityData = CompoundTag.fromNBT(originalTileEntity.toNBT()); String id = this.tileEntityData.getString("id").orElse(null); if (id == null) { Log.warn("Weird tile-entity data detected: " + this.tileEntityData.getValue()); throw new RuntimeException("Detected tile-entity data with no 'id' key."); } if (isSignId(id)) { if (this.tileEntityData.containsKey("front_text")) { backFrontSignLinesReplace(this.tileEntityData, island); } else { legacySignLinesReplace(this.tileEntityData, island); } } else if (plugin.getSettings().getDefaultContainers().isEnabled() && isChestId(id)) { String inventoryType = this.tileEntityData.getString("inventoryType").orElse(null); if (inventoryType != null) { try { InventoryType containerType = InventoryType.valueOf(inventoryType); ListTag items = plugin.getSettings().getDefaultContainers().getContents(containerType); if (items != null) this.tileEntityData.setTag("Items", items.copy()); } catch (Exception ignored) { } } } } public boolean shouldPostPlace() { if (this.tileEntityData == null) return false; String id = this.tileEntityData.getString("id").orElse(null); return id != null && isSignId(id); } public void doPostPlace(Island island) { try { plugin.getNMSWorld().placeSign(island, location); } finally { this.tileEntityData = null; } } private static void backFrontSignLinesReplace(CompoundTag tileEntityData, Island island) { CompoundTag frontText = tileEntityData.getCompound("front_text").orElse(null); CompoundTag backText = tileEntityData.getCompound("back_text").orElse(null); if (frontText == null || backText == null) { // This should never occur Log.error("Invalid sign tile entity data: ", tileEntityData); } ListTag frontTextMessages = frontText.getList("messages").orElse(EMPTY_LIST_TAG); ListTag backTextMessages = backText.getList("messages").orElse(EMPTY_LIST_TAG); ListTag newFrontTextMessages = ListTag.of(StringTag.class); ListTag newBackTextMessages = ListTag.of(StringTag.class); for (int i = 0; i < 8; ++i) { ListTag messages = i < 4 ? frontTextMessages : backTextMessages; ListTag newMessages = i < 4 ? newFrontTextMessages : newBackTextMessages; int realIndex = i % 4; String line; if (i < plugin.getSettings().getDefaultSign().size()) { line = plugin.getSettings().getDefaultSign().get(i); } else { Tag tag = messages.getValue().get(realIndex); if (tag instanceof CompoundTag) { JsonObject jsonObject = new JsonObject(); for (Map.Entry> entry : ((CompoundTag) tag).entrySet()) { Tag valueTag = entry.getValue(); if (valueTag instanceof NumberTag) { // Booleans are parsed as NumberTag jsonObject.addProperty(entry.getKey(), ((NumberTag) valueTag).getValue().intValue() == 1); } else { jsonObject.addProperty(entry.getKey(), String.valueOf(valueTag.getValue())); } } line = GSON.toJson(jsonObject); } else { line = ((StringTag) tag).getValue(); } } line = parseSignPlaceholders(island, line); newMessages.addTag(StringTag.of(line)); } frontText.setTag("messages", newFrontTextMessages); backText.setTag("messages", newBackTextMessages); } private static void legacySignLinesReplace(CompoundTag tileEntityData, Island island) { boolean needSignFormat = false; for (int i = 1; i <= 4; i++) { boolean isDefaultSignLine = false; String line; if ((i - 1) >= plugin.getSettings().getDefaultSign().size()) { line = tileEntityData.getString("Text" + i).orElse(null); } else { line = plugin.getSettings().getDefaultSign().get(i - 1); if (ServerVersion.isAtLeast(ServerVersion.v1_17)) { isDefaultSignLine = true; needSignFormat = true; } } if (line != null) { tileEntityData.setString((isDefaultSignLine ? "SSB.Text" : "Text") + i, parseSignPlaceholders(island, line)); } } if (needSignFormat) tileEntityData.setByte("SSB.HasSignLines", (byte) 1); } private static String parseSignPlaceholders(Island island, String val) { return val.replace("{player}", island.getOwner().getName()) .replace("{island}", island.getName().isEmpty() ? island.getOwner().getName() : island.getName()); } public SchematicBlock setLocation(Location newBlockLoc) { return new SchematicBlock(newBlockLoc, this.blockId, this.extra); } private static boolean isSignId(String id) { return id.equals("Sign") || id.equals("minecraft:sign") || id.equals("minecraft:hanging_sign"); } private static boolean isChestId(String id) { return id.equals("Chest") || id.equals("minecraft:chest") || id.equals("minecraft:trapped_chest"); } public static class Extra { @Nullable private final CompoundTag statesTag; @Nullable private final CompoundTag tileEntity; public Extra(@Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) { this.statesTag = statesTag; this.tileEntity = tileEntity; } public CompoundTag getTileEntity() { return tileEntity; } public CompoundTag getStatesTag() { return statesTag; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlockData.java ================================================ package com.bgsoftware.superiorskyblock.core.schematic; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; public class SchematicBlockData implements Comparable { private final int combinedId; private final BlockOffset blockOffset; @Nullable private final SchematicBlock.Extra extra; public SchematicBlockData(int combinedId, BlockOffset blockOffset, @Nullable SchematicBlock.Extra extra) { this.combinedId = combinedId; this.blockOffset = blockOffset; this.extra = extra; } public BlockOffset getBlockOffset() { return blockOffset; } public int getCombinedId() { return combinedId; } @Nullable public SchematicBlock.Extra getExtra() { return extra; } @Override public int compareTo(@NotNull SchematicBlockData o) { int levelCompare = Integer.compare(blockOffset.getOffsetY(), o.blockOffset.getOffsetY()); if (levelCompare != 0) return levelCompare; int xCoordCompare = Integer.compare(blockOffset.getOffsetX(), o.blockOffset.getOffsetX()); return xCoordCompare != 0 ? xCoordCompare : Integer.compare(blockOffset.getOffsetZ(), o.blockOffset.getOffsetZ()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicEntity.java ================================================ package com.bgsoftware.superiorskyblock.core.schematic; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import org.bukkit.Location; import org.bukkit.entity.EntityType; public class SchematicEntity { private final static SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final EntityType entityType; private final CompoundTag entityTag; private final BlockOffset offset; public SchematicEntity(EntityType entityType, CompoundTag entityTag, BlockOffset offset) { this.entityType = entityType; this.entityTag = SchematicEntityFilter.filterNBTTag(entityTag); this.offset = offset; } public void spawnEntity(Location min) { plugin.getNMSTags().spawnEntity(entityType, offset.applyToLocation(min), entityTag); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicEntityFilter.java ================================================ package com.bgsoftware.superiorskyblock.core.schematic; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.tag.CompoundTag; public class SchematicEntityFilter { private SchematicEntityFilter() { } public static CompoundTag filterNBTTag(@Nullable CompoundTag entityTag) { if (entityTag != null) { entityTag.remove("UUID"); entityTag.remove("UUIDMost"); entityTag.remove("UUIDLeast"); } return entityTag; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/ISerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; public interface ISerializer { @NotNull D serialize(@Nullable S serializable); @Nullable S deserialize(@Nullable D deserializable); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.serialization.impl.BlockPositionSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.InventorySerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.ItemStack2TagSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.ItemStackSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.LocationSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.OffsetSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.WorldPositionSerializer; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; public class Serializers { public static final ISerializer INVENTORY_SERIALIZER = InventorySerializer.getInstance(); public static final ISerializer ITEM_STACK_SERIALIZER = ItemStackSerializer.getInstance(); public static final ISerializer ITEM_STACK_TO_TAG_SERIALIZER = ItemStack2TagSerializer.getInstance(); public static final ISerializer LOCATION_SPACED_CENTERED_SERIALIZER = new LocationSerializer(", ", true); public static final ISerializer LOCATION_SPACED_SERIALIZER = new LocationSerializer(", "); public static final ISerializer LOCATION_SERIALIZER = new LocationSerializer(","); public static final ISerializer BLOCK_POSITION_SERIALIZER = BlockPositionSerializer.getInstance(); public static final ISerializer WORLD_POSITION_SERIALIZER = WorldPositionSerializer.getInstance(); public static final ISerializer OFFSET_SPACED_SERIALIZER = new OffsetSerializer(", "); public static final ISerializer OFFSET_SERIALIZER = new OffsetSerializer(","); private Serializers() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/BlockPositionSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; public class BlockPositionSerializer implements ISerializer { private static final BlockPositionSerializer INSTANCE = new BlockPositionSerializer(); public static BlockPositionSerializer getInstance() { return INSTANCE; } private BlockPositionSerializer() { } @NotNull @Override public String serialize(@Nullable BlockPosition serializable) { return serializable == null ? "" : serializable.getX() + ", " + serializable.getY() + ", " + serializable.getZ(); } @Nullable @Override public BlockPosition deserialize(@Nullable String element) { if (Text.isBlank(element)) return null; try { String[] sections = element.split(", "); int startIndex = 0; if (sections.length >= 4) { // In the past, BlockPositions were serialized with a world, yaw and pitch. // Nowadays, we ignore all of them. ++startIndex; } int x = (int) Double.parseDouble(sections[startIndex++]); int y = (int) Double.parseDouble(sections[startIndex++]); int z = (int) Double.parseDouble(sections[startIndex]); return SBlockPosition.of(x, y, z); } catch (Exception error) { Log.entering("ENTER", element); Log.error(error, "An unexpected error occurred while deserializing position '" + element + "':"); return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/InventorySerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.Tag; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public class InventorySerializer implements ISerializer { private static final ItemStack[] EMPTY_CONTENTS = new ItemStack[0]; private static final byte[] EMPTY_SERIALIZED_DATA = new byte[0]; private static final byte[] EMPTY_SLOTS = new byte[0]; private static final ListTag EMPTY_ITEMS_LIST = ListTag.of(Collections.emptyList()); private static final InventorySerializer INSTANCE = new InventorySerializer(); public static InventorySerializer getInstance() { return INSTANCE; } private InventorySerializer() { } @NotNull @Override public byte[] serialize(@Nullable ItemStack[] serializable) { if (serializable == null || serializable.length == 0) return EMPTY_SERIALIZED_DATA; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DataOutputStream dataOutput = new DataOutputStream(outputStream); CompoundTag compoundTag = CompoundTag.of(); List serializedItems = new ArrayList<>(serializable.length); byte[] slots = new byte[serializable.length * 2]; for (int i = 0; i < serializable.length; ++i) { ItemStack itemStack = serializable[i]; int itemIndex = i * 2; if (itemStack == null || itemStack.getType() == Material.AIR) { slots[itemIndex] = -1; slots[itemIndex + 1] = 0; } else { ItemStack serializedItem = getSerializedItem(itemStack); int similarItemIndex = serializedItems.indexOf(serializedItem); if (similarItemIndex == -1) { slots[itemIndex] = (byte) serializedItems.size(); serializedItems.add(serializedItem); } else { slots[itemIndex] = (byte) similarItemIndex; } slots[itemIndex + 1] = (byte) itemStack.getAmount(); } } ListTag items = ListTag.of(CompoundTag.class); for (ItemStack itemStack : serializedItems) items.addTag(Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack)); compoundTag.setTag("Items", items); compoundTag.setByteArray("Slots", slots); try { compoundTag.write(dataOutput); } catch (Exception error) { Log.entering("ENTER", Arrays.asList(serializable)); Log.error(error, "An unexpected error occurred while serializing inventory:"); return EMPTY_SERIALIZED_DATA; } return outputStream.toByteArray(); } @Override public ItemStack[] deserialize(@Nullable byte[] deserializable) { if (deserializable == null || deserializable.length == 0) return EMPTY_CONTENTS; return deserialize(deserializable, true); } private static ItemStack[] deserialize(byte[] deserializable, boolean tryAgain) { ByteArrayInputStream inputStream = new ByteArrayInputStream(deserializable); CompoundTag compoundTag; try { compoundTag = (CompoundTag) Tag.fromStream(new DataInputStream(inputStream), 0); } catch (Exception error) { if (tryAgain) return deserialize(new BigInteger(new String(deserializable), 32).toByteArray(), false); Log.entering("ENTER", new String(deserializable)); Log.error(error, "An unexpected error occurred while deserializing inventory:"); return EMPTY_CONTENTS; } ItemStack[] contents; if (compoundTag.containsKey("Length")) { contents = new ItemStack[compoundTag.getInt("Length").orElse(0)]; for (int i = 0; i < contents.length; i++) { CompoundTag itemCompound = compoundTag.getCompound(i + "").orElse(null); if (itemCompound != null) contents[i] = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(itemCompound); } } else { byte[] slots = compoundTag.getByteArray("Slots").orElse(EMPTY_SLOTS); ListTag items = compoundTag.getList("Items").orElse(EMPTY_ITEMS_LIST); ItemStack[] serializedItems = new ItemStack[items.size()]; contents = new ItemStack[slots.length / 2]; for (int i = 0; i < slots.length; i += 2) { int itemIndex = slots[i]; if (itemIndex == -1 || itemIndex >= serializedItems.length) continue; int itemAmount = slots[i + 1]; if (serializedItems[itemIndex] == null) { Tag itemTag = items.getValue().get(itemIndex); if (itemTag instanceof CompoundTag) { serializedItems[itemIndex] = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize((CompoundTag) itemTag); } else { serializedItems[itemIndex] = new ItemStack(Material.AIR); } } ItemStack contentItem = serializedItems[itemIndex].clone(); contentItem.setAmount(itemAmount); contents[i / 2] = contentItem; } } return contents; } private static ItemStack getSerializedItem(ItemStack itemStack) { ItemStack serializedItem = itemStack.clone(); serializedItem.setAmount(1); return serializedItem; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/ItemStack2TagSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; public class ItemStack2TagSerializer implements ISerializer { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final ItemStack2TagSerializer INSTANCE = new ItemStack2TagSerializer(); public static ItemStack2TagSerializer getInstance() { return INSTANCE; } private ItemStack2TagSerializer() { } @Override @NotNull public CompoundTag serialize(@Nullable ItemStack serializable) { if (serializable == null) return CompoundTag.of(); return plugin.getNMSTags().serializeItem(serializable); } @Nullable @Override public ItemStack deserialize(@Nullable CompoundTag deserializable) { if (deserializable == null) return new ItemStack(Material.AIR); return plugin.getNMSTags().deserializeItem(deserializable); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/ItemStackSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.Tag; import org.bukkit.inventory.ItemStack; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.math.BigInteger; public class ItemStackSerializer implements ISerializer { private static final ItemStackSerializer INSTANCE = new ItemStackSerializer(); public static ItemStackSerializer getInstance() { return INSTANCE; } private ItemStackSerializer() { } @NotNull @Override public String serialize(@Nullable ItemStack serializable) { if (serializable == null) return ""; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DataOutputStream dataOutput = new DataOutputStream(outputStream); try { Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(serializable).write(dataOutput); } catch (Exception error) { Log.entering("ENTER", serializable); Log.error(error, "An unexpected error occurred while serializing item:"); return ""; } return new BigInteger(1, outputStream.toByteArray()).toString(32); } @Nullable @Override public ItemStack deserialize(@Nullable String deserializable) { if (Text.isBlank(deserializable)) return null; ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(deserializable, 32).toByteArray()); try { CompoundTag compoundTag = (CompoundTag) Tag.fromStream(new DataInputStream(inputStream), 0); return Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(compoundTag); } catch (Exception error) { Log.entering("ENTER", deserializable); Log.error(error, "An unexpected error occurred while deserializing item:"); return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/LocationSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; import org.bukkit.Location; public class LocationSerializer implements ISerializer { private final String separator; private final boolean center; public LocationSerializer(String separator) { this.separator = separator; this.center = false; } public LocationSerializer(String separator, boolean center) { this.separator = separator; this.center = center; } @NotNull @Override public String serialize(@Nullable Location serializable) { return serializable == null ? "" : LazyWorldLocation.getWorldName(serializable) + separator + serializable.getX() + separator + serializable.getY() + separator + serializable.getZ() + separator + serializable.getYaw() + separator + serializable.getPitch(); } @Nullable @Override public Location deserialize(@Nullable String element) { if (Text.isBlank(element)) return null; try { String[] sections = element.split(separator); double x = Double.parseDouble(sections[1]); if (center && !sections[1].contains(".")) x += 0.5; double y = Double.parseDouble(sections[2]); double z = Double.parseDouble(sections[3]); if (center && !sections[3].contains(".")) z += 0.5; float yaw = sections.length > 5 ? Float.parseFloat(sections[4]) : 0; float pitch = sections.length > 6 ? Float.parseFloat(sections[5]) : 0; return new LazyWorldLocation(sections[0], x, y, z, yaw, pitch); } catch (Exception error) { Log.entering("ENTER", element); Log.error(error, "An unexpected error occurred while deserializing location '" + element + "':"); return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/OffsetSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; public class OffsetSerializer implements ISerializer { private final String separator; public OffsetSerializer(String separator) { this.separator = separator; } @NotNull @Override public String serialize(@Nullable BlockOffset serializable) { return serializable == null ? "" : serializable.getOffsetX() + separator + serializable.getOffsetY() + separator + serializable.getOffsetZ(); } @Nullable @Override public BlockOffset deserialize(@Nullable String element) { if (Text.isBlank(element)) return null; String[] stringSections = element.split(separator); if (stringSections.length != 3) return null; try { return SBlockOffset.fromOffsets(Integer.parseInt(stringSections[0]), Integer.parseInt(stringSections[1]), Integer.parseInt(stringSections[2])); } catch (NumberFormatException error) { return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/PersistentDataSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; public class PersistentDataSerializer implements ISerializer { private static final Pattern BYTE_VALUE = Pattern.compile("^([0-9]+)b$"); private static final Pattern DOUBLE_VALUE = Pattern.compile("^([0-9.]+)d$"); private static final Pattern FLOAT_VALUE = Pattern.compile("^([0-9]+)f$"); private static final Pattern INT_VALUE = Pattern.compile("^([0-9]+)i$"); private static final Pattern LONG_VALUE = Pattern.compile("^([0-9]+)l$"); private static final Pattern SHORT_VALUE = Pattern.compile("^([0-9]+)s$"); private final Locale locale; public PersistentDataSerializer(Locale locale) { this.locale = locale; } @Override public @NotNull String serialize(@Nullable Object serializable) { if (serializable == null) return ""; String result; if (serializable instanceof Byte) { result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, "b"); } else if (serializable instanceof Double) { result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, "d"); } else if (serializable instanceof Float) { result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, "f"); } else if (serializable instanceof Integer) { result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, "i"); } else if (serializable instanceof Long) { result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, "l"); } else if (serializable instanceof Short) { result = Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, "s"); } else { result = "\"" + Message.PERSISTENT_DATA_SHOW_VALUE.getMessage(locale, serializable, "") + "\""; } return result == null ? "" : result; } @Nullable @Override public Object deserialize(@Nullable String deserializable) { if (deserializable == null) return null; Matcher matcher; if ((matcher = BYTE_VALUE.matcher(deserializable)).matches()) { return new Pair<>(Byte.parseByte(matcher.group(1)), PersistentDataType.BYTE); } else if ((matcher = DOUBLE_VALUE.matcher(deserializable)).matches()) { return new Pair<>(Double.parseDouble(matcher.group(1)), PersistentDataType.DOUBLE); } else if ((matcher = FLOAT_VALUE.matcher(deserializable)).matches()) { return new Pair<>(Float.parseFloat(matcher.group(1)), PersistentDataType.FLOAT); } else if ((matcher = INT_VALUE.matcher(deserializable)).matches()) { return new Pair<>(Integer.parseInt(matcher.group(1)), PersistentDataType.INTEGER); } else if ((matcher = LONG_VALUE.matcher(deserializable)).matches()) { return new Pair<>(Long.parseLong(matcher.group(1)), PersistentDataType.LONG); } else if ((matcher = SHORT_VALUE.matcher(deserializable)).matches()) { return new Pair<>(Short.parseShort(matcher.group(1)), PersistentDataType.SHORT); } return new Pair<>(deserializable, PersistentDataType.STRING); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java ================================================ package com.bgsoftware.superiorskyblock.core.serialization.impl; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; public class WorldPositionSerializer implements ISerializer { private static final WorldPositionSerializer INSTANCE = new WorldPositionSerializer(); public static WorldPositionSerializer getInstance() { return INSTANCE; } private WorldPositionSerializer() { } @NotNull @Override public String serialize(@Nullable WorldPosition serializable) { return serializable == null ? "" : serializable.getX() + "," + serializable.getY() + "," + serializable.getZ() + "," + serializable.getYaw() + "," + serializable.getPitch(); } @Nullable @Override public WorldPosition deserialize(@Nullable String element) { if (Text.isBlank(element)) return null; try { String[] sections = element.split(","); int startIndex = 0; if (sections.length >= 6) { // In the past, WorldPositions were serialized with a world. // Nowadays, we ignore all of them. ++startIndex; } double x = Double.parseDouble(sections[startIndex++]); double y = Double.parseDouble(sections[startIndex++]); double z = Double.parseDouble(sections[startIndex++]); float yaw = Float.parseFloat(sections[startIndex++]); float pitch = Float.parseFloat(sections[startIndex]); return SWorldPosition.of(x, y, z, yaw, pitch); } catch (Exception error) { Log.entering("ENTER", element); Log.error(error, "An unexpected error occurred while deserializing position '" + element + "':"); return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java ================================================ package com.bgsoftware.superiorskyblock.core.stackedblocks; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import org.bukkit.Location; import org.bukkit.World; public class StackedBlock { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference hologramsService = new LazyReference() { @Override protected HologramsService create() { return plugin.getServices().getService(HologramsService.class); } }; private final LazyWorldLocation location; private int amount; private Key blockKey; private Hologram hologram; private boolean removed; public StackedBlock(Location location) { this.location = LazyWorldLocation.of(location); } public LazyWorldLocation getLocation() { return location; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } public Key getBlockKey() { return blockKey; } public void setBlockKey(Key blockKey) { this.blockKey = blockKey; } public void markAsRemoved() { removed = true; removeHologram(); } public void updateName() { if (this.removed || this.amount <= 1) { removeHologram(); return; } World world = this.location.getWorld(); if (world == null) return; Key currentBlockKey = Keys.of(location.getBlock()); if (blockKey == null || blockKey.equals(ConstantKeys.AIR)) { blockKey = currentBlockKey; if (blockKey.equals(ConstantKeys.AIR)) return; } // Must be checked in order to fix issue #632 if (!currentBlockKey.equals(blockKey)) { removeHologram(); return; } if (hologram == null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = copyLocation(wrapper.getHandle()).add(0.5, 1, 0.5); hologram = hologramsService.get().createHologram(location); } } hologram.setHologramName(plugin.getSettings().getStackedBlocks().getCustomName() .replace("{0}", String.valueOf(amount)) .replace("{1}", Formatters.CAPITALIZED_FORMATTER.format(blockKey.getGlobalKey())) .replace("{2}", Formatters.NUMBER_FORMATTER.format(amount)) ); } public void removeHologram() { if (hologram != null) { hologram.removeHologram(); hologram = null; } } private Location copyLocation(Location location) { location.setX(this.location.getX()); location.setY(this.location.getY()); location.setZ(this.location.getZ()); location.setYaw(this.location.getYaw()); location.setPitch(this.location.getPitch()); location.setWorld(this.location.getWorld()); return location; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.stackedblocks; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.bridge.StackedBlocksDatabaseBridge; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.stackedblocks.container.StackedBlocksContainer; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.google.common.base.Preconditions; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; public class StackedBlocksManagerImpl extends Manager implements StackedBlocksManager { private final StackedBlocksContainer stackedBlocksContainer; private DatabaseBridge databaseBridge; public StackedBlocksManagerImpl(SuperiorSkyblockPlugin plugin, StackedBlocksContainer stackedBlocksContainer) { super(plugin); this.stackedBlocksContainer = stackedBlocksContainer; } @Override public void loadData() { initializeDatabaseBridge(); Log.info("Starting to load stacked blocks..."); AtomicBoolean updateBlockKeys = new AtomicBoolean(false); databaseBridge.loadAllObjects("stacked_blocks", _resultSet -> { DatabaseResult resultSet = new DatabaseResult(_resultSet); loadStackedBlock(resultSet); Optional item = resultSet.getString("block_type"); if (!item.isPresent() || item.get().isEmpty()) updateBlockKeys.set(true); }); if (updateBlockKeys.get()) { BukkitExecutor.sync(this::updateStackedBlockKeys); } Log.info("Finished stacked blocks!"); } @Override public int getStackedBlockAmount(Block block) { Preconditions.checkNotNull(block, "block parameter cannot be null."); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return getStackedBlockAmount(block.getLocation(wrapper.getHandle())); } } @Override public int getStackedBlockAmount(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); if (!(location instanceof LazyWorldLocation)) Preconditions.checkNotNull(location.getWorld(), "location's world cannot be null."); StackedBlock stackedBlock = this.stackedBlocksContainer.getStackedBlock(location); return stackedBlock == null ? 1 : stackedBlock.getAmount(); } @Override public Key getStackedBlockKey(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); if (!(location instanceof LazyWorldLocation)) Preconditions.checkNotNull(location.getWorld(), "location's world cannot be null."); StackedBlock stackedBlock = this.stackedBlocksContainer.getStackedBlock(location); return stackedBlock == null ? null : stackedBlock.getBlockKey(); } @Override public boolean setStackedBlock(Block block, int amount) { Preconditions.checkNotNull(block, "block parameter cannot be null."); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return setStackedBlock(block.getLocation(wrapper.getHandle()), Keys.of(block), amount); } } @Override public boolean setStackedBlock(Location location, Key blockKey, int amount) { Preconditions.checkNotNull(location, "location parameter cannot be null."); if (!(location instanceof LazyWorldLocation)) Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); Preconditions.checkNotNull(blockKey, "blockKey parameter cannot be null."); Log.debug(Debug.SET_BLOCK_AMOUNT, location, blockKey, amount); StackedBlock stackedBlock = this.stackedBlocksContainer.createStackedBlock(location); boolean succeed = true; if (stackedBlock.getBlockKey() != null && !blockKey.equals(stackedBlock.getBlockKey())) { Log.warn("Found a glitched stacked-block at ", Formatters.LOCATION_FORMATTER.format(location), " - fixing it..."); amount = 0; succeed = false; } if (amount > 1) { stackedBlock.setBlockKey(blockKey); stackedBlock.setAmount(amount); // Must be called with delay in order to fix issue #632 BukkitExecutor.sync(stackedBlock::updateName, 2L); StackedBlocksDatabaseBridge.saveStackedBlock(this, stackedBlock); } else { this.stackedBlocksContainer.removeStackedBlock(location); StackedBlocksDatabaseBridge.deleteStackedBlock(this, stackedBlock); } return succeed; } @Override public int removeStackedBlock(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); if (!(location instanceof LazyWorldLocation)) Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); StackedBlock oldStackedBlock = this.stackedBlocksContainer.removeStackedBlock(location); if (oldStackedBlock != null) { StackedBlocksDatabaseBridge.deleteStackedBlock(this, oldStackedBlock); } return oldStackedBlock == null ? 1 : oldStackedBlock.getAmount(); } @Override public Map removeStackedBlocks(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); return removeStackedBlocks(chunk.getWorld(), chunk.getX(), chunk.getZ()); } @Override public Map removeStackedBlocks(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); try (ChunkPosition chunkPosition = ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ)) { return removeStackedBlocks(chunkPosition); } } public Map removeStackedBlocks(ChunkPosition chunkPosition) { Preconditions.checkNotNull(chunkPosition, "chunkPosition parameter cannot be null."); Map removedStackedBlocks = new LinkedHashMap<>(); try { databaseBridge.batchOperations(true); this.stackedBlocksContainer.removeStackedBlocks(chunkPosition, stackedBlock -> { removedStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount()); stackedBlock.removeHologram(); StackedBlocksDatabaseBridge.deleteStackedBlock(this, stackedBlock); }); } finally { databaseBridge.batchOperations(false); } return removedStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(removedStackedBlocks); } @Override public Map getStackedBlocks(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); return getStackedBlocks(chunk.getWorld(), chunk.getX(), chunk.getZ()); } @Override public Map getStackedBlocks(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Map chunkStackedBlocks = new LinkedHashMap<>(); try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> { chunkStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount()); }); } return chunkStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(chunkStackedBlocks); } @Override public Map getStackedBlocks() { Map allStackedBlocks = new LinkedHashMap<>(); this.stackedBlocksContainer.forEach(stackedBlock -> { allStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount()); }); return allStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(allStackedBlocks); } public boolean hasStackedBlocks() { return this.stackedBlocksContainer.size() > 0; } @Override public void updateStackedBlockHologram(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); if (!(location instanceof LazyWorldLocation)) Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); StackedBlock stackedBlock = this.stackedBlocksContainer.getStackedBlock(location); if (stackedBlock != null) { stackedBlock.updateName(); if (stackedBlock.getAmount() <= 1) removeStackedBlock(location); } } @Override public void updateStackedBlockHolograms(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> { stackedBlock.updateName(); if (stackedBlock.getAmount() <= 1) removeStackedBlock(stackedBlock.getLocation()); }); } } @Override public void removeStackedBlockHologram(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); if (!(location instanceof LazyWorldLocation)) Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); StackedBlock stackedBlock = this.stackedBlocksContainer.getStackedBlock(location); if (stackedBlock != null) { stackedBlock.removeHologram(); } } @Override public void removeStackedBlockHolograms(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { this.stackedBlocksContainer.forEach(chunkPosition, StackedBlock::removeHologram); } } @Override public DatabaseBridge getDatabaseBridge() { return databaseBridge; } public void forEach(ChunkPosition chunkPosition, Consumer consumer) { this.stackedBlocksContainer.forEach(chunkPosition, consumer); } private void loadStackedBlock(DatabaseResult resultSet) { Optional location = resultSet.getString("location").map(Serializers.LOCATION_SPACED_SERIALIZER::deserialize); if (!location.isPresent()) { Log.warn("Cannot load stacked block from null location, skipping..."); return; } if (!(plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider)) { if (location.get().getWorld() == null) { Log.warn("Cannot load stacked block with invalid world ", LazyWorldLocation.getWorldName(location.get()), ", skipping..."); return; } } Optional amount = resultSet.getInt("amount"); if (!amount.isPresent()) { Log.warn("Cannot load stacked block from null amount, skipping..."); return; } Optional item = resultSet.getString("block_type"); Key blockKey; if (!item.isPresent() || item.get().isEmpty()) { blockKey = null; } else { String itemValue = item.get(); Location blockLocation = location.get(); blockKey = Keys.of(Key.class, new LazyReference() { private final Key baseKey = Keys.ofMaterialAndData(itemValue); private final Location keyLocation = blockLocation; @Override protected Key create() { return Keys.of(this.baseKey, this.keyLocation); } }); } try { StackedBlock stackedBlock = this.stackedBlocksContainer.createStackedBlock(location.get()); stackedBlock.setAmount(amount.get()); stackedBlock.setBlockKey(blockKey); } catch (IllegalArgumentException error) { Log.error(error); } } private void updateStackedBlockKeys() { this.stackedBlocksContainer.forEach(stackedBlock -> stackedBlock.setBlockKey(Keys.of(stackedBlock.getLocation().getBlock()))); } private void initializeDatabaseBridge() { databaseBridge = plugin.getFactory().createDatabaseBridge(this); databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/container/DefaultStackedBlocksContainer.java ================================================ package com.bgsoftware.superiorskyblock.core.stackedblocks.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Location2ObjectMap; import com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlock; import org.bukkit.Location; import java.util.function.Consumer; public class DefaultStackedBlocksContainer implements StackedBlocksContainer { private final Location2ObjectMap stackedBlocks = new Location2ObjectMap<>(); @Nullable @Override public StackedBlock getStackedBlock(Location location) { return this.stackedBlocks.get(location); } @Override public StackedBlock createStackedBlock(Location location) { StackedBlock stackedBlock = new StackedBlock(location); StackedBlock oldStackedBlock = this.stackedBlocks.put(location, stackedBlock); if (oldStackedBlock != null) oldStackedBlock.markAsRemoved(); return stackedBlock; } @Override public StackedBlock removeStackedBlock(Location location) { StackedBlock removedStackedBlock = this.stackedBlocks.remove(location); if (removedStackedBlock != null) removedStackedBlock.markAsRemoved(); return removedStackedBlock; } @Override public void forEach(ChunkPosition chunkPosition, Consumer consumer) { this.stackedBlocks.forEach(chunkPosition, consumer); } @Override public void forEach(Consumer consumer) { this.stackedBlocks.values().forEach(consumer); } @Override public void removeStackedBlocks(ChunkPosition chunkPosition, Consumer consumer) { this.stackedBlocks.removeAll(chunkPosition, stackedBlock -> { stackedBlock.markAsRemoved(); consumer.accept(stackedBlock); }); } @Override public int size() { return this.stackedBlocks.size(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/container/StackedBlocksContainer.java ================================================ package com.bgsoftware.superiorskyblock.core.stackedblocks.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlock; import org.bukkit.Location; import java.util.function.Consumer; public interface StackedBlocksContainer { @Nullable StackedBlock getStackedBlock(Location location); StackedBlock createStackedBlock(Location location); StackedBlock removeStackedBlock(Location location); void forEach(ChunkPosition chunkPosition, Consumer consumer); void forEach(Consumer consumer); void removeStackedBlocks(ChunkPosition chunkPosition, Consumer consumer); int size(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stats/IStatsCollector.java ================================================ package com.bgsoftware.superiorskyblock.core.stats; import com.google.gson.JsonObject; public interface IStatsCollector { void collect(JsonObject statsObject); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsClient.java ================================================ package com.bgsoftware.superiorskyblock.core.stats; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.gson.Gson; import com.google.gson.JsonObject; import org.bukkit.Bukkit; import javax.net.ssl.HttpsURLConnection; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; public class StatsClient { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Gson GSON = new Gson(); private static final int VERSION = 1; private static final long TASK_DELAY = 1; private static final byte MINIMUM_ONLINE_PLAYERS = 10; private static final List STATS_COLLECTORS = new LinkedList<>(); private static final String API_ENDPOINT = "https://api.bg-software.com/v1/stats/"; private static StatsClient INSTANCE; static { STATS_COLLECTORS.add(StatsIslandsCounter.INSTANCE); STATS_COLLECTORS.add(StatsPlayersCounter.INSTANCE); STATS_COLLECTORS.add(StatsProfilers.INSTANCE); STATS_COLLECTORS.add(StatsSchematicsSizes.INSTANCE); } private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder() .setNameFormat("SuperiorSkyblock Stats").build()); private ScheduledFuture scheduledTask; private StatsClient() { } public void start() { this.scheduledTask = scheduler.scheduleAtFixedRate(this::collectStatsTask, 1, TASK_DELAY, TimeUnit.MINUTES); } public void shutdown() { if (this.scheduledTask != null) { this.scheduledTask.cancel(true); this.scheduledTask = null; } if (!this.scheduler.isShutdown()) this.scheduler.shutdownNow(); } private void collectStatsTask() { UUID serverUUID = plugin.getGrid().getServerUUID(); if (serverUUID == null) { shutdown(); return; } if (Bukkit.getOnlinePlayers().size() < MINIMUM_ONLINE_PLAYERS) return; try { JsonObject statsObject = new JsonObject(); STATS_COLLECTORS.forEach(collector -> collector.collect(statsObject)); submitStats(statsObject, serverUUID); } catch (Exception error) { Log.error(error, "An error occurred while uploading stats:"); } } private void submitStats(JsonObject statsObject, UUID serverUUID) throws IOException { if (statsObject.entrySet().isEmpty()) return; statsObject.addProperty("version", VERSION); statsObject.addProperty("server", serverUUID.toString()); HttpsURLConnection conn = (HttpsURLConnection) new URL(API_ENDPOINT).openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/json"); conn.setDoOutput(true); try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()))) { writer.write(GSON.toJson(statsObject)); } int statusCode = conn.getResponseCode(); if (statusCode != 200) throw new RuntimeException("Received error code when submitting stats: " + statusCode); JsonObject response; try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { response = GSON.fromJson(reader.readLine(), JsonObject.class); } if (response.has("error")) throw new RuntimeException("Received error when submitting stats: " + response.get("error").getAsString()); if (!response.has("status")) throw new RuntimeException("Received invalid response when submitting stats: " + response); String status = response.get("status").getAsString(); if (!status.equalsIgnoreCase("success")) throw new RuntimeException("Received invalid status when submitting stats: " + status); } public static StatsClient getInstance() { if (INSTANCE == null) INSTANCE = new StatsClient(); return INSTANCE; } public static Optional getIfExists() { return Optional.ofNullable(INSTANCE); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsIslandsCounter.java ================================================ package com.bgsoftware.superiorskyblock.core.stats; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.google.gson.JsonObject; public class StatsIslandsCounter implements IStatsCollector { public static final StatsIslandsCounter INSTANCE = new StatsIslandsCounter(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private int lastIslandsCount = 0; private StatsIslandsCounter() { } @Override public void collect(JsonObject statsObject) { int currentIslandsCount = plugin.getGrid().getIslands().size(); if (currentIslandsCount != this.lastIslandsCount) { statsObject.addProperty("islands_count", currentIslandsCount); this.lastIslandsCount = currentIslandsCount; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsPlayersCounter.java ================================================ package com.bgsoftware.superiorskyblock.core.stats; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.google.gson.JsonObject; import org.bukkit.Bukkit; public class StatsPlayersCounter implements IStatsCollector { public static final StatsPlayersCounter INSTANCE = new StatsPlayersCounter(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private int lastAllPlayers; private StatsPlayersCounter() { } @Override public void collect(JsonObject statsObject) { statsObject.addProperty("online_players", Bukkit.getOnlinePlayers().size()); int currentAllPlayers = plugin.getPlayers().getAllPlayers().size(); if (currentAllPlayers != this.lastAllPlayers) { statsObject.addProperty("all_players", currentAllPlayers); this.lastAllPlayers = currentAllPlayers; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsProfilers.java ================================================ package com.bgsoftware.superiorskyblock.core.stats; import com.bgsoftware.superiorskyblock.core.profiler.ProfilerSession; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; public class StatsProfilers implements IStatsCollector { public static final StatsProfilers INSTANCE = new StatsProfilers(); private final List collectedProfilers = new LinkedList<>(); private StatsProfilers() { } public void submitProfiler(ProfilerSession session) { synchronized (this) { collectedProfilers.add(session); } } @Override public void collect(JsonObject statsObject) { List collectedProfilers; synchronized (this) { if (this.collectedProfilers.isEmpty()) return; collectedProfilers = new LinkedList<>(this.collectedProfilers); this.collectedProfilers.clear(); } JsonArray profilers = new JsonArray(); collectedProfilers.forEach(session -> { JsonObject profiler = new JsonObject(); profiler.addProperty("type", session.getProfileType().name()); profiler.addProperty("time_elapsed", TimeUnit.NANOSECONDS.toMillis(session.getEndData().time - session.getStartData().time)); profiler.addProperty("start_tps", session.getStartData().tps); profiler.addProperty("end_tps", session.getEndData().tps); Object extra = session.getExtra(); if (extra != null) profiler.addProperty("extra", String.valueOf(extra)); profilers.add(profiler); }); statsObject.add("profilers", profilers); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/stats/StatsSchematicsSizes.java ================================================ package com.bgsoftware.superiorskyblock.core.stats; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.core.mutable.MutableLong; import com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic; import com.google.gson.JsonObject; import java.util.List; public class StatsSchematicsSizes implements IStatsCollector { public static final StatsSchematicsSizes INSTANCE = new StatsSchematicsSizes(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private boolean collected = false; private StatsSchematicsSizes() { } @Override public void collect(JsonObject statsObject) { if (collected) return; collected = true; List schematicNames = plugin.getSchematics().getSchematics(); if (schematicNames.isEmpty()) return; JsonObject schematics = new JsonObject(); schematicNames.forEach(schematicName -> { Schematic schematic = plugin.getSchematics().getSchematic(schematicName); if (schematic instanceof SuperiorSchematic) { MutableLong blocksCount = new MutableLong(0); schematic.getBlockCounts().values().forEach(count -> blocksCount.set(blocksCount.get() + count)); if (blocksCount.get() > 0) schematics.addProperty(schematicName, blocksCount.get()); } }); statsObject.add("schematics", schematics); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/task/CalcTask.java ================================================ package com.bgsoftware.superiorskyblock.core.task; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; public class CalcTask extends BukkitRunnable { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static BukkitTask calcTask; private CalcTask() { calcTask = runTaskTimerAsynchronously(plugin, plugin.getSettings().getCalcInterval(), plugin.getSettings().getCalcInterval()); } public static void startTask() { cancelTask(); if (plugin.getSettings().getCalcInterval() > 0) new CalcTask(); } public static void cancelTask() { if (calcTask != null) { calcTask.cancel(); calcTask = null; } } @Override public void run() { if (Bukkit.getOnlinePlayers().size() > 0) { announceToPlayers(false); announceToOps("&7&o[SuperiorSkyblock] Calculating islands..."); plugin.getGrid().calcAllIslands(() -> { announceToPlayers(true); announceToOps("&7&o[SuperiorSkyblock] Calculating islands done!"); }); } } private void announceToOps(String message) { for (Player player : Bukkit.getOnlinePlayers()) { if (player.isOp()) Message.CUSTOM.send(player, message, true); } Message.CUSTOM.send(Bukkit.getConsoleSender(), message, true); } private void announceToPlayers(boolean done) { for (Player player : Bukkit.getOnlinePlayers()) { if (done) { Message.RECALC_ALL_ISLANDS_DONE.send(player); } else { Message.RECALC_ALL_ISLANDS.send(player); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/task/ShutdownTask.java ================================================ package com.bgsoftware.superiorskyblock.core.task; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.logging.Log; public class ShutdownTask extends Thread { private final SuperiorSkyblockPlugin plugin; public ShutdownTask(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public void run() { if (!plugin.getGrid().wasPluginDisabled()) { Log.error("Detected crash. SuperiorSkyblock will attempt to save data..."); plugin.onDisable(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java ================================================ package com.bgsoftware.superiorskyblock.core.threads; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Bukkit; import org.bukkit.scheduler.BukkitTask; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Function; public class BukkitExecutor { private static final int DEFAULT_SHUTDOWN_TIMEOUT = 1000 * 20; private static final int SHUTDOWN_INTERVAL_WAIT_TIME = 100; private static SuperiorSkyblockPlugin plugin; private static State state = State.RUNNING; private static final AtomicLong ACTIVE_TASKS_COUNT = new AtomicLong(0); private BukkitExecutor() { } public static void init(SuperiorSkyblockPlugin plugin) { BukkitExecutor.plugin = plugin; } @Nullable public static BukkitTask ensureMain(Runnable runnable) { if (ensureNotShudown()) return null; if (state != State.PREPARE_SHUTDOWN && !Bukkit.isPrimaryThread()) { return sync(runnable); } else { runnable.run(); return null; } } @Nullable public static BukkitTask ensureAsync(Runnable runnable) { if (ensureNotShudown()) return null; if (state != State.PREPARE_SHUTDOWN && Bukkit.isPrimaryThread()) { return async(runnable); } else { runnable.run(); return null; } } public static BukkitTask sync(Runnable runnable) { return sync(runnable, 0); } public static BukkitTask sync(Runnable runnable, long delay) { if (ensureNotShudown()) return null; if (state == State.PREPARE_SHUTDOWN) { runnable.run(); return null; } else { return Bukkit.getScheduler().runTaskLater(plugin, runnable, delay); } } public static BukkitTask async(Runnable runnable) { if (ensureNotShudown()) return null; if (state == State.PREPARE_SHUTDOWN) { runnable.run(); return null; } else { return Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable); } } public static BukkitTask async(Runnable runnable, long delay) { if (ensureNotShudown()) return null; if (state == State.PREPARE_SHUTDOWN) { runnable.run(); return null; } else { return Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay); } } public static void asyncTimer(Runnable runnable, long delay) { if (ensureNotShudown()) return; Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, delay); } public static void timer(Runnable runnable, long delay) { if (ensureNotShudown()) return; Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, delay); } public static NestedTask createTask() { return new NestedTask().complete(); } public static void prepareShutdown() { state = State.PREPARE_SHUTDOWN; } public static void close(SuperiorSkyblockPlugin plugin) { // Waiting for all active tasks to finish Log.info("This can take up to " + (DEFAULT_SHUTDOWN_TIMEOUT / 1000) + " seconds to complete"); long timeoutLeft = DEFAULT_SHUTDOWN_TIMEOUT; while (ACTIVE_TASKS_COUNT.get() != 0 && timeoutLeft > 0) { try { Thread.sleep(SHUTDOWN_INTERVAL_WAIT_TIME); timeoutLeft -= SHUTDOWN_INTERVAL_WAIT_TIME; } catch (Throwable ignored) { } } if (ACTIVE_TASKS_COUNT.get() != 0) { new RuntimeException("Not all active tasks finished").printStackTrace(); } state = State.SHUTDOWN; Bukkit.getScheduler().cancelTasks(plugin); } private static boolean ensureNotShudown() { if (state == State.SHUTDOWN) { new RuntimeException("Tried to call BukkitExecutor after it was shut down").printStackTrace(); return true; } return false; } public static class NestedTask { private final CompletableFuture value = new CompletableFuture<>(); NestedTask() { } public NestedTask runSync(Function function) { ensureNotShudown(); NestedTask nestedTask = new NestedTask<>(); if (state == State.PREPARE_SHUTDOWN) { nestedTask.value.complete(function.apply(value.join())); } else { onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> { try { nestedTask.value.complete(function.apply(value)); } finally { onComplete(); } })); } return nestedTask; } public NestedTask runSync(Consumer consumer) { ensureNotShudown(); NestedTask nestedTask = new NestedTask<>(); if (state == State.PREPARE_SHUTDOWN) { consumer.accept(value.join()); nestedTask.value.complete(null); } else { onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> { try { consumer.accept(value); nestedTask.value.complete(null); } finally { onComplete(); } })); } return nestedTask; } public NestedTask runAsync(Function function) { ensureNotShudown(); NestedTask nestedTask = new NestedTask<>(); if (state == State.PREPARE_SHUTDOWN) { nestedTask.value.complete(function.apply(value.join())); } else { onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.async(() -> { try { nestedTask.value.complete(function.apply(value)); } finally { onComplete(); } })); } return nestedTask; } public NestedTask runAsync(Consumer consumer) { ensureNotShudown(); NestedTask nestedTask = new NestedTask<>(); if (state == State.PREPARE_SHUTDOWN) { consumer.accept(value.join()); nestedTask.value.complete(null); } else { onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.async(() -> { try { consumer.accept(value); nestedTask.value.complete(null); } finally { onComplete(); } })); } return nestedTask; } private NestedTask complete() { value.complete(null); return this; } private static void onCreate() { long curr = ACTIVE_TASKS_COUNT.incrementAndGet(); Log.debug(Debug.TRACK_TASK, curr); } private static void onComplete() { long curr = ACTIVE_TASKS_COUNT.decrementAndGet(); Log.debug(Debug.TRACK_TASK, curr); if (curr < 0) { new RuntimeException("Active tasks count is less than 0").printStackTrace(); ACTIVE_TASKS_COUNT.set(0); } } } private enum State { RUNNING, PREPARE_SHUTDOWN, SHUTDOWN } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/threads/Synchronized.java ================================================ package com.bgsoftware.superiorskyblock.core.threads; import java.util.Collection; import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; import java.util.function.Function; public class Synchronized { private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private T value; Synchronized(T value) { this.value = value; } public static Synchronized of(T value) { return new Synchronized<>(value); } public T get() { if (value instanceof Map) throw new UnsupportedOperationException("Cannot get raw maps from synced objects."); if (value instanceof Collection) throw new UnsupportedOperationException("Cannot get raw collections from synced objects."); try { lock.readLock().lock(); return value; } finally { lock.readLock().unlock(); } } public T set(T value) { try { lock.writeLock().lock(); T oldValue = this.value; this.value = value; return oldValue; } finally { lock.writeLock().unlock(); } } public void set(Function function) { try { lock.writeLock().lock(); this.value = function.apply(value); } finally { lock.writeLock().unlock(); } } public void read(Consumer consumer) { try { lock.readLock().lock(); consumer.accept(value); } finally { lock.readLock().unlock(); } } public R readAndGet(Function function) { try { lock.readLock().lock(); return function.apply(value); } finally { lock.readLock().unlock(); } } public void write(Consumer consumer) { try { lock.writeLock().lock(); consumer.accept(value); } finally { lock.writeLock().unlock(); } } public R writeAndGet(Function function) { try { lock.writeLock().lock(); return function.apply(value); } finally { lock.writeLock().unlock(); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java ================================================ package com.bgsoftware.superiorskyblock.core.threads; import javax.annotation.Nullable; import java.util.concurrent.CountDownLatch; public class SynchronizedTasks { @Nullable private final CountDownLatch countDownLatch; @Nullable private final Runnable onFinishCallback; public SynchronizedTasks(int count, @Nullable Runnable onFinishCallback) { this.countDownLatch = count <= 0 ? null : new CountDownLatch(count); this.onFinishCallback = onFinishCallback; } public void notifyTaskComplete() { if (this.countDownLatch != null) this.countDownLatch.countDown(); } public void waitAllAsync() { BukkitExecutor.ensureAsync(this::waitAllAsyncInternal); } private void waitAllAsyncInternal() { if (this.countDownLatch != null) { try { this.countDownLatch.await(); } catch (InterruptedException error) { throw new RuntimeException(error); } } if (this.onFinishCallback != null) this.onFinishCallback.run(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/DoubleValue.java ================================================ package com.bgsoftware.superiorskyblock.core.value; import com.bgsoftware.common.annotations.Nullable; import java.util.function.DoubleSupplier; public interface DoubleValue { static DoubleValue fixed(double value) { return DoubleValueFixed.of(value); } static DoubleValue syncedFixed(double value) { return DoubleValueFixedSynced.of(value); } static DoubleValue syncedSupplied(DoubleSupplier supplier) { return DoubleValueSuppliedSynced.of(supplier); } static double getNonSynced(@Nullable DoubleValue value, double syncedValue) { return value == null ? syncedValue : value.getNonSynced(syncedValue); } double get(); boolean isSynced(); default double getNonSynced(double syncedValue) { return isSynced() ? syncedValue : get(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/DoubleValueFixed.java ================================================ package com.bgsoftware.superiorskyblock.core.value; public class DoubleValueFixed implements DoubleValue { private static final ValuesCache CACHE = new ValuesCache<>(DoubleValueFixed::new); private final double value; public static DoubleValueFixed of(double value) { return value == (int) value ? CACHE.fetch((int) value) : new DoubleValueFixed(value); } private DoubleValueFixed(double value) { this.value = value; } @Override public double get() { return this.value; } @Override public boolean isSynced() { return false; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/DoubleValueFixedSynced.java ================================================ package com.bgsoftware.superiorskyblock.core.value; public class DoubleValueFixedSynced implements DoubleValue { private static final ValuesCache CACHE = new ValuesCache<>(DoubleValueFixedSynced::new); private final double value; public static DoubleValueFixedSynced of(double value) { return value == (int) value ? CACHE.fetch((int) value) : new DoubleValueFixedSynced(value); } private DoubleValueFixedSynced(double value) { this.value = value; } @Override public double get() { return value; } @Override public boolean isSynced() { return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/DoubleValueSuppliedSynced.java ================================================ package com.bgsoftware.superiorskyblock.core.value; import java.util.function.DoubleSupplier; public class DoubleValueSuppliedSynced implements DoubleValue { private final DoubleSupplier supplier; public static DoubleValueSuppliedSynced of(DoubleSupplier supplier) { return new DoubleValueSuppliedSynced(supplier); } private DoubleValueSuppliedSynced(DoubleSupplier supplier) { this.supplier = supplier; } @Override public double get() { return supplier.getAsDouble(); } @Override public boolean isSynced() { return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/IntValue.java ================================================ package com.bgsoftware.superiorskyblock.core.value; import com.bgsoftware.common.annotations.Nullable; import java.util.Map; import java.util.function.IntSupplier; import java.util.stream.Collectors; public interface IntValue { static IntValue fixed(int value) { return IntValueFixed.of(value); } static IntValue syncedFixed(int value) { return IntValueFixedSynced.of(value); } static IntValue syncedSupplied(IntSupplier supplier) { return IntValueSuppliedSynced.of(supplier); } static Map unboxMap(Map input) { return input.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> entry.getValue().get() )); } static int getNonSynced(@Nullable IntValue value, int syncedValue) { return value == null ? syncedValue : value.getNonSynced(syncedValue); } int get(); boolean isSynced(); default int getNonSynced(int syncedValue) { return isSynced() ? syncedValue : get(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/IntValueFixed.java ================================================ package com.bgsoftware.superiorskyblock.core.value; public class IntValueFixed implements IntValue { private static final ValuesCache CACHE = new ValuesCache<>(IntValueFixed::new); private final int value; public static IntValueFixed of(int value) { return CACHE.fetch(value); } private IntValueFixed(int value) { this.value = value; } public int get() { return this.value; } @Override public boolean isSynced() { return false; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/IntValueFixedSynced.java ================================================ package com.bgsoftware.superiorskyblock.core.value; public class IntValueFixedSynced implements IntValue { private static final ValuesCache CACHE = new ValuesCache<>(IntValueFixedSynced::new); private final int value; public static IntValueFixedSynced of(int value) { return CACHE.fetch(value); } private IntValueFixedSynced(int value) { this.value = value; } @Override public int get() { return value; } @Override public boolean isSynced() { return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/IntValueSuppliedSynced.java ================================================ package com.bgsoftware.superiorskyblock.core.value; import java.util.function.IntSupplier; public class IntValueSuppliedSynced implements IntValue { private final IntSupplier supplier; public static IntValueSuppliedSynced of(IntSupplier supplier) { return new IntValueSuppliedSynced(supplier); } private IntValueSuppliedSynced(IntSupplier supplier) { this.supplier = supplier; } @Override public int get() { return supplier.getAsInt(); } @Override public boolean isSynced() { return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/Value.java ================================================ package com.bgsoftware.superiorskyblock.core.value; import com.bgsoftware.common.annotations.Nullable; import java.util.function.Supplier; public interface Value { static Value fixed(V value) { return new ValueFixed<>(value); } static Value syncedSupplied(Supplier supplier) { return new ValueSuppliedSynced<>(supplier); } static Value syncedFixed(V value) { return new ValueFixedSynced<>(value); } static V getNonSynced(@Nullable Value value, V syncedValue) { return value == null ? syncedValue : value.getNonSynced(syncedValue); } V get(); boolean isSynced(); default V getNonSynced(V syncedValue) { return isSynced() ? syncedValue : get(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixed.java ================================================ package com.bgsoftware.superiorskyblock.core.value; public class ValueFixed implements Value { private final V value; ValueFixed(V value) { this.value = value; } @Override public V get() { return value; } @Override public boolean isSynced() { return false; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixedSynced.java ================================================ package com.bgsoftware.superiorskyblock.core.value; public class ValueFixedSynced implements Value { private final V value; ValueFixedSynced(V value) { this.value = value; } @Override public V get() { return value; } @Override public boolean isSynced() { return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueSuppliedSynced.java ================================================ package com.bgsoftware.superiorskyblock.core.value; import java.util.function.Supplier; public class ValueSuppliedSynced implements Value { private final Supplier supplier; ValueSuppliedSynced(Supplier supplier) { this.supplier = supplier; } @Override public V get() { return supplier.get(); } @Override public boolean isSynced() { return true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/value/ValuesCache.java ================================================ package com.bgsoftware.superiorskyblock.core.value; import java.util.Objects; import java.util.function.IntFunction; public class ValuesCache { private static final int CACHE_SIZE = 32; private final int[] indexes = new int[CACHE_SIZE]; private final Object[] cache = new Object[CACHE_SIZE]; private int capacity = 0; private final IntFunction creator; public ValuesCache(IntFunction creator) { this.creator = creator; } public T fetch(int value) { for (int i = 0; i < this.capacity; ++i) { if (this.indexes[i] == value) { return Objects.requireNonNull((T) this.cache[i]); } } T cachedValue = this.creator.apply(value); if (cachedValue != null && this.capacity < CACHE_SIZE) { this.indexes[this.capacity] = value; this.cache[this.capacity] = cachedValue; ++this.capacity; } return cachedValue; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValue.java ================================================ package com.bgsoftware.superiorskyblock.core.values; import javax.annotation.Nullable; import java.math.BigDecimal; public class BlockValue { public static final BlockValue ZERO = new BlockValue(null, null); @Nullable private final BigDecimal worth; @Nullable private final BigDecimal level; private static boolean isZero(@Nullable BigDecimal value) { return value == null || value.compareTo(BigDecimal.ZERO) == 0; } public static BlockValue ofWorth(@Nullable BigDecimal worth) { return ofWorthAndLevel(worth, null); } public static BlockValue ofLevel(@Nullable BigDecimal level) { return ofWorthAndLevel(null, level); } public static BlockValue ofWorthAndLevel(@Nullable BigDecimal worth, @Nullable BigDecimal level) { return isZero(worth) && isZero(level) ? ZERO : new BlockValue(worth, level); } private BlockValue(@Nullable BigDecimal worth, @Nullable BigDecimal level) { this.worth = worth; this.level = level; } public BigDecimal getWorth() { return this.worth == null ? BigDecimal.ZERO : this.worth; } public boolean hasWorth() { return this.worth != null; } public BlockValue setWorth(@Nullable BigDecimal worth) { return ofWorthAndLevel(worth, this.level); } public BigDecimal getLevel() { return this.level == null ? BigDecimal.ZERO : this.level; } public boolean hasLevel() { return this.level != null; } public BlockValue setLevel(@Nullable BigDecimal level) { return ofWorthAndLevel(this.worth, level); } @Override public String toString() { return "BlockValue{" + "worth=" + worth + ", level=" + level + '}'; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.core.values; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.values.container.BlockValuesContainer; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.inventory.ItemStack; import javax.script.Bindings; import javax.script.ScriptException; import javax.script.SimpleBindings; import java.io.File; import java.math.BigDecimal; import java.util.Collection; import java.util.Map; import java.util.function.BiConsumer; public class BlockValuesManagerImpl extends Manager implements BlockValuesManager { private static final Map CACHED_BIG_DECIMALS; static { ImmutableMap.Builder mapBuilder = new ImmutableMap.Builder<>(); mapBuilder.put("", BigDecimal.ZERO); for (int i = 0; i < 10; ++i) { mapBuilder.put(i + "", BigDecimal.valueOf(i)); } for (int i = 10; i < 100; i *= 10) { mapBuilder.put(i + "", BigDecimal.valueOf(i)); } for (int i = 100; i <= 1000; i *= 100) { mapBuilder.put(i + "", BigDecimal.valueOf(i)); } CACHED_BIG_DECIMALS = mapBuilder.build(); } private static final Bindings bindings = createBindings(); private static final KeyMap customKeyParsers = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); private static final KeySet valuesMenuBlocks = KeySets.createHashSet(KeyIndicator.MATERIAL); private static final KeySet customBlockKeys = KeySets.createHashSet(KeyIndicator.MATERIAL); private final BlockValuesContainer blockValuesContainer; private final BlockValuesContainer customValuesContainer; public BlockValuesManagerImpl(SuperiorSkyblockPlugin plugin, BlockValuesContainer blockValuesContainer, BlockValuesContainer customValuesContainer) { super(plugin); this.blockValuesContainer = blockValuesContainer; this.customValuesContainer = customValuesContainer; } private static Bindings createBindings() { SimpleBindings bindings = new SimpleBindings(); bindings.put("Math", Math.class); return bindings; } @Override public void loadData() { this.blockValuesContainer.clear(); this.customValuesContainer.clear(); loadDefaultValues(); plugin.getProviders().addPricesLoadCallback(this::convertWorthValuesToLevels); } @Override public BigDecimal getBlockWorth(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return getBlockValue(key, true).getWorth(); } @Override public BigDecimal getBlockLevel(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return getBlockValue(key, false).getLevel(); } public BlockValue getBlockValue(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return getBlockValue(key, true); } private BlockValue getBlockValue(Key key, boolean checkPrices) { Log.debug(Debug.GET_VALUE, key); BlockValue customBlockValue = customValuesContainer.getBlockValue(key); if (customBlockValue != null) { Log.debugResult(Debug.GET_VALUE, "Return Custom Block Value", customBlockValue); return customBlockValue; } if (checkPrices) { if (blockValuesContainer.containsKeyRaw(key)) { BlockValue value = blockValuesContainer.getBlockValue(key); if (value != null) { Log.debugResult(Debug.GET_VALUE, "Return File", value); return value; } } if (plugin.getSettings().getSyncWorth() != SyncWorthStatus.NONE) { BigDecimal price = plugin.getProviders().getPricesProvider().getPrice(key); if (price.compareTo(BigDecimal.ZERO) >= 0) { BlockValue blockValue = BlockValue.ofWorth(price); Log.debugResult(Debug.GET_VALUE, "Return Price", blockValue); return blockValue; } } } BlockValue value = blockValuesContainer.getBlockValue(key); if (value != null) { Log.debugResult(Debug.GET_VALUE, "Return File", value); return value; } Log.debugResult(Debug.GET_VALUE, "Return File", 0); return BlockValue.ZERO; } @Override public Key getBlockKey(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); if (isValuesMenu(key)) { return markAsAPIIfNeeded(key, getValuesKey(key)); } if (blockValuesContainer.containsKeyRaw(key)) { return key; } if (plugin.getSettings().getSyncWorth() != SyncWorthStatus.NONE) { Key newKey = plugin.getProviders().getPricesProvider().getBlockKey(key); if (newKey != null) { return markAsAPIIfNeeded(key, newKey); } } Key blockValuesKey = blockValuesContainer.getBlockValueKey(key); if (blockValuesKey != key) return markAsAPIIfNeeded(key, blockValuesKey); return markAsAPIIfNeeded(key, customBlockKeys.getKey(key, key)); } private Key markAsAPIIfNeeded(Key original, Key newKey) { if (original != newKey && ((BaseKey) original).isAPIKey()) newKey = ((BaseKey) newKey).markAPIKey(); return newKey; } @Override public void registerCustomKey(Key key, @Nullable BigDecimal worthValue, @Nullable BigDecimal levelValue) { Preconditions.checkNotNull(key, "key parameter cannot be null."); if (!customValuesContainer.containsKey(key)) { customValuesContainer.setBlockValue(key, BlockValue.ofWorthAndLevel(worthValue, levelValue)); } } @Override public void registerKeyParser(CustomKeyParser customKeyParser, Key... blockTypes) { Preconditions.checkNotNull(customKeyParser, "customKeyParser parameter cannot be null."); Preconditions.checkNotNull(blockTypes, "blockTypes parameter cannot be null."); for (Key blockType : blockTypes) customKeyParsers.put(blockType, customKeyParser); } public void registerMenuValueBlocks(KeySet blocks) { valuesMenuBlocks.addAll(blocks); } public boolean isValuesMenu(Key key) { return valuesMenuBlocks.contains(key); } public Key getValuesKey(Key key) { return valuesMenuBlocks.getKey(key, key); } public void addCustomBlockKey(Key key) { customBlockKeys.add(key); } public void addCustomBlockKeys(Collection blocks) { customBlockKeys.addAll(blocks); } public Key convertKey(Key original, Location location) { CustomKeyParser customKeyParser = customKeyParsers.get(original); if (customKeyParser == null) return original; Key key = customKeyParser.getCustomKey(location); return key == null ? original : key; } public Key convertKey(Key original, ItemStack itemStack) { CustomKeyParser customKeyParser = customKeyParsers.get(original); if (customKeyParser == null) return original; return customKeyParser.getCustomKey(itemStack, original); } public Key convertKey(Key original, Entity entity) { CustomKeyParser customKeyParser = customKeyParsers.get(original); if (customKeyParser == null) return original; Key key = customKeyParser.getCustomKey(entity); return key == null ? original : key; } @Nullable public Pair convertCustomKeyItem(Key original) { for (Map.Entry entry : customKeyParsers.entrySet()) { if (entry.getValue().isCustomKey(original)) { return new Pair<>(entry.getKey(), entry.getValue().getCustomKeyItem(original)); } } return new Pair<>(original, null); } private BigDecimal convertWorthToLevel(BigDecimal value) { // If the formula contains no mathematical operations or the placeholder for the worth value, // we can directly create the BigDecimal instance from it. try { return fastBigDecimalFromString(plugin.getSettings().getIslandLevelFormula()); } catch (NumberFormatException ignored) { } try { Object evaluated = plugin.getScriptEngine().eval(plugin.getSettings().getIslandLevelFormula() .replace("{}", value.toString()), bindings); // Checking for division by 0 if (evaluated.equals(Double.POSITIVE_INFINITY) || evaluated.equals(Double.NEGATIVE_INFINITY)) return BigDecimal.ZERO; return fastBigDecimalFromString(evaluated.toString()); } catch (ScriptException error) { Log.entering("ENTER", value); Log.error(error, "An unexpected error occurred while converting level from worth:"); return value; } } private void convertWorthValuesToLevels() { blockValuesContainer.forEach((blockKey, blockCount) -> { BlockValue realBlockValue = blockValuesContainer.getBlockValue(blockKey); if (realBlockValue != null && !realBlockValue.hasLevel()) { BlockValue newBlockValue = realBlockValue.setLevel(convertWorthToLevel(realBlockValue.getWorth())); blockValuesContainer.setBlockValue(blockKey, newBlockValue); } }); } private void loadDefaultValues() { // First, convert old file File blockValuesFile = new File(plugin.getDataFolder(), "blockvalues.yml"); if (blockValuesFile.exists()) { File worthFile = new File("block-values/worth.yml"); if (!worthFile.getParentFile().mkdirs() || !blockValuesFile.renameTo(worthFile)) Log.error("Failed to convert old block values to the new format."); } // Load level and worth values loadValuesFromFile("block-values/worth.yml", (key, worth) -> { blockValuesContainer.setBlockValue(key, BlockValue.ofWorth(worth)); }); loadValuesFromFile("block-values/levels.yml", (key, level) -> { BlockValue currValue = blockValuesContainer.getBlockValue(key); BlockValue newValue = currValue == null ? BlockValue.ofLevel(level) : currValue.setLevel(level); blockValuesContainer.setBlockValue(key, newValue); }); } private void loadValuesFromFile(String fileName, BiConsumer consumer) { File file = new File(plugin.getDataFolder(), fileName); if (!file.exists()) plugin.saveResource(fileName, true); YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); ConfigurationSection valuesSection = cfg.isConfigurationSection("block-values") ? cfg.getConfigurationSection("block-values") : cfg.getConfigurationSection(""); for (String key : valuesSection.getKeys(false)) { String value = valuesSection.getString(key); try { consumer.accept(Keys.ofMaterialAndData(key), new BigDecimal(value)); } catch (Exception ex) { Log.warnFromFile("levels.yml", "Cannot parse value for ", key, " in file ", fileName, ", skipping..."); } } } private static BigDecimal fastBigDecimalFromString(String value) { return CACHED_BIG_DECIMALS.getOrDefault(value, new BigDecimal(value)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java ================================================ package com.bgsoftware.superiorskyblock.core.values.container; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import javax.annotation.Nullable; import java.util.function.BiConsumer; public class BlockValuesContainer { private final KeyMap valuesMap = KeyMaps.createHashMap(KeyIndicator.MATERIAL); public void setBlockValue(Key key, BlockValue value) { valuesMap.put(key, value); } @Nullable public BlockValue getBlockValue(Key key) { return valuesMap.get(key); } public boolean containsKeyRaw(Key key) { return valuesMap.getKey(key) == key; } public boolean containsKey(Key key) { return valuesMap.containsKey(key); } public Key getBlockValueKey(Key key) { return valuesMap.getKey(key, key); } public void forEach(BiConsumer consumer) { valuesMap.forEach(consumer); } public void clear() { valuesMap.clear(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.common.shopsbridge.ShopsProvider; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.ProvidersManager; import com.bgsoftware.superiorskyblock.api.hooks.AFKProvider; import com.bgsoftware.superiorskyblock.api.hooks.ChunksProvider; import com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider; import com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider; import com.bgsoftware.superiorskyblock.api.hooks.MenusProvider; import com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider; import com.bgsoftware.superiorskyblock.api.hooks.PricesProvider; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersSnapshotProvider; import com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksProvider; import com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksSnapshotProvider; import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.hooks.listener.ISkinsListener; import com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener; import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldsListener; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.JavaVersion; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.external.async.AsyncProvider; import com.bgsoftware.superiorskyblock.external.async.AsyncProvider_Default; import com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider; import com.bgsoftware.superiorskyblock.external.chunks.ChunksProvider_Default; import com.bgsoftware.superiorskyblock.external.economy.EconomyProvider_Default; import com.bgsoftware.superiorskyblock.external.menus.MenusProvider_Default; import com.bgsoftware.superiorskyblock.external.permissions.PermissionsProvider_Default; import com.bgsoftware.superiorskyblock.external.placeholders.PlaceholdersProvider; import com.bgsoftware.superiorskyblock.external.prices.PricesProvider_Default; import com.bgsoftware.superiorskyblock.external.prices.PricesProvider_ShopsBridgeWrapper; import com.bgsoftware.superiorskyblock.external.spawners.SpawnersProvider_AutoDetect; import com.bgsoftware.superiorskyblock.external.spawners.SpawnersProvider_Default; import com.bgsoftware.superiorskyblock.external.stackedblocks.StackedBlocksProvider_AutoDetect; import com.bgsoftware.superiorskyblock.external.stackedblocks.StackedBlocksProvider_Default; import com.bgsoftware.superiorskyblock.external.vanish.VanishProvider_Default; import com.bgsoftware.superiorskyblock.external.worlds.DefaultWorldLoadListener; import com.bgsoftware.superiorskyblock.external.worlds.WorldsProvider_Default; import com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Optional; public class ProvidersManagerImpl extends Manager implements ProvidersManager { private static final BigDecimal MAX_DOUBLE = BigDecimal.valueOf(Double.MAX_VALUE); private final List AFKProvidersList = new LinkedList<>(); private List pricesLoadCallbacks = new LinkedList<>(); private SpawnersProvider spawnersProvider = new SpawnersProvider_Default(); private StackedBlocksProvider stackedBlocksProvider = new StackedBlocksProvider_Default(); private EconomyProvider economyProvider = new EconomyProvider_Default(); private EconomyProvider bankEconomyProvider = new EconomyProvider_Default(); private PermissionsProvider permissionsProvider = new PermissionsProvider_Default(); private PricesProvider pricesProvider = new PricesProvider_Default(); private VanishProvider vanishProvider = new VanishProvider_Default(); private AsyncProvider asyncProvider = new AsyncProvider_Default(); private WorldsProvider worldsProvider; private boolean isCustomWorldsProvider; private ChunksProvider chunksProvider = new ChunksProvider_Default(); private MenusProvider menusProvider; private boolean listenToSpawnerChanges = true; private final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; private final List skinsListeners = new LinkedList<>(); private final List stackedBlocksListeners = new LinkedList<>(); private final List worldsListeners = new LinkedList<>(); private final List customBlocksProviders = new LinkedList<>(); private final List entitiesProviders = new LinkedList<>(); private final IWorldLoadListener DEFAULT_WORLD_LOAD_LISTENER = new DefaultWorldLoadListener(plugin); public ProvidersManagerImpl(SuperiorSkyblockPlugin plugin) { super(plugin); setWorldsProviderInternal(new WorldsProvider_Default(plugin)); this.menusProvider = new MenusProvider_Default(plugin); } @Override public void loadData() { BukkitExecutor.sync(() -> { registerGeneralHooks(); registerSpawnersProvider(); registerStackedBlocksProvider(); registerEntitiesProvider(); registerPermissionsProvider(); registerPricesProvider(); registerVanishProvider(); registerAFKProvider(); registerAsyncProvider(); registerEconomyProviders(); registerPlaceholdersProvider(); registerChunksProvider(); }); registerMessageProviders(); // We try to forcefully load prices after a second the server has enabled. BukkitExecutor.sync(this::forcePricesLoad, 60L); } @Override public SpawnersProvider getSpawnersProvider() { return this.spawnersProvider; } @Override public void setSpawnersProvider(SpawnersProvider spawnersProvider) { Preconditions.checkNotNull(spawnersProvider, "spawnersProvider parameter cannot be null."); this.spawnersProvider = spawnersProvider; } @Override public StackedBlocksProvider getStackedBlocksProvider() { return this.stackedBlocksProvider; } @Override public void setStackedBlocksProvider(StackedBlocksProvider stackedBlocksProvider) { Preconditions.checkNotNull(stackedBlocksProvider, "stackedBlocksProvider parameter cannot be null."); this.stackedBlocksProvider = stackedBlocksProvider; } @Override public List getEntitiesProviders() { return Collections.unmodifiableList(this.entitiesProviders); } @Override public void addEntitiesProvider(EntitiesProvider entitiesProvider) { Preconditions.checkNotNull(entitiesProvider, "entitiesProvider parameter cannot be null."); this.entitiesProviders.add(entitiesProvider); } @Override public EconomyProvider getEconomyProvider() { return this.economyProvider; } @Override public void setEconomyProvider(EconomyProvider economyProvider) { Preconditions.checkNotNull(economyProvider, "economyProvider parameter cannot be null."); this.economyProvider = economyProvider; } @Override public WorldsProvider getWorldsProvider() { return this.worldsProvider; } @Override public void setWorldsProvider(WorldsProvider worldsProvider) { Preconditions.checkNotNull(worldsProvider, "worldsProvider parameter cannot be null."); setWorldsProviderInternal(worldsProvider); PluginEventsFactory.callWorldsProviderUpdateEvent(); } private void setWorldsProviderInternal(WorldsProvider worldsProvider) { this.worldsProvider = worldsProvider; this.isCustomWorldsProvider = !(worldsProvider instanceof WorldsProvider_Default); try { this.worldsProvider.addWorldLoadListener(DEFAULT_WORLD_LOAD_LISTENER); } catch (UnsupportedOperationException ignored) { // Ignore UnsupportedOperationException } } @Override public ChunksProvider getChunksProvider() { return chunksProvider; } @Override public void setChunksProvider(ChunksProvider chunksProvider) { Preconditions.checkNotNull(chunksProvider, "chunksProvider parameter cannot be null."); this.chunksProvider = chunksProvider; } @Override public EconomyProvider getBankEconomyProvider() { return this.bankEconomyProvider; } @Override public void setBankEconomyProvider(EconomyProvider bankEconomyProvider) { Preconditions.checkNotNull(bankEconomyProvider, "bankEconomyProvider parameter cannot be null."); this.bankEconomyProvider = bankEconomyProvider; } @Override public List getAFKProviders() { return Collections.unmodifiableList(this.AFKProvidersList); } @Override public void addAFKProvider(AFKProvider afkProvider) { Preconditions.checkNotNull(afkProvider, "afkProvider parameter cannot be null."); AFKProvidersList.add(afkProvider); } @Override public MenusProvider getMenusProvider() { return this.menusProvider; } @Override public void setMenusProvider(MenusProvider menusProvider) { Preconditions.checkNotNull(menusProvider, "menusProvider parameter cannot be null."); this.menusProvider = menusProvider; } @Override public PermissionsProvider getPermissionsProvider() { return permissionsProvider; } @Override public void setPermissionsProvider(PermissionsProvider permissionsProvider) { this.permissionsProvider = permissionsProvider; } @Override public PricesProvider getPricesProvider() { return pricesProvider; } @Override public void setPricesProvider(PricesProvider pricesProvider) { this.pricesProvider = pricesProvider; this.pricesProvider.getWhenPricesAreReady().whenComplete((result, error) -> this.forcePricesLoad()); } public void forcePricesLoad() { if (this.pricesLoadCallbacks != null) { this.pricesLoadCallbacks.forEach(Runnable::run); this.pricesLoadCallbacks = null; // After we loaded all the price callbacks, we want to sort the top islands. SortingType.values().forEach(plugin.getGrid()::forceSortIslands); } } @Override public VanishProvider getVanishProvider() { return vanishProvider; } @Override public void setVanishProvider(VanishProvider vanishProvider) { this.vanishProvider = vanishProvider; } @Override public void registerSkinsListener(ISkinsListener skinsListener) { this.skinsListeners.add(skinsListener); } @Override public void unregisterSkinsListener(ISkinsListener skinsListener) { this.skinsListeners.remove(skinsListener); } public boolean notifySkinsListeners(SuperiorPlayer superiorPlayer) { this.skinsListeners.forEach(skinsListener -> skinsListener.setSkinTexture(superiorPlayer)); return !this.skinsListeners.isEmpty(); } @Override public void registerStackedBlocksListener(IStackedBlocksListener stackedBlocksListener) { this.stackedBlocksListeners.add(stackedBlocksListener); } @Override public void unregisterStackedBlocksListener(IStackedBlocksListener stackedBlocksListener) { this.stackedBlocksListeners.remove(stackedBlocksListener); } public void registerCustomBlocksProvider(ICustomBlocksProvider customBlocksProvider) { this.customBlocksProviders.add(customBlocksProvider); } public List getCustomBlocksProviders() { return customBlocksProviders; } public void addPricesLoadCallback(Runnable callback) { if (this.pricesLoadCallbacks == null) { callback.run(); } else { this.pricesLoadCallbacks.add(callback); } } public void notifyStackedBlocksListeners(OfflinePlayer offlinePlayer, Block block, IStackedBlocksListener.Action action) { this.stackedBlocksListeners.forEach(stackedBlocksListener -> stackedBlocksListener.recordBlockAction(offlinePlayer, block, action)); } @Override public void registerWorldsListener(IWorldsListener worldsListener) { this.worldsListeners.add(worldsListener); } @Override public void unregisterWorldsListener(IWorldsListener worldsListener) { this.worldsListeners.remove(worldsListener); } public void runWorldsListeners(String worldName) { this.worldsListeners.forEach(worldsListener -> worldsListener.loadWorld(worldName)); } public Key getSpawnerKey(ItemStack itemStack) { String type = spawnersProvider.getSpawnerType(itemStack); return type == null ? SpawnerKey.GLOBAL_KEY : Keys.ofSpawner(type); } public boolean hasSnapshotsSupport() { return spawnersProvider instanceof SpawnersSnapshotProvider || stackedBlocksProvider instanceof StackedBlocksSnapshotProvider; } public void takeSnapshots(Chunk chunk) { if (spawnersProvider instanceof SpawnersSnapshotProvider) { ((SpawnersSnapshotProvider) spawnersProvider).takeSnapshot(chunk); } if (stackedBlocksProvider instanceof StackedBlocksSnapshotProvider) { ((StackedBlocksSnapshotProvider) stackedBlocksProvider).takeSnapshot(chunk); } } public void releaseSnapshots(ChunkPosition chunkPosition) { if (spawnersProvider instanceof SpawnersSnapshotProvider) { ((SpawnersSnapshotProvider) spawnersProvider).releaseSnapshot( chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ()); } if (stackedBlocksProvider instanceof StackedBlocksSnapshotProvider) { ((StackedBlocksSnapshotProvider) stackedBlocksProvider).releaseSnapshot( chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ()); } } public AsyncProvider getAsyncProvider() { return asyncProvider; } public EconomyProvider.EconomyResult depositMoney(SuperiorPlayer superiorPlayer, BigDecimal amount) { while (amount.compareTo(MAX_DOUBLE) > 0) { EconomyProvider.EconomyResult result = economyProvider.depositMoney(superiorPlayer, Double.MAX_VALUE); if (result.hasFailed()) return result; amount = amount.subtract(MAX_DOUBLE); } return economyProvider.depositMoney(superiorPlayer, amount.doubleValue()); } public EconomyProvider.EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal amount) { while (amount.compareTo(MAX_DOUBLE) > 0) { EconomyProvider.EconomyResult result = economyProvider.withdrawMoney(superiorPlayer, Double.MAX_VALUE); if (result.hasFailed()) return result; amount = amount.subtract(MAX_DOUBLE); } return economyProvider.withdrawMoney(superiorPlayer, amount.doubleValue()); } public EconomyProvider.EconomyResult depositMoneyForBanks(SuperiorPlayer superiorPlayer, BigDecimal amount) { while (amount.compareTo(MAX_DOUBLE) > 0) { EconomyProvider.EconomyResult result = bankEconomyProvider.depositMoney(superiorPlayer, Double.MAX_VALUE); if (result.hasFailed()) return result; amount = amount.subtract(MAX_DOUBLE); } return bankEconomyProvider.depositMoney(superiorPlayer, amount.doubleValue()); } public EconomyProvider.EconomyResult withdrawMoneyForBanks(SuperiorPlayer superiorPlayer, BigDecimal amount) { while (amount.compareTo(MAX_DOUBLE) > 0) { EconomyProvider.EconomyResult result = bankEconomyProvider.withdrawMoney(superiorPlayer, Double.MAX_VALUE); if (result.hasFailed()) return result; amount = amount.subtract(MAX_DOUBLE); } return bankEconomyProvider.withdrawMoney(superiorPlayer, amount.doubleValue()); } public boolean hasCustomWorldsSupport() { return this.isCustomWorldsProvider; } public boolean isAFK(Player player) { return AFKProvidersList.stream().anyMatch(afkProvider -> afkProvider.isAFK(player)); } public boolean shouldListenToSpawnerChanges() { return listenToSpawnerChanges; } private void registerGeneralHooks() { if (canRegisterHook("JetsMinions")) registerHook("JetsMinionsHook"); if (canRegisterHook("SkinsRestorer")) { String version = Bukkit.getPluginManager().getPlugin("SkinsRestorer").getDescription().getVersion(); if (version.startsWith("14")) { registerHook("SkinsRestorer14Hook"); } else if (version.startsWith("15")) { registerHook("SkinsRestorer15Hook"); } else { registerHook("SkinsRestorerHook"); } } if (canRegisterHook("ChangeSkin")) registerHook("ChangeSkinHook"); if (canRegisterHook("Slimefun")) registerHook("SlimefunHook"); if (canRegisterHook("CoreProtect")) registerHook("CoreProtectHook"); if (isHookEnabled("SlimeWorldManager") && JavaVersion.isAtLeast(17)) { if (isOldSlimeWorldManager()) { registerHook("SlimeWorldManagerHook"); } else { registerHook("AdvancedSlimePaperHook"); } } if (canRegisterHook("ProtocolLib")) registerHook("ProtocolLibHook"); if (Bukkit.getPluginManager().isPluginEnabled("Oraxen")) registerHook("OraxenHook"); if (Bukkit.getPluginManager().isPluginEnabled("Nexo")) registerHook("NexoHook"); if (Bukkit.getPluginManager().isPluginEnabled("ItemsAdder")) registerHook("ItemsAdderHook"); if (canRegisterHook("Plan")) registerHook("PlanHook"); if (Bukkit.getPluginManager().isPluginEnabled("CraftEngine")) // We load the hook with an extra delay to let CraftEngine load its data first BukkitExecutor.sync(() -> registerHook("CraftEngineHook"), 5L); if (canRegisterHook("SmoothTimber")) registerHook("SmoothTimberHook"); if (canRegisterHook("SilkSpawners")) { List pluginAuthors = Bukkit.getPluginManager().getPlugin("SilkSpawners").getDescription().getAuthors(); if (pluginAuthors.contains("mushroomhostage")) { registerHook("TimbruSilkSpawnersHook"); } } } private void registerMessageProviders() { if (isHookEnabled("MiniMessage") && hasMiniMessageSupport()) { registerHook("MiniMessageHook"); } } private void registerSpawnersProvider() { if (!(spawnersProvider instanceof SpawnersProvider_AutoDetect)) return; String configSpawnersProvider = plugin.getSettings().getSpawnersProvider(); boolean auto = configSpawnersProvider.equalsIgnoreCase("Auto"); Optional spawnersProvider = Optional.empty(); if (canRegisterHook("MergedSpawner") && (auto || configSpawnersProvider.equalsIgnoreCase("MergedSpawner"))) { spawnersProvider = createInstance("spawners.SpawnersProvider_MergedSpawner"); listenToSpawnerChanges = false; } else if (canRegisterHook("AdvancedSpawners") && (auto || configSpawnersProvider.equalsIgnoreCase("AdvancedSpawners"))) { spawnersProvider = createInstance("spawners.SpawnersProvider_AdvancedSpawners"); } else if (canRegisterHook("WildStacker") && (auto || configSpawnersProvider.equalsIgnoreCase("WildStacker"))) { spawnersProvider = createInstance("spawners.SpawnersProvider_WildStacker"); } else if (canRegisterHook("SilkSpawners") && (auto || configSpawnersProvider.equalsIgnoreCase("SilkSpawners"))) { Plugin silkSpawnersPlugin = Bukkit.getPluginManager().getPlugin("SilkSpawners"); if (silkSpawnersPlugin.getDescription().getAuthors().contains("CandC_9_12")) { spawnersProvider = createInstance("spawners.SpawnersProvider_CandcSilkSpawners"); } else if (silkSpawnersPlugin.getDescription().getAuthors().contains("mushroomhostage")) { spawnersProvider = createInstance("spawners.SpawnersProvider_TimbruSilkSpawners"); } } else if (canRegisterHook("PvpingSpawners") && (auto || configSpawnersProvider.equalsIgnoreCase("PvpingSpawners"))) { spawnersProvider = createInstance("spawners.SpawnersProvider_PvpingSpawners"); } else if (canRegisterHook("EpicSpawners") && (auto || configSpawnersProvider.equalsIgnoreCase("EpicSpawners"))) { String version = Bukkit.getPluginManager().getPlugin("EpicSpawners").getDescription().getVersion(); if (version.startsWith("9")) { spawnersProvider = createInstance("spawners.SpawnersProvider_EpicSpawners9"); } else if (version.startsWith("8")) { spawnersProvider = createInstance("spawners.SpawnersProvider_EpicSpawners8"); } else if (version.startsWith("7")) { spawnersProvider = createInstance("spawners.SpawnersProvider_EpicSpawners7"); } else { spawnersProvider = createInstance("spawners.SpawnersProvider_EpicSpawners6"); } } else if (canRegisterHook("UltimateStacker") && (auto || configSpawnersProvider.equalsIgnoreCase("UltimateStacker"))) { String version = Bukkit.getPluginManager().getPlugin("UltimateStacker").getDescription().getVersion(); int majorVersion = Integer.parseInt(String.valueOf(version.charAt(0))); if (majorVersion >= 4) { spawnersProvider = createInstance("spawners.SpawnersProvider_UltimateStacker4"); } else if (majorVersion == 3) { spawnersProvider = createInstance("spawners.SpawnersProvider_UltimateStacker3"); } else { spawnersProvider = createInstance("spawners.SpawnersProvider_UltimateStacker"); } listenToSpawnerChanges = false; } else if (canRegisterHook("RoseStacker") && (auto || configSpawnersProvider.equalsIgnoreCase("RoseStacker"))) { spawnersProvider = createInstance("spawners.SpawnersProvider_RoseStacker"); listenToSpawnerChanges = false; } spawnersProvider.ifPresent(this::setSpawnersProvider); } private void registerStackedBlocksProvider() { if (!(stackedBlocksProvider instanceof StackedBlocksProvider_AutoDetect)) return; String configStackedBlocksProvider = plugin.getSettings().getStackedBlocksProvider(); boolean auto = configStackedBlocksProvider.equalsIgnoreCase("Auto"); Optional stackedBlocksProvider = Optional.empty(); if (canRegisterHook("WildStacker") && (auto || configStackedBlocksProvider.equalsIgnoreCase("WildStacker"))) { stackedBlocksProvider = createInstance("stackedblocks.StackedBlocksProvider_WildStacker"); } else if (canRegisterHook("RoseStacker") && (auto || configStackedBlocksProvider.equalsIgnoreCase("RoseStacker"))) { stackedBlocksProvider = createInstance("stackedblocks.StackedBlocksProvider_RoseStacker"); } stackedBlocksProvider.ifPresent(this::setStackedBlocksProvider); } private void registerEntitiesProvider() { if (canRegisterHook("WildStacker")) { Optional entitiesProvider = createInstance("entities.EntitiesProvider_WildStacker"); entitiesProvider.ifPresent(this::addEntitiesProvider); } if (canRegisterHook("RoseStacker")) { Optional entitiesProvider = createInstance("entities.EntitiesProvider_RoseStacker"); entitiesProvider.ifPresent(this::addEntitiesProvider); } } private void registerPermissionsProvider() { Optional permissionsProvider = Optional.empty(); if (canRegisterHook("LuckPerms")) { permissionsProvider = createInstance("permissions.PermissionsProvider_LuckPerms"); } permissionsProvider.ifPresent(this::setPermissionsProvider); } private void registerPricesProvider() { ShopsProvider.SHOPGUIPLUS.createInstance(plugin) .map(shopsBridge -> new PricesProvider_ShopsBridgeWrapper(plugin, ShopsProvider.SHOPGUIPLUS, shopsBridge)) .ifPresent(this::setPricesProvider); } private void registerVanishProvider() { Optional vanishProvider = Optional.empty(); if (canRegisterHook("VanishNoPacket")) { vanishProvider = createInstance("vanish.VanishProvider_VanishNoPacket"); } else if (canRegisterHook("SuperVanish") || canRegisterHook("PremiumVanish")) { vanishProvider = createInstance("vanish.VanishProvider_SuperVanish"); } else if (canRegisterHook("Essentials")) { vanishProvider = createInstance("vanish.VanishProvider_Essentials"); } else if (canRegisterHook("CMI")) { vanishProvider = createInstance("vanish.VanishProvider_CMI"); } vanishProvider.ifPresent(this::setVanishProvider); } private void registerAFKProvider() { if (canRegisterHook("CMI")) { Optional afkProvider = createInstance("afk.AFKProvider_CMI"); afkProvider.ifPresent(this::addAFKProvider); } if (canRegisterHook("Essentials")) { Optional afkProvider = createInstance("afk.AFKProvider_Essentials"); afkProvider.ifPresent(this::addAFKProvider); } } private void registerAsyncProvider() { if (hasPaperAsyncSupport()) { Optional asyncProviderOptional = createInstance("async.AsyncProvider_Paper"); asyncProviderOptional.ifPresent(asyncProvider -> { this.asyncProvider = asyncProvider; }); } } private void registerEconomyProviders() { if (canRegisterHook("Vault")) { if (this.economyProvider instanceof EconomyProvider_Default || this.bankEconomyProvider instanceof EconomyProvider_Default) { Optional economyProviderOptional = createInstance("economy.EconomyProvider_Vault"); economyProviderOptional.ifPresent(economyProvider -> { if (this.economyProvider instanceof EconomyProvider_Default) setEconomyProvider(economyProvider); if (this.bankEconomyProvider instanceof EconomyProvider_Default) setBankEconomyProvider(economyProvider); }); } } } private void registerPlaceholdersProvider() { List placeholdersProviders = new ArrayList<>(); if (canRegisterHook("MVdWPlaceholderAPI")) { Optional placeholdersProvider = createInstance("placeholders.PlaceholdersProvider_MVdWPlaceholderAPI"); placeholdersProvider.ifPresent(placeholdersProviders::add); } if (canRegisterHook("PlaceholderAPI")) { Optional placeholdersProvider = createInstance("placeholders.PlaceholdersProvider_PlaceholderAPI"); placeholdersProvider.ifPresent(placeholdersProviders::add); } ((PlaceholdersServiceImpl) this.placeholdersService.get()).register(placeholdersProviders); } private void registerChunksProvider() { if (hasPaperAsyncSupport()) { Optional chunksProviderOptional = createInstance("chunks.ChunksProvider_Paper"); chunksProviderOptional.ifPresent(chunksProvider -> { try { setChunksProvider(chunksProvider); Log.info("Detected PaperSpigot - Using async chunk-loading support with PaperMC."); } catch (Exception error) { Log.error(error, "Detected PaperSpigot but failed to load async chunk-loading support due to an unexpected error:"); } }); } } private void registerHook(String className) { try { Class clazz = Class.forName("com.bgsoftware.superiorskyblock.external." + className); if (!isHookCompatible(clazz)) return; Method registerMethod = clazz.getMethod("register", SuperiorSkyblockPlugin.class); registerMethod.invoke(null, plugin); } catch (Throwable error) { if (error.getClass() != UnsupportedClassVersionError.class) Log.error(error, "An unexpected error occurred while registering hook ", className, ":"); } } private static boolean hasPaperAsyncSupport() { return new ReflectMethod<>(World.class, "getChunkAtAsync", int.class, int.class).isValid(); } private static boolean isOldSlimeWorldManager() { try { Class.forName("com.grinderwolf.swm.api.SlimePlugin"); return true; } catch (ClassNotFoundException error) { return false; } } private static boolean hasMiniMessageSupport() { try { Class.forName("net.kyori.adventure.text.minimessage.MiniMessage"); return ServerVersion.isAtLeast(ServerVersion.v1_18); } catch (ClassNotFoundException error) { return false; } } private Optional createInstance(String className) { try { Class clazz = Class.forName("com.bgsoftware.superiorskyblock.external." + className); if (!isHookCompatible(clazz)) return Optional.empty(); try { Constructor constructor = clazz.getConstructor(SuperiorSkyblockPlugin.class); // noinspection unchecked return Optional.of((T) constructor.newInstance(plugin)); } catch (NoSuchMethodException error) { // noinspection unchecked return Optional.of((T) clazz.newInstance()); } } catch (ClassNotFoundException ignored) { return Optional.empty(); } catch (Exception error) { Log.entering("ENTER", className); Log.error(error, "An unexpected error occurred while creating hook instance:"); return Optional.empty(); } } private boolean canRegisterHook(String pluginName) { return Bukkit.getPluginManager().isPluginEnabled(pluginName) && isHookEnabled(pluginName); } private boolean isHookEnabled(String pluginName) { return !plugin.getSettings().getDisabledHooks().contains(pluginName.toLowerCase(Locale.ENGLISH)); } private boolean isHookCompatible(Class clazz) { ReflectMethod compatibleMethod = new ReflectMethod<>(clazz, "isCompatible"); return !compatibleMethod.isValid() || compatibleMethod.invoke(null); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/async/AsyncProvider.java ================================================ package com.bgsoftware.superiorskyblock.external.async; import org.bukkit.Location; import org.bukkit.entity.Entity; import java.util.function.Consumer; public interface AsyncProvider { default void teleport(Entity entity, Location location) { teleport(entity, location, r -> { }); } void teleport(Entity entity, Location location, Consumer teleportResult); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/async/AsyncProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.async; import com.bgsoftware.superiorskyblock.external.async.AsyncProvider; import org.bukkit.Location; import org.bukkit.entity.Entity; import java.util.function.Consumer; public class AsyncProvider_Default implements AsyncProvider { @Override public void teleport(Entity entity, Location location, Consumer teleportResult) { boolean result = entity.teleport(location); if (teleportResult != null) teleportResult.accept(result); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/blocks/ICustomBlocksProvider.java ================================================ package com.bgsoftware.superiorskyblock.external.blocks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.ChunkPosition; public interface ICustomBlocksProvider { @Nullable KeyMap getBlockCountsForChunk(ChunkPosition chunkPosition); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/chunks/ChunksProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.chunks; import com.bgsoftware.superiorskyblock.api.hooks.ChunksProvider; import org.bukkit.Chunk; import org.bukkit.World; import java.util.concurrent.CompletableFuture; public class ChunksProvider_Default implements ChunksProvider { @Override public CompletableFuture loadChunk(World world, int chunkX, int chunkZ) { return CompletableFuture.completedFuture(world.getChunkAt(chunkX, chunkZ)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/economy/EconomyProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.economy; import com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.math.BigDecimal; public class EconomyProvider_Default implements EconomyProvider { private static final BigDecimal MAX_DOUBLE = BigDecimal.valueOf(Double.MAX_VALUE); @Override public BigDecimal getBalance(SuperiorPlayer superiorPlayer) { return MAX_DOUBLE; } @Override public EconomyResult depositMoney(SuperiorPlayer superiorPlayer, double amount) { return new EconomyResult("Vault is not installed"); } @Override public EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, double amount) { return new EconomyResult("Vault is not installed"); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.menus; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.MenusProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.MenuConfig; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmBan; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandCreation; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandPrivileges; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissionsCategory; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryIconEdit; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpIconEdit; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpManage; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarps; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.MenuCustom; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.google.common.base.Preconditions; import java.io.File; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class MenusProvider_Default implements MenusProvider { private final Map ISLAND_CREATION_CONFIG_CACHE = new IdentityHashMap<>(); private final SuperiorSkyblockPlugin plugin; public MenusProvider_Default(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } private static void handleExceptions(Runnable runnable) { try { runnable.run(); } catch (Exception ex) { ManagerLoadException handlerError = new ManagerLoadException(ex, ManagerLoadException.ErrorLevel.CONTINUE); Log.error(handlerError, "An unexpected error occurred while loading menu:"); } } @Override public void initializeMenus() { File guiFolder = new File(plugin.getDataFolder(), "guis"); if (guiFolder.exists()) { File oldGuisFolder = new File(plugin.getDataFolder(), "old-guis"); //noinspection ResultOfMethodCallIgnored guiFolder.renameTo(oldGuisFolder); } // We first want to unregister all menus plugin.getMenus().unregisterMenus(); Menus.registerMenus(); File customMenusFolder = new File(plugin.getDataFolder(), "menus/custom"); if (!customMenusFolder.exists()) { //noinspection ResultOfMethodCallIgnored customMenusFolder.mkdirs(); return; } for (File menuFile : Files.listFolderFiles(customMenusFolder, false)) { handleExceptions(() -> plugin.getMenus().registerMenu(MenuCustom.createInstance(menuFile))); } } @Override public void openBankLogs(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_BANK_LOGS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshBankLogs(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_BANK_LOGS.refreshViews(island); } @Override public void openBiomes(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_BIOMES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void openBorderColor(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Menus.MENU_BORDER_COLOR.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu); } @Override public void openConfirmBan(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer bannedPlayer) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Preconditions.checkNotNull(bannedPlayer, "bannedPlayer parameter cannot be null."); Menus.MENU_CONFIRM_BAN.createView(targetPlayer, new MenuConfirmBan.Args(targetIsland, bannedPlayer), previousMenu); } @Override public void openConfirmDisband(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_CONFIRM_DISBAND.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void openConfirmKick(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer kickedPlayer) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Preconditions.checkNotNull(kickedPlayer, "kickedPlayer parameter cannot be null."); Menus.MENU_CONFIRM_KICK.createView(targetPlayer, new MenuConfirmKick.Args(targetIsland, kickedPlayer), previousMenu); } @Override public void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Menus.MENU_CONFIRM_LEAVE.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu); } @Override public void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Preconditions.checkNotNull(newOwner, "newOwner parameter cannot be null."); Menus.MENU_CONFIRM_TRANSFER.createView(targetPlayer, new MenuConfirmTransfer.Args(targetIsland, newOwner), previousMenu); } @Override public void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_CONTROL_PANEL.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void openCoops(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_COOPS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshCoops(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_COOPS.refreshViews(island); } @Override public void openCounts(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_COUNTS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshCounts(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_COUNTS.refreshViews(island); } @Override public void openGlobalWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Menus.MENU_GLOBAL_WARPS.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu); } @Override public void refreshGlobalWarps() { Menus.MENU_GLOBAL_WARPS.refreshViews(); } @Override public void openIslandBank(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_BANK.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshIslandBank(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_BANK.refreshViews(island); } @Override public void openIslandBannedPlayers(SuperiorPlayer targetPlayer, ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_BANNED_PLAYERS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshIslandBannedPlayers(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_BANNED_PLAYERS.refreshViews(island); } @Override public void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); if (Menus.MENU_ISLAND_CHEST.isSkipOneItem()) { IslandChest[] islandChest = targetIsland.getChest(); if (islandChest.length == 1) { islandChest[0].openChest(targetPlayer); return; } } Menus.MENU_ISLAND_CHEST.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshIslandChest(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_CHEST.refreshViews(island); } @Override public MenuIslandCreationConfig getIslandCreationConfig(Schematic schematic) { return ISLAND_CREATION_CONFIG_CACHE.computeIfAbsent(schematic, unused -> { for (MenuTemplateButton button : Menus.MENU_ISLAND_CREATION.getLayout().getButtons()) { if (IslandCreationButton.class.equals(button.getViewButtonType()) && ((IslandCreationButton.Template) button).getSchematic().equals(schematic)) { return ((IslandCreationButton.Template) button).getCreationConfig(); } } return new MenuConfig.IslandCreation(schematic, null); }); } @Override public void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); if (Menus.MENU_ISLAND_CREATION.isSkipOneItem()) { List schematicButtons = Menus.MENU_ISLAND_CREATION.getLayout().getButtons().stream() .filter(button -> IslandCreationButton.class.equals(button.getViewButtonType())) .map(button -> ((IslandCreationButton.Template) button).getSchematic()) .collect(Collectors.toList()); if (schematicButtons.size() == 1) { MenuIslandCreationConfig creationConfig = getIslandCreationConfig(schematicButtons.get(0)); MenuActions.simulateIslandCreationClick(targetPlayer, islandName, creationConfig, false, targetPlayer.getOpenedView()); return; } } Menus.MENU_ISLAND_CREATION.createView(targetPlayer, new MenuIslandCreation.Args(islandName), previousMenu); } @Override public void openIslandRate(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_RATE.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void openIslandRatings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_RATINGS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshIslandRatings(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_RATINGS.refreshViews(island); } @Override public void openMemberManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(islandMember, "islandMember parameter cannot be null."); Menus.MENU_MEMBER_MANAGE.createView(targetPlayer, new PlayerViewArgs(islandMember), previousMenu); } @Override public void destroyMemberManage(SuperiorPlayer islandMember) { Preconditions.checkNotNull(islandMember, "islandMember parameter cannot be null."); Menus.MENU_MEMBER_MANAGE.closeViews(islandMember); } @Override public void openMemberRole(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SuperiorPlayer islandMember) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(islandMember, "islandMember parameter cannot be null."); Menus.MENU_MEMBER_ROLE.createView(targetPlayer, new PlayerViewArgs(islandMember), previousMenu); } @Override public void destroyMemberRole(SuperiorPlayer islandMember) { Preconditions.checkNotNull(islandMember, "islandMember parameter cannot be null."); Menus.MENU_MEMBER_ROLE.closeViews(islandMember); } @Override public void openMembers(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_MEMBERS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshMembers(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_MEMBERS.refreshViews(island); } @Override public void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); if (Menus.MENU_MISSIONS.isSkipOneItem()) { List missionCategories = plugin.getMissions().getMissionCategories(); if (missionCategories.size() == 1) { openMissionsCategory(targetPlayer, previousMenu, missionCategories.get(0)); return; } } Menus.MENU_MISSIONS.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu); } @Override public void openMissionsCategory(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, MissionCategory missionCategory) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(missionCategory, "missionCategory parameter cannot be null."); Menus.MENU_MISSIONS_CATEGORY.createView(targetPlayer, new MenuMissionsCategory.Args(missionCategory), previousMenu); } @Override public void refreshMissionsCategory(MissionCategory missionCategory) { Preconditions.checkNotNull(missionCategory, "missionCategory parameter cannot be null."); Menus.MENU_MISSIONS_CATEGORY.refreshViews(missionCategory); } @Override public void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer permissiblePlayer) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Preconditions.checkNotNull(permissiblePlayer, "permissiblePlayer parameter cannot be null."); Menus.MENU_ISLAND_PRIVILEGES.createView(targetPlayer, new MenuIslandPrivileges.Args(targetIsland, permissiblePlayer), previousMenu); } @Override public void openPermissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, PlayerRole permissibleRole) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Preconditions.checkNotNull(permissibleRole, "permissibleRole parameter cannot be null."); Menus.MENU_ISLAND_PRIVILEGES.createView(targetPlayer, new MenuIslandPrivileges.Args(targetIsland, permissibleRole), previousMenu); } @Override public void refreshPermissions(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_PRIVILEGES.refreshViews(island); } @Override public void refreshPermissions(Island island, SuperiorPlayer permissiblePlayer) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(permissiblePlayer, "permissiblePlayer parameter cannot be null."); Menus.MENU_ISLAND_PRIVILEGES.refreshViews(island, permissiblePlayer); } @Override public void refreshPermissions(Island island, PlayerRole permissibleRole) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(permissibleRole, "permissibleRole parameter cannot be null."); Menus.MENU_ISLAND_PRIVILEGES.refreshViews(island, permissibleRole); } @Override public void updatePermission(IslandPrivilege islandPrivilege) { // The default implementation does not care if the island privilege is valid for showing the island // privileges in the menu. If the island privilege is not valid at the time of opening the menu, it // will show it as it was disabled. This is the responsibility of the server owners to properly // configure the menu. } @Override public void openPlayerLanguage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Menus.MENU_PLAYER_LANGUAGE.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu); } @Override public void openSettings(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_FLAGS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshSettings(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_FLAGS.refreshViews(island); } @Override public void updateSettings(IslandFlag islandFlag) { // The default implementation does not care if the island flag is valid for showing the island flags // in the menu. If the island flag is not valid at the time of opening the menu, it will show it as // it was disabled. This is the responsibility of the server owners to properly configure the menu. } @Override public void openTopIslands(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, SortingType sortingType) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); Menus.MENU_TOP_ISLANDS.createView(targetPlayer, new MenuTopIslands.Args(sortingType), previousMenu); } @Override public void refreshTopIslands(SortingType sortingType) { Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); Menus.MENU_TOP_ISLANDS.refreshViews(sortingType); } @Override public void openUniqueVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_UNIQUE_VISITORS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshUniqueVisitors(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_UNIQUE_VISITORS.refreshViews(island); } @Override public void openUpgrades(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_UPGRADES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshUpgrades(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_UPGRADES.refreshViews(island); } @Override public void openValues(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_VALUES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshValues(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_VALUES.refreshViews(island); } @Override public void openVisitors(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); Menus.MENU_ISLAND_VISITORS.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @Override public void refreshVisitors(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_ISLAND_VISITORS.refreshViews(island); } @Override public void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); // The warp categories menu should be opened only if: // A) its enabled // B) there are more than 1 category if (plugin.getSettings().isWarpCategories() && targetIsland.getWarpCategories().size() > 1) { Menus.MENU_WARP_CATEGORIES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } else { WarpCategory warpCategory = targetIsland.getWarpCategories().values().stream().findFirst() .orElseGet(() -> targetIsland.createWarpCategory("Default Category")); openWarps(targetPlayer, previousMenu, warpCategory); } } @Override public void refreshWarpCategories(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_WARP_CATEGORIES.refreshViews(island); } @Override public void destroyWarpCategories(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Menus.MENU_WARP_CATEGORIES.closeViews(island); } @Override public void openWarpCategoryIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetCategory, "targetCategory parameter cannot be null."); Menus.MENU_WARP_CATEGORY_ICON_EDIT.createView(targetPlayer, new MenuWarpCategoryIconEdit.Args(targetCategory), previousMenu); } @Override public void openWarpCategoryManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetCategory, "targetCategory parameter cannot be null."); Menus.MENU_WARP_CATEGORY_MANAGE.createView(targetPlayer, new MenuWarpCategoryManage.Args(targetCategory), previousMenu); } @Override public void refreshWarpCategoryManage(WarpCategory warpCategory) { Preconditions.checkNotNull(warpCategory, "warpCategory parameter cannot be null."); Menus.MENU_WARP_CATEGORY_MANAGE.refreshViews(warpCategory); } @Override public void openWarpIconEdit(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetWarp, "targetWarp parameter cannot be null."); Menus.MENU_WARP_ICON_EDIT.createView(targetPlayer, new MenuWarpIconEdit.Args(targetWarp), previousMenu); } @Override public void openWarpManage(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, IslandWarp targetWarp) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetWarp, "targetWarp parameter cannot be null."); Menus.MENU_WARP_MANAGE.createView(targetPlayer, new MenuWarpManage.Args(targetWarp), previousMenu); } @Override public void refreshWarpManage(IslandWarp islandWarp) { Preconditions.checkNotNull(islandWarp, "islandWarp parameter cannot be null."); Menus.MENU_WARP_MANAGE.refreshViews(islandWarp); } @Override public void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetCategory, "targetCategory parameter cannot be null."); // We want skip one item to only work if the player can't edit warps, otherwise he // won't be able to edit them as the menu will get skipped if only one warp exists. if (Menus.MENU_WARPS.isSkipOneItem() && !targetCategory.getIsland().hasPermission(targetPlayer, IslandPrivileges.SET_WARP)) { List availableWarps = targetCategory.getIsland().isMember(targetPlayer) ? targetCategory.getWarps() : targetCategory.getWarps().stream() .filter(islandWarp -> !islandWarp.hasPrivateFlag()) .collect(Collectors.toList()); if (availableWarps.size() == 1) { MenuActions.simulateWarpsClick(targetPlayer, targetCategory.getIsland(), availableWarps.get(0)); return; } } Menus.MENU_WARPS.createView(targetPlayer, new MenuWarps.Args(targetCategory), previousMenu); } @Override public void refreshWarps(WarpCategory warpCategory) { Preconditions.checkNotNull(warpCategory, "warpCategory parameter cannot be null."); Menus.MENU_WARPS.refreshViews(warpCategory); } @Override public void destroyWarps(WarpCategory warpCategory) { Preconditions.checkNotNull(warpCategory, "warpCategory parameter cannot be null."); Menus.MENU_WARPS.closeViews(warpCategory); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/permissions/PermissionsProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.permissions; import com.bgsoftware.common.reflection.ClassInfo; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider; import org.bukkit.entity.Player; import org.bukkit.permissions.PermissibleBase; import org.bukkit.permissions.PermissionAttachmentInfo; import java.util.Locale; import java.util.Map; public class PermissionsProvider_Default implements PermissionsProvider { private static final ReflectField HUMAN_ENTITY_PERMS = new ReflectField<>( new ClassInfo("entity.CraftHumanEntity", ClassInfo.PackageType.CRAFTBUKKIT), PermissibleBase.class, "perm"); private static final ReflectField> PERMISSIBLE_BASE_PERMISSIONS = new ReflectField<>(PermissibleBase.class, Map.class, "permissions"); @Override public boolean hasPermission(Player player, String permission) { PermissibleBase permissibleBase = HUMAN_ENTITY_PERMS.get(player); PermissionAttachmentInfo permissionAttachmentInfo = PERMISSIBLE_BASE_PERMISSIONS.get(permissibleBase) .get(permission.toLowerCase(Locale.ENGLISH)); return permissionAttachmentInfo != null && permissionAttachmentInfo.getValue(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/placeholders/PlaceholdersProvider.java ================================================ package com.bgsoftware.superiorskyblock.external.placeholders; import org.bukkit.OfflinePlayer; public interface PlaceholdersProvider { String parsePlaceholders(OfflinePlayer offlinePlayer, String value); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/prices/PricesProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.prices; import com.bgsoftware.superiorskyblock.api.hooks.PricesProvider; import com.bgsoftware.superiorskyblock.api.key.Key; import java.math.BigDecimal; public class PricesProvider_Default implements PricesProvider { private final BigDecimal INVALID_WORTH = BigDecimal.valueOf(-1); @Override public BigDecimal getPrice(Key key) { return INVALID_WORTH; } @Override public Key getBlockKey(Key blockKey) { return blockKey; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/prices/PricesProvider_ShopsBridgeWrapper.java ================================================ package com.bgsoftware.superiorskyblock.external.prices; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.shopsbridge.IShopsBridge; import com.bgsoftware.common.shopsbridge.ShopsProvider; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.PricesProvider; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Material; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.math.BigDecimal; import java.util.Locale; import java.util.concurrent.CompletableFuture; public class PricesProvider_ShopsBridgeWrapper implements PricesProvider { private final KeyMap cachedPrices = KeyMap.createConcurrentKeyMap(); private final SuperiorSkyblockPlugin plugin; private final IShopsBridge shopsBridge; public PricesProvider_ShopsBridgeWrapper(SuperiorSkyblockPlugin plugin, ShopsProvider shopsProvider, IShopsBridge shopsBridge) { Log.info("Using " + shopsProvider.getPluginName() + " as a prices provider."); this.plugin = plugin; this.shopsBridge = shopsBridge; } @Override public BigDecimal getPrice(Key key) { try { return this.cachedPrices.computeIfAbsent(key, this::getPriceFromShopsBridge); } catch (Throwable error) { Log.error(error, "Failed to load prices for item " + key); return BigDecimal.ZERO; } } @Nullable @Override public Key getBlockKey(Key blockKey) { return this.cachedPrices.getKey(blockKey, null); } @Override public CompletableFuture getWhenPricesAreReady() { return this.shopsBridge.getWhenShopsLoaded(); } private BigDecimal getPriceFromShopsBridge(Key key) { ItemStack itemStack; try { Material material = Material.valueOf(key.getGlobalKey().toUpperCase(Locale.ENGLISH)); if (material == Materials.SPAWNER.toBukkitType()) { EntityType entityType = EntityType.valueOf(key.getSubKey().toUpperCase(Locale.ENGLISH)); itemStack = new ItemBuilder(material).withEntityType(entityType).build(); } else { short durability = Short.parseShort(key.getSubKey()); itemStack = new ItemStack(material, 1, durability); } } catch (Throwable error) { return BigDecimal.ZERO; } switch (plugin.getSettings().getSyncWorth()) { case BUY: return this.shopsBridge.getBuyPrice(itemStack); case SELL: return this.shopsBridge.getSellPrice(itemStack); default: return BigDecimal.ZERO; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProviderItemMetaSpawnerType.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.google.common.base.Preconditions; import org.bukkit.block.CreatureSpawner; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; import java.util.Optional; public interface SpawnersProviderItemMetaSpawnerType extends SpawnersProvider_AutoDetect { default String getSpawnerType(ItemStack itemStack) { Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); if (itemStack.getItemMeta() instanceof BlockStateMeta) { CreatureSpawner creatureSpawner = (CreatureSpawner) ((BlockStateMeta) itemStack.getItemMeta()).getBlockState(); return Optional.ofNullable(creatureSpawner.getSpawnedType()).map(EntityType::name).orElse(null); } return "PIG"; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AutoDetect.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider; public interface SpawnersProvider_AutoDetect extends SpawnersProvider { } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.spawners; import com.bgsoftware.superiorskyblock.api.objects.Pair; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; public class SpawnersProvider_Default implements SpawnersProvider_AutoDetect { @Override public Pair getSpawner(Location location) { return new Pair<>(1, null); } @Override public String getSpawnerType(ItemStack itemStack) { return "PIG"; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_AutoDetect.java ================================================ package com.bgsoftware.superiorskyblock.external.stackedblocks; import com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksProvider; public interface StackedBlocksProvider_AutoDetect extends StackedBlocksProvider { } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.stackedblocks; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import org.bukkit.World; import java.util.Collection; import java.util.Collections; public class StackedBlocksProvider_Default implements StackedBlocksProvider_AutoDetect { @Override public Collection> getBlocks(World world, int chunkX, int chunkZ) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/text/ITextFormatter.java ================================================ package com.bgsoftware.superiorskyblock.external.text; public interface ITextFormatter { String format(String value); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.vanish; import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; import org.bukkit.entity.Player; import org.bukkit.metadata.MetadataValue; public class VanishProvider_Default implements VanishProvider { @Override public boolean isVanished(Player player) { return player.getMetadata("vanished").stream() .anyMatch(MetadataValue::asBoolean); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java ================================================ package com.bgsoftware.superiorskyblock.external.worlds; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; import com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags; import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.LazyReference; import org.bukkit.World; public class DefaultWorldLoadListener implements IWorldLoadListener { private final LazyReference dragonBattleService = new LazyReference() { @Override protected DragonBattleService create() { return plugin.getServices().getService(DragonBattleService.class); } }; private final SuperiorSkyblockPlugin plugin; public DefaultWorldLoadListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public void onWorldLoad(World world, Dimension worldDimension, @WorldLoadFlags int flags) { if ((flags & WorldLoadFlags.END_DRAGON_FIGHT) != 0) { SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(worldDimension); if (worldDimension.getEnvironment() == World.Environment.THE_END && dimensionConfig instanceof SettingsManager.Worlds.End && ((SettingsManager.Worlds.End) dimensionConfig).isDragonFight()) { dragonBattleService.get().prepareEndWorld(world); } } if ((flags & WorldLoadFlags.REMOVE_ANTI_XRAY) != 0) plugin.getNMSWorld().removeAntiXray(world); if ((flags & WorldLoadFlags.UPDATE_OCEAN_LEVEL) != 0) plugin.getNMSWorld().setOceanLevel(world); if ((flags & WorldLoadFlags.LISTEN_BLOCK_CHANGES) != 0) plugin.getNMSWorld().listenBlockStateChanges(world); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java ================================================ package com.bgsoftware.superiorskyblock.external.worlds; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; import com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import org.bukkit.Bukkit; import org.bukkit.Difficulty; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.WorldCreator; import org.bukkit.WorldType; import org.bukkit.block.BlockFace; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; public class WorldsProvider_Default implements WorldsProvider { @WorldLoadFlags private static final int SUPPORTED_LOAD_FLAGS = WorldLoadFlags.END_DRAGON_FIGHT | WorldLoadFlags.REMOVE_ANTI_XRAY | WorldLoadFlags.UPDATE_OCEAN_LEVEL | WorldLoadFlags.LISTEN_BLOCK_CHANGES; private final Set servedPositions = Sets.newHashSet(); private final EnumerateMap islandWorlds = new EnumerateMap<>(Dimension.values()); private final Map islandWorldsToDimensions = new HashMap<>(); private final List worldLoadListenerList = new LinkedList<>(); private final SuperiorSkyblockPlugin plugin; private World islandsWorld; public WorldsProvider_Default(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public void prepareWorlds() { Difficulty difficulty = Difficulty.valueOf(plugin.getSettings().getWorlds().getDifficulty()); for (Dimension dimension : Dimension.values()) { SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); if (dimensionConfig != null && dimensionConfig.isEnabled()) { String worldName = dimensionConfig.getName(); World world = loadWorld(worldName, difficulty, dimension); if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) this.islandsWorld = world; } } } @Override public World getIslandsWorld(Island island, Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); return islandWorlds.get(dimension); } @Override public Dimension getIslandsWorldDimension(World world) { Preconditions.checkNotNull(world, "world parameter cannot be null."); return islandWorldsToDimensions.get(world.getUID()); } @Override public boolean isIslandsWorld(World world) { Preconditions.checkNotNull(world, "world parameter cannot be null."); return islandWorldsToDimensions.containsKey(world.getUID()); } @Override public Location getNextLocation(BlockPosition previousPosition, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID) { Preconditions.checkNotNull(previousPosition, "previousPosition parameter cannot be null."); BlockFace islandFace = getIslandFace(previousPosition); BlockPosition nextPosition; int islandRange = maxIslandSize * 3; if (islandFace == BlockFace.NORTH) { nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0); } else if (islandFace == BlockFace.EAST) { if (previousPosition.getX() == -previousPosition.getZ()) nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0); else if (previousPosition.getX() == previousPosition.getZ()) nextPosition = nextPosition(previousPosition, islandsHeight, -islandRange, 0); else nextPosition = nextPosition(previousPosition, islandsHeight, 0, islandRange); } else if (islandFace == BlockFace.SOUTH) { if (previousPosition.getX() == -previousPosition.getZ()) nextPosition = nextPosition(previousPosition, islandsHeight, 0, -islandRange); else nextPosition = nextPosition(previousPosition, islandsHeight, -islandRange, 0); } else if (islandFace == BlockFace.WEST) { if (previousPosition.getX() == previousPosition.getZ()) nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0); else nextPosition = nextPosition(previousPosition, islandsHeight, 0, -islandRange); } else { throw new IllegalStateException(); } Location nextLocation = nextPosition.toLocation(this.islandsWorld); if (servedPositions.contains(nextPosition) || plugin.getGrid().getIslandAt(nextLocation) != null) { return getNextLocation(nextPosition, islandsHeight, maxIslandSize, islandOwner, islandUUID); } servedPositions.add(nextPosition); return nextLocation; } @Override public void finishIslandCreation(Location islandLocation, UUID islandOwner, UUID islandUUID) { Preconditions.checkNotNull(islandLocation, "islandLocation parameter cannot be null."); servedPositions.remove(SBlockPosition.of(islandLocation)); } @Override public void prepareTeleport(Island island, Location location, Runnable finishCallback) { finishCallback.run(); } @Override public boolean isDimensionEnabled(Dimension dimension) { SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); // If the config is null, it probably means another plugin registered it. // Therefore, we register it as enabled. return dimensionConfig == null || dimensionConfig.isEnabled(); } @Override public boolean isDimensionUnlocked(Dimension dimension) { SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); // If the config is null, it probably means another plugin registered it. // Therefore, we register it as not unlocked by default. return dimensionConfig != null && dimensionConfig.isEnabled() && dimensionConfig.isUnlocked(); } @Override public void addWorldLoadListener(IWorldLoadListener worldLoadListener) { Preconditions.checkNotNull(worldLoadListener, "worldLoadListener parameter cannot be null"); this.worldLoadListenerList.add(worldLoadListener); } private void notifyWorldLoadListeners(World world, Dimension worldDimension) { for (IWorldLoadListener worldLoadListener : this.worldLoadListenerList) worldLoadListener.onWorldLoad(world, worldDimension, SUPPORTED_LOAD_FLAGS); } private BlockFace getIslandFace(BlockPosition blockPosition) { //Possibilities: North / East if (blockPosition.getX() >= blockPosition.getZ()) { return -blockPosition.getX() > blockPosition.getZ() ? BlockFace.NORTH : BlockFace.EAST; } //Possibilities: South / West else { return -blockPosition.getX() > blockPosition.getZ() ? BlockFace.WEST : BlockFace.SOUTH; } } private World loadWorld(String worldName, Difficulty difficulty, Dimension dimension) { if (Bukkit.getWorld(worldName) != null) { throw new RuntimeException("The world " + worldName + " is already loaded. This can occur by one of the following reasons:\n" + "- Another plugin loaded it manually before SuperiorSkyblock.\n" + "- Your level-name property in server.properties is set to " + worldName + "."); } World world = WorldCreator.name(worldName) .type(WorldType.FLAT) .environment(dimension.getEnvironment()) .generator(WorldGenerator.getWorldGenerator(dimension)) .createWorld(); world.setDifficulty(difficulty); islandWorlds.put(dimension, world); islandWorldsToDimensions.put(world.getUID(), dimension); notifyWorldLoadListeners(world, dimension); if (Bukkit.getPluginManager().isPluginEnabled("Multiverse-Core")) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "mv import " + worldName + " normal -g " + plugin.getName()); Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "mv modify set generator " + plugin.getName() + " " + worldName); } return world; } private static BlockPosition nextPosition(BlockPosition previousPosition, int islandsHeight, int offsetX, int offsetZ) { return SBlockPosition.of(previousPosition.getX() + offsetX, islandsHeight, previousPosition.getZ() + offsetZ); } public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, WorldsProvider_Default::onSettingsUpdate); } private static void onSettingsUpdate() { WorldsProvider worldsProvider = SuperiorSkyblockPlugin.getPlugin().getProviders().getWorldsProvider(); if (!(worldsProvider instanceof WorldsProvider_Default)) return; WorldsProvider_Default worldsProviderDefault = (WorldsProvider_Default) worldsProvider; worldsProviderDefault.islandWorlds.values().forEach(SuperiorSkyblockPlugin.getPlugin().getNMSWorld()::setOceanLevel); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.island; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandCreationAlgorithm; import com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl; import com.bgsoftware.superiorskyblock.island.preview.IslandPreviews; import com.bgsoftware.superiorskyblock.island.preview.SIslandPreview; import com.bgsoftware.superiorskyblock.island.purge.IslandsPurger; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import com.bgsoftware.superiorskyblock.world.WorldBlocks; import com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; public class GridManagerImpl extends Manager implements GridManager { private static final Function ISLAND_OWNERS_MAPPER = island -> island.getOwner().getUniqueId(); private final Set pendingCreationTasks = Sets.newHashSet(); private final Set customWorlds = Sets.newHashSet(); private final LazyReference dragonBattleService = new LazyReference() { @Override protected DragonBattleService create() { return plugin.getServices().getService(DragonBattleService.class); } }; private final IslandsPurger islandsPurger; private final IslandPreviews islandPreviews; private IslandsContainer islandsContainer; private DatabaseBridge databaseBridge; private IslandCreationAlgorithm islandCreationAlgorithm; private Island spawnIsland; private BlockPosition lastIsland; @Nullable private UUID serverUUID; private BigDecimal totalWorth = BigDecimal.ZERO; private long lastTimeWorthUpdate = 0; private BigDecimal totalLevel = BigDecimal.ZERO; private long lastTimeLevelUpdate = 0; private boolean pluginDisable = false; private boolean forceSort = false; private final List pendingSortingTypes = new LinkedList<>(); private final AtomicInteger activeCalcTasks = new AtomicInteger(0); private final LazyReference>> activeSortingTasks = new LazyReference>>() { @Override protected Synchronized> create() { return Synchronized.of(new EnumerateSet<>(SortingType.values())); } }; public GridManagerImpl(SuperiorSkyblockPlugin plugin, IslandsPurger islandsPurger, IslandPreviews islandPreviews) { super(plugin); this.islandsPurger = islandsPurger; this.islandPreviews = islandPreviews; } @Override public void loadData() { if (this.islandsContainer == null) throw new RuntimeException("GridManager was not initialized correctly. Contact Ome_R regarding this!"); initializeDatabaseBridge(); if (this.islandCreationAlgorithm == null) this.islandCreationAlgorithm = DefaultIslandCreationAlgorithm.getInstance(); loadServerUuid(); this.lastIsland = SBlockPosition.of(0, 100, 0); BukkitExecutor.sync(this::updateSpawn); } public void updateSpawn() { try { this.spawnIsland = new SpawnIsland(); PluginEventsFactory.callSpawnUpdateEvent(); } catch (ManagerLoadException error) { ManagerLoadException.handle(error); } } public void syncUpgrades() { getIslands().forEach(Island::updateUpgrades); } public UUID getServerUUID() { return serverUUID; } @Override public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonus, Biome biome, String islandName) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(bonus, "bonus parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); createIsland(superiorPlayer, schematicName, bonus, biome, islandName, false); } @Override public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonus, Biome biome, String islandName, boolean offset) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(bonus, "bonus parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); createIsland(superiorPlayer, schematicName, bonus, BigDecimal.ZERO, biome, islandName, false); } @Override public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonusWorth, BigDecimal bonusLevel, Biome biome, String islandName, boolean offset) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(bonusWorth, "bonusWorth parameter cannot be null."); Preconditions.checkNotNull(bonusLevel, "bonusLevel parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); createIsland(superiorPlayer, schematicName, bonusWorth, bonusLevel, biome, islandName, offset, null); } @Override public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonusWorth, BigDecimal bonusLevel, Biome biome, String islandName, boolean offset, @Nullable BlockOffset spawnOffset) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(bonusWorth, "bonusWorth parameter cannot be null."); Preconditions.checkNotNull(bonusLevel, "bonusLevel parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); Island.Builder builder = Island.newBuilder() .setOwner(superiorPlayer) .setSchematicName(schematicName) .setName(islandName); if (!offset) { builder.setBonusWorth(bonusWorth) .setBonusLevel(bonusLevel); } createIsland(builder, biome, offset, spawnOffset); } @Override public void createIsland(Island.Builder builderParam, Biome biome, boolean offset) { Preconditions.checkNotNull(builderParam, "builder parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkArgument(builderParam instanceof IslandBuilderImpl, "Cannot create islands out of a custom builder."); createIsland(builderParam, biome, offset, null); } @Override public void createIsland(Island.Builder builderParam, Biome biome, boolean offset, @Nullable BlockOffset spawnOffset) { Preconditions.checkNotNull(builderParam, "builder parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkArgument(builderParam instanceof IslandBuilderImpl, "Cannot create islands out of a custom builder."); IslandBuilderImpl builder = (IslandBuilderImpl) builderParam; Preconditions.checkArgument(builder.owner != null, "Cannot create an island with an invalid owner."); Schematic schematic = builder.islandType == null ? null : plugin.getSchematics().getSchematic(builder.islandType); Preconditions.checkArgument(schematic != null, "Cannot create an island with an invalid schematic."); try { if (!Bukkit.isPrimaryThread()) { BukkitExecutor.sync(() -> createIslandInternalAsync(builder, biome, offset, schematic, spawnOffset)); } else { createIslandInternalAsync(builder, biome, offset, schematic, spawnOffset); } } catch (Throwable error) { Log.entering("ENTER", builder.owner.getName(), builder.islandType, biome, offset); Log.error(error, "An unexpected error occurred while creating an island:"); builder.owner.setIsland(null); Message.CREATE_ISLAND_FAILURE.send(builder.owner); } } private void createIslandInternalAsync(IslandBuilderImpl builder, Biome biome, boolean offset, Schematic schematic, @Nullable BlockOffset spawnOffset) { assert builder.owner != null; Log.debug(Debug.CREATE_ISLAND, builder.owner.getName(), builder.bonusWorth, builder.bonusLevel, builder.islandName, offset, biome, schematic.getName()); // Removing any active previews for the player. boolean updateGameMode = this.islandPreviews.endIslandPreview(builder.owner) != null; if (!PluginEventsFactory.callPreIslandCreateEvent(builder.owner, builder.islandName)) return; builder.setUniqueId(generateIslandUUID()); long startTime = System.currentTimeMillis(); pendingCreationTasks.add(builder.owner.getUniqueId()); this.islandCreationAlgorithm.createIsland(builder, this.lastIsland).whenComplete((islandCreationResult, error) -> { pendingCreationTasks.remove(builder.owner.getUniqueId()); if (error == null && islandCreationResult != null) { Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Successfully created island"); try { createIslandInternalOnSuccessCallback(builder, biome, offset, spawnOffset, schematic, updateGameMode, startTime, islandCreationResult); return; } catch (Throwable runtimeError) { error = runtimeError; } } Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Failed to create island"); Log.entering(builder.owner.getName(), builder.bonusWorth, builder.bonusLevel, builder.islandName, offset, biome, schematic.getName()); if (error != null) Log.error(error, "An unexpected error occurred while creating an island:"); builder.owner.setIsland(null); Message.CREATE_ISLAND_FAILURE.send(builder.owner); }); } private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Biome biome, boolean offset, @Nullable BlockOffset spawnOffset, Schematic schematic, boolean updateGameMode, long startTime, IslandCreationAlgorithm.IslandCreationResult islandCreationResult) { switch (islandCreationResult.getStatus()) { case NAME_OCCUPIED: builder.owner.setIsland(null); Message.ISLAND_ALREADY_EXIST.send(builder.owner); Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Island already exists"); return; case EVENT_CANCELLED: builder.owner.setIsland(null); Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Island creation event was cancelled"); return; case SUCCESS: break; default: throw new RuntimeException("Cannot handle creation status: " + islandCreationResult.getStatus()); } Island island = islandCreationResult.getIsland(); Location islandLocation = islandCreationResult.getIslandLocation(); boolean teleportPlayer = islandCreationResult.shouldTeleportPlayer(); List affectedChunks = schematic instanceof BaseSchematic ? ((BaseSchematic) schematic).getAffectedChunks() : null; Runnable onTeleportCallback = schematic instanceof BaseSchematic ? ((BaseSchematic) schematic).onTeleportCallback() : null; Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Registering new island"); this.islandsContainer.addIsland(island); setLastIslandPosition(SBlockPosition.of(islandLocation)); Dimension defaultDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); try { island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.IDLE); island.setBiome(biome, false); island.setSchematicGenerate(defaultDimension); island.setCurrentlyActive(true); if (offset) { island.setBonusWorth(island.getRawWorth().negate()); island.setBonusLevel(island.getRawLevel().negate()); } } finally { island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } IslandsDatabaseBridge.insertIsland(island, affectedChunks); Location homeLocation = schematic.adjustRotation(islandLocation); if (spawnOffset != null) homeLocation = spawnOffset.applyToLocation(homeLocation); island.setIslandHome(defaultDimension, SWorldPosition.of(homeLocation)); BukkitExecutor.sync(() -> builder.owner.runIfOnline(player -> { if (updateGameMode) player.setGameMode(GameMode.SURVIVAL); if (!teleportPlayer) { Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Do not teleport player"); Message.CREATE_ISLAND.send(builder.owner, Formatters.LOCATION_FORMATTER.format( islandLocation), System.currentTimeMillis() - startTime); } else { Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Teleporting player"); builder.owner.teleport(island, result -> { Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Teleported player. Result: " + result); Message.CREATE_ISLAND.send(builder.owner, Formatters.LOCATION_FORMATTER.format( islandLocation), System.currentTimeMillis() - startTime); if (result) { if (affectedChunks != null) { BukkitExecutor.sync(() -> { IslandUtils.resetChunksExcludedFromList(island, affectedChunks); island.setBiome(biome, true); }, 10L); } if (defaultDimension.getEnvironment() == World.Environment.THE_END) { plugin.getNMSDragonFight().awardTheEndAchievement(player); this.dragonBattleService.get().resetEnderDragonBattle(island, defaultDimension); } PluginEventsFactory.callPostIslandCreateEvent(island, builder.owner); if (onTeleportCallback != null) onTeleportCallback.run(); } }); } }), 1L); } @Override public void setIslandCreationAlgorithm(@Nullable IslandCreationAlgorithm islandCreationAlgorithm) { this.islandCreationAlgorithm = islandCreationAlgorithm != null ? islandCreationAlgorithm : DefaultIslandCreationAlgorithm.getInstance(); } @Override public IslandCreationAlgorithm getIslandCreationAlgorithm() { return Optional.ofNullable(this.islandCreationAlgorithm).orElse(DefaultIslandCreationAlgorithm.getInstance()); } @Override public boolean hasActiveCreateRequest(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return pendingCreationTasks.contains(superiorPlayer.getUniqueId()); } @Override public void startIslandPreview(SuperiorPlayer superiorPlayer, String schematicName, String islandName) { Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); startIslandPreview(superiorPlayer, plugin.getSchematics().getSchematic(schematicName), islandName); } public void startIslandPreview(SuperiorPlayer superiorPlayer, Schematic schematic, String islandName) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(schematic, "schematic parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); Location previewLocation = plugin.getSettings().getIslandPreviews().getLocations().get(schematic.getName().toLowerCase(Locale.ENGLISH)); if (previewLocation != null && previewLocation.getWorld() != null) { superiorPlayer.teleport(previewLocation, result -> { if (result) { this.islandPreviews.startIslandPreview(new SIslandPreview(superiorPlayer, previewLocation, schematic, islandName, superiorPlayer.asPlayer().getGameMode())); BukkitExecutor.ensureMain(() -> superiorPlayer.runIfOnline(player -> player.setGameMode(plugin.getSettings().getIslandPreviews().getGameMode()))); Message.ISLAND_PREVIEW_START.send(superiorPlayer, schematic.getName()); } }); } } @Override public void cancelIslandPreview(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); IslandPreview islandPreview = this.islandPreviews.endIslandPreview(superiorPlayer); if (islandPreview != null) { superiorPlayer.runIfOnline(player -> { BukkitExecutor.ensureMain(() -> superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(), teleportResult -> { if (teleportResult && superiorPlayer.isOnline()) player.setGameMode(islandPreview.getPreviousGameMode()); })); PlayerChat.remove(player); }); } } @Override public void cancelAllIslandPreviews() { if (!Bukkit.isPrimaryThread()) { BukkitExecutor.sync(this::cancelAllIslandPreviewsSync); } else { cancelAllIslandPreviewsSync(); } } private void cancelAllIslandPreviewsSync() { if (!Bukkit.isPrimaryThread()) { Log.warn("Trying to cancel all island previews asynchronous. Stack trace:"); new Exception().printStackTrace(); } this.islandPreviews.getActivePreviews().forEach(islandPreview -> { SuperiorPlayer superiorPlayer = islandPreview.getPlayer(); superiorPlayer.runIfOnline(player -> { superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); // We don't wait for the teleport to happen, as this method is called when the server is disabled. // Therefore, we can't wait for the async task to occur. player.setGameMode(GameMode.SURVIVAL); PlayerChat.remove(player); }); }); } @Override public IslandPreview getIslandPreview(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return this.islandPreviews.getIslandPreview(superiorPlayer); } @Override public void deleteIsland(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Log.debug(Debug.DELETE_ISLAND, island.getOwner().getName()); island.getAllPlayersInside().forEach(superiorPlayer -> { MenuView openedView = superiorPlayer.getOpenedView(); if (openedView != null) openedView.closeView(); island.removeEffects(superiorPlayer); superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); Message.ISLAND_GOT_DELETED_WHILE_INSIDE.send(superiorPlayer); }); this.islandsContainer.removeIsland(island); // Delete island from database IslandsDatabaseBridge.deleteIsland(island); for (Dimension dimension : Dimension.values()) { if (dimension.getEnvironment() == World.Environment.THE_END) this.dragonBattleService.get().stopEnderDragonBattle(island, dimension); } } @Override public Island getIsland(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return superiorPlayer.getIsland(); } @Override public Island getIsland(int index, SortingType sortingType) { Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); return this.islandsContainer.getIslandAtPosition(index, sortingType); } @Override public int getIslandPosition(Island island, SortingType sortingType) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); return this.islandsContainer.getIslandPosition(island, sortingType); } @Override public Island getIsland(UUID uuid) { Preconditions.checkNotNull(uuid, "uuid parameter cannot be null."); SuperiorPlayer superiorPlayer = plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(uuid); return superiorPlayer == null ? null : getIsland(superiorPlayer); } @Override public Island getIslandByUUID(UUID uuid) { Preconditions.checkNotNull(uuid, "uuid parameter cannot be null."); return this.islandsContainer.getIslandByUUID(uuid); } @Override public Island getIsland(String islandName) { Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); return this.islandsContainer.getIslandByName(islandName); } @Override public Island getIslandAt(@Nullable Location location) { if (location == null) return null; World world = location.getWorld(); if (world == null) return null; if (spawnIsland != null && spawnIsland.isInside(location)) return spawnIsland; return this.islandsContainer.getIslandAt(location); } @Override @Deprecated public Island getIslandAt(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk argument cannot be null"); if (!plugin.getGrid().isIslandsWorld(chunk.getWorld())) return null; Location cornerLocation; try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { cornerLocation = WorldBlocks.getChunkBlock(chunkPosition, 0, 100, 0); } Island island; // Checks corner at 0, y, 0 if ((island = getIslandAt(cornerLocation)) != null) return island; // Checks corner at 15, y, 0 cornerLocation.add(15, 0, 0); if ((island = getIslandAt(cornerLocation)) != null) return island; // Checks corner at 15, y, 15 cornerLocation.add(0, 0, 15); if ((island = getIslandAt(cornerLocation)) != null) return island; // Checks corner at 0, y, 15 cornerLocation.add(-15, 0, 0); if ((island = getIslandAt(cornerLocation)) != null) return island; return null; } @Override public List getIslandsAt(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk argument cannot be null"); if (!plugin.getGrid().isIslandsWorld(chunk.getWorld())) return Collections.emptyList(); Set islands = new LinkedHashSet<>(); Location cornerLocation; try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { cornerLocation = WorldBlocks.getChunkBlock(chunkPosition, 0, 100, 0); } Island island; // Checks corner at 0, y, 0 if ((island = getIslandAt(cornerLocation)) != null) islands.add(island); // Checks corner at 15, y, 0 cornerLocation.add(15, 0, 0); if ((island = getIslandAt(cornerLocation)) != null) islands.add(island); // Checks corner at 15, y, 15 cornerLocation.add(0, 0, 15); if ((island = getIslandAt(cornerLocation)) != null) islands.add(island); // Checks corner at 0, y, 15 cornerLocation.add(-15, 0, 0); if ((island = getIslandAt(cornerLocation)) != null) islands.add(island); return islands.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new LinkedList<>(islands)); } @Override public void transferIsland(UUID oldOwner, UUID newOwner) { // Do nothing. } @Override public int getSize() { return this.islandsContainer.getIslandsAmount(); } @Override public void sortIslands(SortingType sortingType) { Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); sortIslands(sortingType, null); } public void forceSortIslands(SortingType sortingType) { Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); setForceSort(true); sortIslands(sortingType, null); } @Override public void sortIslands(SortingType sortingType, @Nullable Runnable onFinish) { Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); Log.debug(Debug.SORT_ISLANDS, sortingType.getName()); boolean isSortedAlready = activeSortingTasks.get().readAndGet( activeSortingTasks -> activeSortingTasks.contains(sortingType)); if (isSortedAlready) { if (onFinish != null) onFinish.run(); forceSort = false; return; } activeSortingTasks.get().write(activeSortingTasks -> activeSortingTasks.add(sortingType)); this.islandsContainer.sortIslands(sortingType, forceSort, () -> { plugin.getMenus().refreshTopIslands(sortingType); activeSortingTasks.get().write(activeSortingTasks -> activeSortingTasks.remove(sortingType)); if (onFinish != null) onFinish.run(); }); forceSort = false; } public void setForceSort(boolean forceSort) { this.forceSort = forceSort; } @Override public Island getSpawnIsland() { if (spawnIsland == null) updateSpawn(); return spawnIsland; } @Override public World getIslandsWorld(Island island, Dimension dimension) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); if (island.isSpawn()) { if (island instanceof SpawnIsland) return ((SpawnIsland) island).getSpawnWorld(); return island.getIslandHome(dimension).getWorld(); } return plugin.getProviders().getWorldsProvider().getIslandsWorld(island, dimension); } @Override public Dimension getIslandsWorldDimension(World world) { Preconditions.checkNotNull(world, "world parameter cannot be null."); if (!isIslandsWorld(world)) return null; if (customWorlds.contains(world.getUID())) return Dimension.getByName(world.getName().toUpperCase(Locale.ENGLISH)); return plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); } @Override public WorldInfo getIslandsWorldInfo(Island island, Dimension dimension) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); if (island.isSpawn()) { if (island instanceof SpawnIsland) return ((SpawnIsland) island).getSpawnWorldInfo(); return WorldInfo.of(island.getIslandHome(dimension).getWorld()); } WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); if (worldsProvider instanceof LazyWorldsProvider) return ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(island, dimension); World world = this.getIslandsWorld(island, dimension); return world == null ? null : WorldInfo.of(world); } @Nullable @Override public WorldInfo getIslandsWorldInfo(Island island, String worldName) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(worldName, "worldName parameter cannot be null."); if (island.isSpawn()) { if (island instanceof SpawnIsland) return ((SpawnIsland) island).getSpawnWorldInfo(); return WorldInfo.of(island.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getWorld()); } WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); if (worldsProvider instanceof LazyWorldsProvider) return ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(island, worldName); World world = Bukkit.getWorld(worldName); return world == null || !isIslandsWorld(world) ? null : WorldInfo.of(world); } @Override public boolean isIslandsWorld(World world) { Preconditions.checkNotNull(world, "world parameter cannot be null."); return customWorlds.contains(world.getUID()) || plugin.getProviders().getWorldsProvider().isIslandsWorld(world); } @Override public void registerIslandWorld(World world) { Preconditions.checkNotNull(world, "world parameter cannot be null."); String dimensionName = world.getName().toUpperCase(Locale.ENGLISH); try { Dimension.register(dimensionName, world.getEnvironment()); } catch (Exception error) { throw new IllegalArgumentException("Dimension with the name " + dimensionName + " already exists."); } customWorlds.add(world.getUID()); } @Override public List getRegisteredWorlds() { return new SequentialListBuilder().build(customWorlds, Bukkit::getWorld); } @Override @Deprecated public List getAllIslands(SortingType sortingType) { return new SequentialListBuilder() .build(getIslands(sortingType), ISLAND_OWNERS_MAPPER); } @Override public List getIslands() { return this.islandsContainer.getIslandsUnsorted(); } @Override public List getIslands(SortingType sortingType) { Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); return this.islandsContainer.getSortedIslands(sortingType); } @Override @Deprecated public int getBlockAmount(Block block) { Preconditions.checkNotNull(block, "block parameter cannot be null."); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return getBlockAmount(block.getLocation(wrapper.getHandle())); } } @Override @Deprecated public int getBlockAmount(Location location) { return plugin.getStackedBlocks().getStackedBlockAmount(location); } @Override @Deprecated public void setBlockAmount(Block block, int amount) { plugin.getStackedBlocks().setStackedBlock(block, amount); } @Override public List getStackedBlocks() { return new SequentialListBuilder().build(plugin.getStackedBlocks().getStackedBlocks().keySet()); } @Override public void calcAllIslands() { calcAllIslands(null); } @Override public void calcAllIslands(Runnable callback) { Log.debug(Debug.CALCULATE_ALL_ISLANDS); List islands = new ArrayList<>(); { for (Island island : this.islandsContainer.getIslandsUnsorted()) { if (!island.isBeingRecalculated()) islands.add(island); } } for (int i = 0; i < islands.size(); i++) { islands.get(i).calcIslandWorth(null, i + 1 < islands.size() ? null : callback); } } public void startCalcTask() { this.activeCalcTasks.incrementAndGet(); } public boolean stopCalcTask() { int activeCalcTasks = this.activeCalcTasks.decrementAndGet(); if (activeCalcTasks < 0) throw new IllegalStateException(); return activeCalcTasks == 0; } @Override public void addIslandToPurge(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(island.getOwner(), "island's owner cannot be null."); Log.debug(Debug.PURGE_ISLAND, island.getOwner().getName()); this.islandsPurger.scheduleIslandPurge(island); } @Override public void removeIslandFromPurge(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(island.getOwner(), "island's owner cannot be null."); Log.debug(Debug.UNPURGE_ISLAND, island.getOwner().getName()); this.islandsPurger.unscheduleIslandPurge(island); } @Override public boolean isIslandPurge(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null."); Preconditions.checkNotNull(island.getOwner(), "island's owner cannot be null."); return this.islandsPurger.isIslandPurgeScheduled(island); } @Override public List getIslandsToPurge() { return this.islandsPurger.getScheduledPurgedIslands(); } @Override public void registerSortingType(SortingType sortingType) { Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); Log.debug(Debug.REGISTER_SORTING_TYPE, sortingType.getName()); if (this.islandsContainer == null) { pendingSortingTypes.add(sortingType); } else { this.islandsContainer.addSortingType(sortingType, true); } } @Override public BigDecimal getTotalWorth() { long currentTime = System.currentTimeMillis(); if (currentTime - lastTimeWorthUpdate > 60000) { lastTimeWorthUpdate = currentTime; totalWorth = BigDecimal.ZERO; for (Island island : getIslands()) totalWorth = totalWorth.add(island.getWorth()); } return totalWorth; } @Override public BigDecimal getTotalLevel() { long currentTime = System.currentTimeMillis(); if (currentTime - lastTimeLevelUpdate > 60000) { lastTimeLevelUpdate = currentTime; totalLevel = BigDecimal.ZERO; for (Island island : getIslands()) totalLevel = totalLevel.add(island.getIslandLevel()); } return totalLevel; } @Override @Deprecated public Location getLastIslandLocation() { return lastIsland.toLocation((World) null); } @Override @Deprecated public void setLastIslandLocation(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null"); setLastIslandPosition(SBlockPosition.of(location)); } @Override public BlockPosition getLastIslandPosition() { return this.lastIsland; } @Override public void setLastIslandPosition(BlockPosition lastIsland) { Preconditions.checkNotNull(lastIsland, "lastIsland parameter cannot be null"); Log.debug(Debug.SET_LAST_ISLAND, lastIsland); if (Objects.equals(this.lastIsland, lastIsland)) return; this.lastIsland = lastIsland; GridDatabaseBridge.saveLastIsland(this, lastIsland); } @Override public IslandsContainer getIslandsContainer() { return this.islandsContainer; } @Override public void setIslandsContainer(IslandsContainer islandsContainer) { Preconditions.checkNotNull(islandsContainer, "islandsContainer parameter cannot be null"); this.islandsContainer = islandsContainer; pendingSortingTypes.forEach(sortingType -> islandsContainer.addSortingType(sortingType, false)); pendingSortingTypes.clear(); } @Override public DatabaseBridge getDatabaseBridge() { return databaseBridge; } public UUID generateIslandUUID() { UUID uuid; do { uuid = UUID.randomUUID(); } while (getIslandByUUID(uuid) != null || plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(uuid) != null); return uuid; } public void disablePlugin() { this.pluginDisable = true; cancelAllIslandPreviews(); } public boolean wasPluginDisabled() { return this.pluginDisable; } public void loadGrid(DatabaseResult resultSet) { resultSet.getString("last_island").map(Serializers.BLOCK_POSITION_SERIALIZER::deserialize) .ifPresent(lastIsland -> this.lastIsland = lastIsland); int maxIslandSize = resultSet.getInt("max_island_size").orElse(plugin.getSettings().getMaxIslandSize()); String world = resultSet.getString("world").orElse(plugin.getSettings().getWorlds().getDefaultWorldName()); try { if (plugin.getSettings().getMaxIslandSize() != maxIslandSize) { Log.warn("You have changed the max-island-size value without deleting database."); Log.warn("Restoring it to the old value..."); plugin.getSettings().updateValue("max-island-size", maxIslandSize); } if (!plugin.getSettings().getWorlds().getDefaultWorldName().equals(world)) { Log.warn("You have changed the island-world value without deleting database."); Log.warn("Restoring it to the old value..."); plugin.getSettings().updateValue("worlds.normal-world", world); } } catch (IOException error) { Log.error(error, "An unexpected error occurred while loading grid:"); Bukkit.shutdown(); } } public void saveIslands() { List onlineIslands = new SequentialListBuilder() .filter(Objects::nonNull) .build(Bukkit.getOnlinePlayers(), player -> plugin.getPlayers().getSuperiorPlayer(player).getIsland()); List modifiedIslands = new SequentialListBuilder() .filter(IslandsDatabaseBridge::isModified) .build(getIslands()); if (!onlineIslands.isEmpty()) onlineIslands.forEach(Island::updateLastTime); if (!modifiedIslands.isEmpty()) modifiedIslands.forEach(IslandsDatabaseBridge::executeFutureSaves); getIslands().forEach(Island::removeEffects); } private void initializeDatabaseBridge() { databaseBridge = plugin.getFactory().createDatabaseBridge(this); databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } private void loadServerUuid() { File bStatsFile = new File(plugin.getDataFolder().getParentFile(), "bStats/config.yml"); if (!bStatsFile.exists()) return; YamlConfiguration config = YamlConfiguration.loadConfiguration(bStatsFile); if (!config.isString("serverUuid")) return; try { this.serverUUID = UUID.fromString(config.getString("serverUuid")); } catch (Exception ignored) { } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java ================================================ package com.bgsoftware.superiorskyblock.island; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import javax.annotation.Nullable; import java.util.Collections; import java.util.Locale; public class IslandNames { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private IslandNames() { } public static boolean isValidName(SuperiorPlayer superiorPlayer, @Nullable Island currentIsland, String islandName) { return isValidName(superiorPlayer.asPlayer(), currentIsland, islandName); } public static boolean isValidName(CommandSender sender, Island currentIsland, String islandName) { String strippedName = Formatters.STRIP_COLOR_FORMATTER.format(islandName); int maxLength = plugin.getSettings().getIslandNames().getMaxLength(); int minLength = plugin.getSettings().getIslandNames().getMinLength(); if (strippedName.length() > maxLength) { Message.NAME_TOO_LONG.send(sender, maxLength); return false; } if (strippedName.length() < minLength) { Message.NAME_TOO_SHORT.send(sender, minLength); return false; } if (plugin.getSettings().getIslandNames().isPreventPlayerNames() && plugin.getPlayers().getSuperiorPlayer(strippedName) != null) { Message.NAME_SAME_AS_PLAYER.send(sender); return false; } String lookupName = islandName.toLowerCase(Locale.ENGLISH); if (plugin.getSettings().getIslandNames().getFilteredNames().stream().anyMatch(lookupName::contains)) { Message.NAME_BLACKLISTED.send(sender); return false; } if (currentIsland != null) { String formattedName = Formatters.COLOR_FORMATTER.format(islandName); if (currentIsland.getFormattedName().equalsIgnoreCase(formattedName)) { Message.SAME_NAME_CHANGE.send(sender); return false; } } Island islandWithName = plugin.getGrid().getIsland(strippedName); if (islandWithName != null && islandWithName != currentIsland) { Message.ISLAND_ALREADY_EXIST.send(sender); return false; } return true; } public static void announceChange(Island island, Message message, Object... args) { if (plugin.getSettings().getIslandNames().isAnnounceChangeToAll()) for (Player player : Bukkit.getOnlinePlayers()) message.send(player, args); else IslandUtils.sendMessage(island, message, Collections.emptyList(), args); } public static String getNameForDatabase(Island island) { return island.getFormattedName().replace(ChatColor.COLOR_CHAR, '&'); } public static String getNameForLookup(String name) { return Formatters.STRIP_COLOR_FORMATTER.format(name).toLowerCase(Locale.ENGLISH); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java ================================================ package com.bgsoftware.superiorskyblock.island; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.SynchronizedTasks; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public class IslandUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final EnumerateMap DEFAULT_WORLD_BIOMES = new EnumerateMap<>(Dimension.values()); private static Biome getDefaultBiomeForEnvironment(World.Environment environment) { switch (environment) { case NORMAL: return Biome.PLAINS; case NETHER: return Optional.ofNullable(EnumHelper.getEnum(Biome.class, "NETHER_WASTES", "NETHER", "HELL")) .orElseThrow(IllegalArgumentException::new); case THE_END: return Optional.ofNullable(EnumHelper.getEnum(Biome.class, "THE_END", "SKY")) .orElseThrow(IllegalArgumentException::new); } throw new IllegalArgumentException(); } static { for (Dimension dimension : Dimension.values()) { Biome biome = Optional.ofNullable(plugin.getSettings().getWorlds().getDimensionConfig(dimension)) .map(config -> plugin.getNMSAlgorithms().getBiome(config.getBiome())) .orElseGet(() -> getDefaultBiomeForEnvironment(dimension.getEnvironment())); DEFAULT_WORLD_BIOMES.put(dimension, biome); } } private IslandUtils() { } public static List getChunkCoords(Island island, WorldInfo worldInfo, @IslandChunkFlags int flags) { List chunkCoords = new LinkedList<>(); boolean onlyProtected = (flags & IslandChunkFlags.ONLY_PROTECTED) != 0; boolean noEmptyChunks = (flags & IslandChunkFlags.NO_EMPTY_CHUNKS) != 0; BlockPosition min = onlyProtected ? island.getMinimumProtectedPosition() : island.getMinimumPosition(); BlockPosition max = onlyProtected ? island.getMaximumProtectedPosition() : island.getMaximumPosition(); for (int x = min.getX() >> 4; x <= max.getX() >> 4; x++) { for (int z = min.getZ() >> 4; z <= max.getZ() >> 4; z++) { if (!noEmptyChunks || island.isChunkDirty(worldInfo.getName(), x, z)) { chunkCoords.add(ChunkPosition.of(worldInfo, x, z, false)); } } } return chunkCoords; } public static Map> getChunkCoords(Island island, @IslandChunkFlags int flags) { Map> chunkCoords = new ArrayMap<>(); for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); List chunkPositions = getChunkCoords(island, worldInfo, flags); if (!chunkPositions.isEmpty()) chunkCoords.put(worldInfo, chunkPositions); } } for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { WorldInfo worldInfo = WorldInfo.of(registeredWorld); List chunkPositions = getChunkCoords(island, worldInfo, flags); if (!chunkPositions.isEmpty()) chunkCoords.put(worldInfo, chunkPositions); } return chunkCoords; } public static List> getAllChunksAsync(Island island, WorldInfo worldInfo, @IslandChunkFlags int flags, ChunkLoadReason chunkLoadReason, Consumer onChunkLoad) { return new SequentialListBuilder>() .mutable() .build(IslandUtils.getChunkCoords(island, worldInfo, flags), chunkPosition -> ChunksProvider.loadChunk(chunkPosition, chunkLoadReason, onChunkLoad)); } public static List> getAllChunksAsync(Island island, @IslandChunkFlags int flags, ChunkLoadReason chunkLoadReason, Consumer onChunkLoad) { List> chunkCoords = new LinkedList<>(); for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); chunkCoords.addAll(getAllChunksAsync(island, worldInfo, flags, chunkLoadReason, onChunkLoad)); } } for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { chunkCoords.addAll(getAllChunksAsync(island, WorldInfo.of(registeredWorld), flags, chunkLoadReason, onChunkLoad)); } return chunkCoords; } public static void updateIslandFly(Island island, SuperiorPlayer superiorPlayer) { superiorPlayer.runIfOnline(player -> { if (!player.getAllowFlight() && superiorPlayer.hasIslandFlyEnabled() && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { player.setAllowFlight(true); player.setFlying(true); Message.ISLAND_FLY_ENABLED.send(player); } else if (player.getAllowFlight() && !island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { player.setAllowFlight(false); player.setFlying(false); Message.ISLAND_FLY_DISABLED.send(player); } }); } public static void updateTradingMenus(Island island, SuperiorPlayer superiorPlayer) { superiorPlayer.runIfOnline(player -> { Inventory openInventory = player.getOpenInventory().getTopInventory(); if (openInventory != null && openInventory.getType() == InventoryType.MERCHANT && !island.hasPermission(superiorPlayer, IslandPrivileges.VILLAGER_TRADING)) player.closeInventory(); }); } public static void resetChunksExcludedFromList(Island island, Collection excludedChunkPositions) { Map> chunksToDelete = IslandUtils.getChunkCoords(island, 0); chunksToDelete.values().forEach(chunkPositions -> { List clonedChunkPositions = new LinkedList<>(chunkPositions); clonedChunkPositions.removeAll(excludedChunkPositions); deleteChunks(island, clonedChunkPositions, null); }); } public static void sendMessage(Island island, Message message, List ignoredMembers, Object... args) { for (SuperiorPlayer islandMember : island.getIslandMembers(true)) { if (!ignoredMembers.contains(islandMember.getUniqueId())) message.send(islandMember, args); } } public static double getGeneratorPercentageDecimal(Island island, Key key, Dimension dimension) { int totalAmount = island.getGeneratorTotalAmount(dimension); return totalAmount == 0 ? 0 : (island.getGeneratorAmount(key, dimension) * 100D) / totalAmount; } public static boolean checkTransferRestrictions(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) { if (!superiorPlayer.getPlayerRole().isLastRole()) { Message.NO_TRANSFER_PERMISSION.send(superiorPlayer); return false; } if (!island.isMember(targetPlayer)) { Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer); return false; } if (island.getOwner().getUniqueId().equals(targetPlayer.getUniqueId())) { Message.TRANSFER_ALREADY_LEADER.send(superiorPlayer); return false; } return true; } public static void handleTransferIsland(SuperiorPlayer caller, Island island, SuperiorPlayer target) { if (!PluginEventsFactory.callIslandTransferEvent(island, caller, target)) return; island.transferIsland(target); IslandUtils.sendMessage(island, Message.TRANSFER_BROADCAST, Collections.emptyList(), target.getName()); } public static boolean checkKickRestrictions(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) { if (!island.isMember(targetPlayer)) { Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer); return false; } if (!targetPlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole())) { Message.KICK_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer); return false; } return true; } public static void handleLeaveIsland(SuperiorPlayer superiorPlayer, Island island) { if (!PluginEventsFactory.callIslandQuitEvent(island, superiorPlayer)) return; island.removeMember(superiorPlayer, MemberRemoveReason.LEAVE); IslandUtils.sendMessage(island, Message.LEAVE_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); Message.LEFT_ISLAND.send(superiorPlayer); } public static void handleKickPlayer(SuperiorPlayer caller, Island island, SuperiorPlayer target) { handleKickPlayer(caller, caller.getName(), island, target); } public static void handleKickPlayer(SuperiorPlayer caller, String callerName, Island island, SuperiorPlayer target) { if (!PluginEventsFactory.callIslandKickEvent(island, caller, target)) return; island.removeMember(target, MemberRemoveReason.KICK); IslandUtils.sendMessage(island, Message.KICK_ANNOUNCEMENT, Collections.emptyList(), target.getName(), callerName); Message.GOT_KICKED.send(target, callerName); } public static boolean checkBanRestrictions(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) { Island playerIsland = superiorPlayer.getIsland(); if (playerIsland != null && playerIsland.isMember(targetPlayer) && !targetPlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole())) { Message.BAN_PLAYERS_WITH_LOWER_ROLE.send(superiorPlayer); return false; } if (island.isBanned(targetPlayer)) { Message.PLAYER_ALREADY_BANNED.send(superiorPlayer); return false; } return true; } public static void handleBanPlayer(SuperiorPlayer caller, Island island, SuperiorPlayer target) { if (!PluginEventsFactory.callIslandBanEvent(island, caller, target)) return; island.banMember(target, caller); IslandUtils.sendMessage(island, Message.BAN_ANNOUNCEMENT, Collections.emptyList(), target.getName(), caller.getName()); Message.GOT_BANNED.send(target, island.getOwner().getName()); } public static void deleteChunks(Island island, List chunkPositions, Runnable onFinish) { SynchronizedTasks synchronizedTasks = new SynchronizedTasks(1, onFinish); chunkPositions.forEach(chunkPosition -> { plugin.getStackedBlocks().removeStackedBlocks(chunkPosition); PluginEventsFactory.callIslandChunkResetEvent(island, chunkPosition); }); plugin.getNMSChunks().deleteChunks(island, chunkPositions, synchronizedTasks::notifyTaskComplete); synchronizedTasks.waitAllAsync(); } public static boolean isValidRoleForLimit(PlayerRole playerRole) { return playerRole.isRoleLadder() && !playerRole.isFirstRole() && !playerRole.isLastRole(); } public static boolean isWarpNameLengthValid(String warpName) { return warpName.length() <= getMaxWarpNameLength(); } public static int getMaxWarpNameLength() { return 255; } public static boolean handleBorderColorUpdate(SuperiorPlayer superiorPlayer, BorderColor borderColor) { if (!superiorPlayer.hasWorldBorderEnabled()) { if (!PluginEventsFactory.callPlayerToggleBorderEvent(superiorPlayer)) return false; superiorPlayer.toggleWorldBorder(); } if (!PluginEventsFactory.callPlayerChangeBorderColorEvent(superiorPlayer, borderColor)) return false; superiorPlayer.setBorderColor(borderColor); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { plugin.getNMSWorld().setWorldBorder(superiorPlayer, plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle()))); } Message.BORDER_PLAYER_COLOR_UPDATED.send(superiorPlayer, Formatters.BORDER_COLOR_FORMATTER.format(borderColor, superiorPlayer.getUserLocale())); return true; } public static Biome getDefaultWorldBiome(Dimension dimension) { return Objects.requireNonNull(DEFAULT_WORLD_BIOMES.get(dimension)); } public static List getDefaultWorldBiomes() { return new SequentialListBuilder().build(DEFAULT_WORLD_BIOMES.values()); } public static void handleIslandChat(Island island, SuperiorPlayer superiorPlayer, String message) { PluginEvent event = PluginEventsFactory.callIslandChatEvent(island, superiorPlayer, superiorPlayer.hasPermissionWithoutOP("superior.chat.color") ? Formatters.COLOR_FORMATTER.format(message) : message); if (event.isCancelled()) return; IslandUtils.sendMessage(island, Message.TEAM_CHAT_FORMAT, Collections.emptyList(), superiorPlayer.getPlayerRole(), superiorPlayer.getName(), event.getArgs().message); Message.SPY_TEAM_CHAT_FORMAT.send(Bukkit.getConsoleSender(), superiorPlayer.getPlayerRole().getDisplayName(), superiorPlayer.getName(), event.getArgs().message); for (Player _onlinePlayer : Bukkit.getOnlinePlayers()) { SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(_onlinePlayer); if (onlinePlayer.hasAdminSpyEnabled()) Message.SPY_TEAM_CHAT_FORMAT.send(onlinePlayer, superiorPlayer.getPlayerRole().getDisplayName(), superiorPlayer.getName(), event.getArgs().message); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java ================================================ package com.bgsoftware.superiorskyblock.island; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.annotations.Size; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.BlockChangeResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PermissionNode; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.IslandArea; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.collections.Location2ObjectMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.core.threads.SynchronizedTasks; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl; import com.bgsoftware.superiorskyblock.island.cache.IslandCacheImpl; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.island.privilege.PrivilegeNodeAbstract; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.island.upgrade.DefaultUpgradeLevel; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import com.bgsoftware.superiorskyblock.island.upgrade.container.IslandUpgrades; import com.bgsoftware.superiorskyblock.island.warp.SIslandWarp; import com.bgsoftware.superiorskyblock.island.warp.SWarpCategory; import com.bgsoftware.superiorskyblock.mission.MissionData; import com.bgsoftware.superiorskyblock.mission.MissionReference; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects; import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.bgsoftware.superiorskyblock.world.GeneratorType; import com.bgsoftware.superiorskyblock.world.WorldBlocks; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.WeatherType; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitTask; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.UUID; import java.util.WeakHashMap; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; public class SIsland implements Island { private static final UUID CONSOLE_UUID = new UUID(0, 0); private static final UUID[] EMPTY_IGNORED_MEMBERS = new UUID[0]; private static final Object[] EMPTY_MESSAGE_ARGS = new Object[0]; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; private static EnumerateSet DEFAULT_FLAGS_CACHE; private final DatabaseBridge databaseBridge; private final IslandBank islandBank; private final IslandCalculationAlgorithm calculationAlgorithm; private final IslandBlocksTrackerAlgorithm blocksTracker; private final IslandEntitiesTrackerAlgorithm entitiesTracker; private final Synchronized bankInterestTask = Synchronized.of(null); private final Synchronized> activeTasks = Synchronized.of(Collections.newSetFromMap(new WeakHashMap<>())); private final DirtyChunksContainer dirtyChunksContainer; private final LazyReference islandCache = new LazyReference() { @Override protected IslandCache create() { return new IslandCacheImpl(SIsland.this); } }; private final IslandArea entireArea = new IslandArea(); private final IslandArea protectedArea = new IslandArea(); /* * Island Identifiers */ private final UUID uuid; private final BlockPosition center; private final long creationTime; @Nullable private final String schematicName; /* * Island Upgrade Values */ private final Synchronized islandSize = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); private final Synchronized warpsLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); private final Synchronized teamLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); private final Synchronized coopLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); private final Synchronized cropGrowth = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); private final Synchronized spawnerRates = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); private final Synchronized mobDrops = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); private final Synchronized> bankLimit = Synchronized.of(Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE)); private final Synchronized> roleLimits = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap()); private final Synchronized>> cobbleGeneratorValues = Synchronized.of(new EnumerateMap<>(Dimension.values())); private final Map islandEffects = new ConcurrentHashMap<>(); private final KeyMap blockLimits = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); private final KeyMap entityLimits = KeyMaps.createConcurrentHashMap(KeyIndicator.ENTITY_TYPE); /* * Island Player-Trackers */ private final Synchronized> members = Synchronized.of(new TreeSet<>(SortingComparators.PLAYER_NAMES_COMPARATOR)); private final Synchronized> playersInside = Synchronized.of(new TreeSet<>(SortingComparators.PLAYER_NAMES_COMPARATOR)); private final Synchronized> uniqueVisitors = Synchronized.of(new TreeSet<>(SortingComparators.PAIRED_PLAYERS_NAMES_COMPARATOR)); private final Set bannedPlayers = Sets.newConcurrentHashSet(); private final Set coopPlayers = Sets.newConcurrentHashSet(); private final Set invitedPlayers = Sets.newConcurrentHashSet(); private final Map playerPermissions = new ConcurrentHashMap<>(); private final Map ratings = new ConcurrentHashMap<>(); /* * Island Warps */ private final Map warpsByName = new ConcurrentHashMap<>(); private final Synchronized> warpsByLocation = Synchronized.of(new Location2ObjectMap<>()); private final Map warpCategories = new ConcurrentHashMap<>(); /* * General Settings */ private final Synchronized> islandHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); private final Synchronized> visitorHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); private final Map rolePermissions = new ConcurrentHashMap<>(); private final Map islandFlags = new ConcurrentHashMap<>(); private final IslandUpgrades upgrades = new IslandUpgrades(); private final AtomicReference islandWorth = new AtomicReference<>(BigDecimal.ZERO); private final AtomicReference islandLevel = new AtomicReference<>(BigDecimal.ZERO); private final AtomicReference bonusWorth = new AtomicReference<>(BigDecimal.ZERO); private final AtomicReference bonusLevel = new AtomicReference<>(BigDecimal.ZERO); private final Map completedMissions = new ConcurrentHashMap<>(); private final Synchronized islandChests = Synchronized.of(createDefaultIslandChests()); private final Synchronized> biomeGetterTask = Synchronized.of(null); private final Synchronized> generatedSchematics = Synchronized.of(new EnumerateSet<>(Dimension.values())); private final Synchronized> unlockedWorlds = Synchronized.of(new EnumerateSet<>(Dimension.values())); @Nullable private PersistentDataContainer persistentDataContainer; /* * Island Flags */ private volatile boolean beingRecalculated = false; private final AtomicReference currentTotalBlockCounts = new AtomicReference<>(BigInteger.ZERO); private volatile BigInteger lastSavedBlockCounts = BigInteger.ZERO; private SuperiorPlayer owner; private String creationTimeDate; /* * Island Time-Trackers */ private volatile long lastTimeUpdate; private volatile boolean currentlyActive = false; private volatile long lastInterest; private volatile long lastUpgradeTime = -1L; private volatile boolean giveInterestFailed = false; private volatile String discord; private volatile String paypal; private volatile boolean isLocked; private volatile boolean isTopIslandsIgnored; private volatile String formattedName; private volatile String strippedName; private volatile String description; private volatile Biome biome = null; public SIsland(IslandBuilderImpl builder) { this.uuid = builder.uuid; this.owner = builder.owner; if (this.owner != null) { this.owner.setPlayerRole(SPlayerRole.lastRole()); this.owner.setIsland(this); } this.center = builder.center; this.creationTime = builder.creationTime; setNameInternal(builder.islandName); this.schematicName = builder.islandType; this.discord = builder.discord; this.paypal = builder.paypal; this.bonusWorth.set(builder.bonusWorth); this.bonusLevel.set(builder.bonusLevel); this.isLocked = builder.isLocked; this.isTopIslandsIgnored = builder.isIgnored; this.description = builder.description; this.generatedSchematics.set(builder.generatedSchematics); this.unlockedWorlds.set(builder.unlockedWorlds); this.lastTimeUpdate = builder.lastTimeUpdated; this.islandHomes.write(islandHomes -> islandHomes.putAll(builder.islandHomes)); this.members.write(members -> { members.addAll(builder.members); members.forEach(member -> member.setIsland(this)); }); this.bannedPlayers.addAll(builder.bannedPlayers); this.playerPermissions.putAll(builder.playerPermissions); this.playerPermissions.values().forEach(permissionNode -> permissionNode.setIsland(this)); this.rolePermissions.putAll(builder.rolePermissions); this.upgrades.setUpgradeLevels(builder.upgrades); this.blockLimits.putAll(builder.blockLimits); this.ratings.putAll(builder.ratings); this.completedMissions.putAll(builder.completedMissions); this.islandFlags.putAll(builder.islandFlags); this.cobbleGeneratorValues.write(cobbleGeneratorValues -> cobbleGeneratorValues.putAll(builder.cobbleGeneratorValues)); this.uniqueVisitors.write(uniqueVisitors -> uniqueVisitors.addAll(builder.uniqueVisitors)); this.entityLimits.putAll(builder.entityLimits); this.islandEffects.putAll(builder.islandEffects); IslandChest[] islandChests = new IslandChest[builder.islandChests.size()]; for (int index = 0; index < islandChests.length; ++index) { islandChests[index] = SIslandChest.createChest(this, index, builder.islandChests.get(index)); } this.islandChests.set(islandChests); this.roleLimits.write(roleLimits -> roleLimits.putAll(builder.roleLimits)); this.visitorHomes.set(builder.visitorHomes); this.islandSize.set(builder.islandSize); this.teamLimit.set(builder.teamLimit); this.warpsLimit.set(builder.warpsLimit); this.cropGrowth.set(builder.cropGrowth); this.spawnerRates.set(builder.spawnerRates); this.mobDrops.set(builder.mobDrops); this.coopLimit.set(builder.coopLimit); this.bankLimit.set(builder.bankLimit); this.lastInterest = builder.lastInterestTime; this.databaseBridge = plugin.getFactory().createDatabaseBridge(this); this.islandBank = plugin.getFactory().createIslandBank(this, this::hasGiveInterestFailed); this.calculationAlgorithm = plugin.getFactory().createIslandCalculationAlgorithm(this); this.blocksTracker = plugin.getFactory().createIslandBlocksTrackerAlgorithm(this); this.entitiesTracker = plugin.getFactory().createIslandEntitiesTrackerAlgorithm(this); this.dirtyChunksContainer = new DirtyChunksContainer(this); // We make sure the default world is always marked as generated. if (!wasSchematicGenerated(plugin.getSettings().getWorlds().getDefaultWorldDimension())) { setSchematicGenerate(plugin.getSettings().getWorlds().getDefaultWorldDimension()); } builder.dirtyChunks.forEach(dirtyChunk -> { try { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dirtyChunk.getWorldName()); if (worldInfo != null) { try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, dirtyChunk.getX(), dirtyChunk.getZ())) { this.dirtyChunksContainer.markDirty(chunkPosition, false); } } } catch (IllegalStateException ignored) { } }); if (!builder.blockCounts.isEmpty()) { plugin.getProviders().addPricesLoadCallback(() -> { accessBlocksTracker(true, unused -> { builder.blockCounts.forEach((block, count) -> handleBlockPlaceInternal(block, count, 0)); return null; }); this.lastSavedBlockCounts = this.currentTotalBlockCounts.get(); }); } builder.warpCategories.forEach(warpCategoryRecord -> { loadWarpCategory(warpCategoryRecord.name, warpCategoryRecord.slot, warpCategoryRecord.icon); }); builder.warps.forEach(warpRecord -> { WarpCategory warpCategory = null; if (!warpRecord.category.isEmpty()) warpCategory = getWarpCategory(warpRecord.category); WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, warpRecord.worldName); loadIslandWarp(warpRecord.name, worldInfo, warpRecord.worldPosition, warpCategory, warpRecord.isPrivate, warpRecord.icon); }); int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); this.entireArea.update(this.center, islandDistance); this.protectedArea.update(this.center, getIslandSize()); // We want to save all the limits to the custom block keys plugin.getBlockValues().addCustomBlockKeys(builder.blockLimits.keySet()); updateDatesFormatter(); startBankInterest(); checkMembersDuplication(); updateOldUpgradeValues(); updateUpgrades(); updateIslandChests(); // We can only track entity counts after upgrades are set up if (!builder.entityCounts.isEmpty()) { builder.entityCounts.forEach((entity, count) -> this.entitiesTracker.trackEntity(entity, count.intValue())); } this.islandBank.setBalance(builder.balance); builder.bankTransactions.forEach(this.islandBank::loadTransaction); if (builder.persistentData.length > 0) getPersistentDataContainer().load(builder.persistentData); this.databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } /* * General methods */ @Override public SuperiorPlayer getOwner() { return owner; } @Override public UUID getUniqueId() { return uuid; } @Override public long getCreationTime() { return creationTime; } /* * Player related methods */ @Override public String getCreationTimeDate() { return creationTimeDate; } @Override public void updateDatesFormatter() { this.creationTimeDate = Formatters.DATE_FORMATTER.format(new Date(creationTime * 1000)); } @Override public IslandCache getCache() { return this.islandCache.get(); } @Override public List getIslandMembers(boolean includeOwner) { List members = this.members.readAndGet(_members -> new SequentialListBuilder() .mutable() .build(_members)); if (includeOwner) members.add(owner); return Collections.unmodifiableList(members); } @Override public List getIslandMembers(PlayerRole... playerRoles) { Preconditions.checkNotNull(playerRoles, "playerRoles parameter cannot be null."); List rolesToFilter = Arrays.asList(playerRoles); List members = this.members.readAndGet(_members -> new SequentialListBuilder() .mutable() .filter(superiorPlayer -> rolesToFilter.contains(superiorPlayer.getPlayerRole())) .build(_members)); if (rolesToFilter.contains(SPlayerRole.lastRole())) members.add(owner); return Collections.unmodifiableList(members); } @Override public List getBannedPlayers() { return new SequentialListBuilder().build(this.bannedPlayers); } @Override public List getIslandVisitors() { return getIslandVisitors(true); } @Override public List getIslandVisitors(boolean vanishPlayers) { return playersInside.readAndGet(playersInside -> new SequentialListBuilder() .filter(superiorPlayer -> !isMember(superiorPlayer) && (vanishPlayers || superiorPlayer.isShownAsOnline())) .build(playersInside)); } @Override public List getAllPlayersInside() { return playersInside.readAndGet(playersInside -> new SequentialListBuilder() .filter(SuperiorPlayer::isOnline) .build(playersInside)); } @Override public List getUniqueVisitors() { return uniqueVisitors.readAndGet(uniqueVisitors -> new SequentialListBuilder() .build(uniqueVisitors, UniqueVisitor::getSuperiorPlayer)); } @Override public List> getUniqueVisitorsWithTimes() { return uniqueVisitors.readAndGet(uniqueVisitors -> new SequentialListBuilder>() .build(uniqueVisitors, UniqueVisitor::toPair)); } @Override public void inviteMember(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Log.debug(Debug.INVITE_MEMBER, owner.getName(), superiorPlayer.getName()); invitedPlayers.add(superiorPlayer); superiorPlayer.addInvite(this); //Revoke the invite after 5 minutes registerTask(BukkitExecutor.sync(() -> revokeInvite(superiorPlayer), 6000L)); } @Override public void revokeInvite(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Log.debug(Debug.REVOKE_INVITE, owner.getName(), superiorPlayer.getName()); invitedPlayers.remove(superiorPlayer); superiorPlayer.removeInvite(this); } @Override public boolean isInvited(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return invitedPlayers.contains(superiorPlayer); } @Override public List getInvitedPlayers() { return new SequentialListBuilder().build(this.invitedPlayers); } @Override public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); Log.debug(Debug.ADD_MEMBER, owner.getName(), superiorPlayer.getName(), playerRole); boolean addedNewMember = members.writeAndGet(members -> members.add(superiorPlayer)); // This player is already a member of the island if (!addedNewMember) return; // Remove player from being cooped, invited and its ratings removeCoop(superiorPlayer); revokeInvite(superiorPlayer); removeRating(superiorPlayer); superiorPlayer.setIsland(this); if (PluginEventsFactory.callPlayerChangeRoleEvent(superiorPlayer, playerRole)) { superiorPlayer.setPlayerRole(playerRole); } else { superiorPlayer.setPlayerRole(SPlayerRole.defaultRole()); } plugin.getMenus().refreshMembers(this); updateLastTime(); ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnJoin(), plugin.getSettings().isTeleportOnJoin() ? this : null); if (superiorPlayer.isOnline()) { updateIslandFly(superiorPlayer); setCurrentlyActive(); } IslandsDatabaseBridge.addMember(this, superiorPlayer, System.currentTimeMillis()); } @Override public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason reason) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(reason, "memberRemoveReason parameter cannot be null."); Preconditions.checkArgument(!superiorPlayer.equals(owner), "superiorPlayer cannot be island owner."); removeMemberSafe(superiorPlayer, reason); } private void removeMemberSafe(SuperiorPlayer superiorPlayer, MemberRemoveReason reason) { if (reason == MemberRemoveReason.KICK) Log.debug(Debug.KICK_MEMBER, owner.getName(), superiorPlayer.getName()); else if (reason == MemberRemoveReason.LEAVE) Log.debug(Debug.LEAVE_ISLAND, owner.getName(), superiorPlayer.getName()); if (!superiorPlayer.equals(owner)) { boolean removedMember = members.writeAndGet(members -> members.remove(superiorPlayer)); if (!removedMember) { // If the remove method failed, we iterate through all the members and remove the member manually. // Should fix issues if members are not in the correct order. // Reference: https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/734 removedMember = members.writeAndGet(members -> members.removeIf(superiorPlayer::equals)); } // This player is not a member of the island. if (!removedMember) return; } boolean isInside = superiorPlayer.isInsideIsland(); superiorPlayer.setIsland(null); if (reason == MemberRemoveReason.DISBAND) { ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnDisband(), isInside ? plugin.getGrid().getSpawnIsland() : null); } else if (reason == MemberRemoveReason.KICK) { boolean shouldTeleport = plugin.getSettings().isTeleportOnKick() && isInside; ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnKick(), shouldTeleport ? plugin.getGrid().getSpawnIsland() : null); if (!shouldTeleport) updateIslandFly(superiorPlayer); } else if (reason == MemberRemoveReason.LEAVE) { boolean shouldTeleport = plugin.getSettings().isTeleportOnLeave() && isInside; ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnLeave(), shouldTeleport ? plugin.getGrid().getSpawnIsland() : null); if (!shouldTeleport) updateIslandFly(superiorPlayer); } superiorPlayer.runIfOnline(player -> { MenuView openedView = superiorPlayer.getOpenedView(); if (openedView != null) openedView.closeView(); }); plugin.getMissions().getPlayerMissions().forEach(mission -> { MissionData missionData = plugin.getMissions().getMissionData(mission).orElse(null); if (missionData == null) return; if ((reason == MemberRemoveReason.DISBAND && missionData.isDisbandReset()) || ((reason == MemberRemoveReason.KICK || reason == MemberRemoveReason.LEAVE) && missionData.isLeaveReset())) superiorPlayer.resetMission(mission); }); if (reason == MemberRemoveReason.KICK || reason == MemberRemoveReason.LEAVE) { plugin.getMenus().destroyMemberManage(superiorPlayer); plugin.getMenus().destroyMemberRole(superiorPlayer); plugin.getMenus().refreshMembers(this); IslandsDatabaseBridge.removeMember(this, superiorPlayer); } } @Override @Deprecated public void kickMember(SuperiorPlayer superiorPlayer) { removeMember(superiorPlayer, MemberRemoveReason.KICK); } @Override public boolean isMember(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return owner.equals(superiorPlayer.getIslandLeader()); } @Override public void banMember(SuperiorPlayer superiorPlayer) { banMember(superiorPlayer, null); } @Override public void banMember(SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer whom) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Log.debug(Debug.BAN_PLAYER, owner.getName(), superiorPlayer.getName(), whom); boolean bannedPlayer = bannedPlayers.add(superiorPlayer); // This player is already banned. if (!bannedPlayer) return; if (isMember(superiorPlayer)) removeMember(superiorPlayer, MemberRemoveReason.KICK); plugin.getMenus().refreshIslandBannedPlayers(this); superiorPlayer.runIfOnline(player -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (isInside(player.getLocation(wrapper.getHandle()))) superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); } }); IslandsDatabaseBridge.addBannedPlayer(this, superiorPlayer, whom == null ? CONSOLE_UUID : whom.getUniqueId(), System.currentTimeMillis()); } @Override public void unbanMember(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Log.debug(Debug.UNBAN_PLAYER, owner.getName(), superiorPlayer.getName()); boolean unbannedPlayer = bannedPlayers.remove(superiorPlayer); if (unbannedPlayer) { plugin.getMenus().refreshIslandBannedPlayers(this); IslandsDatabaseBridge.removeBannedPlayer(this, superiorPlayer); } } @Override public boolean isBanned(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return bannedPlayers.contains(superiorPlayer); } @Override public void addCoop(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Log.debug(Debug.ADD_COOP, owner.getName(), superiorPlayer.getName()); boolean coopPlayer = coopPlayers.add(superiorPlayer); if (!coopPlayer) return; superiorPlayer.addCoop(this); plugin.getMenus().refreshCoops(this); } @Override public void removeCoop(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Log.debug(Debug.REMOVE_COOP, owner.getName(), superiorPlayer.getName()); boolean uncoopPlayer = coopPlayers.remove(superiorPlayer); // This player was not coop. if (!uncoopPlayer) return; superiorPlayer.removeCoop(this); superiorPlayer.runIfOnline(player -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (isLocked() && isInside(player.getLocation(wrapper.getHandle()))) { MenuView openedView = superiorPlayer.getOpenedView(); if (openedView != null) openedView.closeView(); superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); } } }); plugin.getMenus().refreshCoops(this); } @Override public boolean isCoop(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return plugin.getSettings().isCoopMembers() && coopPlayers.contains(superiorPlayer); } @Override public List getCoopPlayers() { return new SequentialListBuilder().build(this.coopPlayers); } @Override public int getCoopLimit() { return this.coopLimit.readAndGet(IntValue::get); } @Override public int getCoopLimitRaw() { return this.coopLimit.readAndGet(coopLimit -> coopLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override public void setCoopLimit(int coopLimit) { coopLimit = Math.max(0, coopLimit); Log.debug(Debug.SET_COOP_LIMIT, owner.getName(), coopLimit); // Original and new coop limit are the same if (coopLimit == getCoopLimitRaw()) return; this.coopLimit.set(IntValue.fixed(coopLimit)); IslandsDatabaseBridge.saveCoopLimit(this); } /* * Location related methods */ @Override public void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); if (inside) { Log.debug(Debug.ENTER_ISLAND, owner.getName(), superiorPlayer.getName()); } else { Log.debug(Debug.LEAVE_ISLAND, owner.getName(), superiorPlayer.getName()); } boolean changePlayers = playersInside.writeAndGet(playersInside -> { if (inside) return playersInside.add(superiorPlayer); else return playersInside.remove(superiorPlayer); }); // The players inside the player weren't changed. if (!changePlayers) return; plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_PLAYERS, this); if (!isMember(superiorPlayer) && superiorPlayer.isShownAsOnline()) { Optional uniqueVisitorOptional = uniqueVisitors.readAndGet(uniqueVisitors -> uniqueVisitors.stream().filter(pair -> pair.getSuperiorPlayer().equals(superiorPlayer)).findFirst()); long visitTime = System.currentTimeMillis(); boolean updateVisitor; if (uniqueVisitorOptional.isPresent()) { uniqueVisitorOptional.get().setLastVisitTime(visitTime); updateVisitor = true; } else { updateVisitor = uniqueVisitors.writeAndGet(uniqueVisitors -> uniqueVisitors.add(new UniqueVisitor(superiorPlayer, visitTime))); } if (updateVisitor) { plugin.getMenus().refreshUniqueVisitors(this); IslandsDatabaseBridge.saveVisitor(this, superiorPlayer, visitTime); } } updateLastTime(); plugin.getMenus().refreshVisitors(this); } @Override public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean includeCoopStatus) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return !isMember(superiorPlayer) && (!includeCoopStatus || !isCoop(superiorPlayer)); } @Override public Location getCenter(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); World world = plugin.getGrid().getIslandsWorld(this, dimension); Preconditions.checkNotNull(world, "Couldn't find world for dimension " + dimension + "."); return this.center.toWorldPosition().toLocation(world); } @Override public BlockPosition getCenterPosition() { return center; } @Override public CompletableFuture accessIslandWorld(Dimension dimension) { CompletableFuture completableFuture = new CompletableFuture<>(); IslandWorlds.accessIslandWorldAsync(this, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(completableFuture::completeExceptionally).ifLeft(completableFuture::complete); }); return completableFuture; } @Override public Location getIslandHome(Dimension dimension) { WorldPosition islandHome = getIslandHomePosition(dimension); return islandHome == null ? null : IslandWorlds.setWorldToLocation(this, dimension, islandHome); } @Override public WorldPosition getIslandHomePosition(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); WorldPosition islandHome = islandHomes.readAndGet(islandHomes -> islandHomes.get(dimension)); return islandHome == null ? this.center.toWorldPosition() : islandHome; } @Override public Map getIslandHomesAsDimensions() { Map islandHomes = this.islandHomes.readAndGet(map -> map.collect(Dimension.values(), this::worldPositionToLocation)); return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes); } @Override public Map getIslandHomes() { Map islandHomes = this.islandHomes.readAndGet(map -> map.collect(Dimension.values())); return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes); } @Override public void setIslandHome(Location homeLocation) { Preconditions.checkNotNull(homeLocation, "homeLocation parameter cannot be null."); Preconditions.checkNotNull(homeLocation.getWorld(), "homeLocation's world cannot be null."); Preconditions.checkArgument(isInside(homeLocation), "homeLocation must be inside island."); Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(homeLocation.getWorld()); setIslandHome(dimension, SWorldPosition.of(homeLocation)); } @Override public void setIslandHome(Dimension dimension, @Nullable Location homeLocation) { setIslandHome(dimension, homeLocation == null ? null : SWorldPosition.of(homeLocation)); } @Override public void setIslandHome(Dimension dimension, @Nullable WorldPosition homePosition) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Log.debug(Debug.SET_ISLAND_HOME, owner.getName(), dimension, homePosition); WorldPosition newHome = adjustPositionToCenterOfBlock(homePosition); WorldPosition oldHome = islandHomes.writeAndGet(islandHomes -> newHome == null ? islandHomes.remove(dimension) : islandHomes.put(dimension, newHome)); if (!Objects.equals(oldHome, newHome)) IslandsDatabaseBridge.saveIslandHome(this, dimension, newHome); } @Nullable @Override public Location getVisitorsLocation(Dimension unused) { WorldPosition visitorsPosition = getVisitorsPosition(null /*unused*/); return visitorsPosition == null ? null : IslandWorlds.setWorldToLocation( this, plugin.getSettings().getWorlds().getDefaultWorldDimension(), visitorsPosition); } @Override public WorldPosition getVisitorsPosition(Dimension unused) { Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); return this.visitorHomes.readAndGet(visitorHomes -> visitorHomes.get(defaultWorldDimension)); } @Override public void setVisitorsLocation(@Nullable Location visitorsLocation) { setVisitorsLocation(null /*unused*/, visitorsLocation == null ? null : SWorldPosition.of(visitorsLocation)); } @Override public void setVisitorsLocation(Dimension unused, @Nullable WorldPosition visitorsPosition) { Log.debug(Debug.SET_VISITOR_HOME, owner.getName(), visitorsPosition); Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); WorldPosition newHome = adjustPositionToCenterOfBlock(visitorsPosition); WorldPosition oldHome = visitorHomes.writeAndGet(visitorHomes -> newHome == null ? visitorHomes.remove(defaultWorldDimension) : visitorHomes.put(defaultWorldDimension, newHome)); if (!Objects.equals(oldHome, newHome)) IslandsDatabaseBridge.saveVisitorLocation(this, defaultWorldDimension, newHome); } @Override public Location getMinimum() { int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); return getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).subtract(islandDistance, 0, islandDistance); } @Override public BlockPosition getMinimumPosition() { int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); return getCenterPosition().offset(-islandDistance, 0, -islandDistance); } @Override public Location getMinimumProtected() { int islandSize = getIslandSize(); return getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).subtract(islandSize, 0, islandSize); } @Override public BlockPosition getMinimumProtectedPosition() { int islandSize = getIslandSize(); return getCenterPosition().offset(-islandSize, 0, -islandSize); } @Override public Location getMaximum() { int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); return getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).add(islandDistance, 0, islandDistance); } @Override public BlockPosition getMaximumPosition() { int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); return getCenterPosition().offset(islandDistance, 0, islandDistance); } @Override public Location getMaximumProtected() { int islandSize = getIslandSize(); return getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).add(islandSize, 0, islandSize); } @Override public BlockPosition getMaximumProtectedPosition() { int islandSize = getIslandSize(); return getCenterPosition().offset(islandSize, 0, islandSize); } @Override public List getAllChunks() { return getAllChunks(0); } @Override public List getAllChunks(int flags) { List chunks = new LinkedList<>(); for (Dimension dimension : Dimension.values()) { try { chunks.addAll(getAllChunks(dimension, flags)); } catch (NullPointerException ignored) { } } return Collections.unmodifiableList(chunks); } @Override public List getAllChunks(Dimension dimension) { return getAllChunks(dimension, 0); } @Override public List getAllChunks(Dimension dimension, @IslandChunkFlags int flags) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); World world = getCenter(dimension).getWorld(); return new SequentialListBuilder().build(IslandUtils.getChunkCoords(this, WorldInfo.of(world), flags), chunkPosition -> world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ())); } @Override public List getLoadedChunks() { return getLoadedChunks(0); } @Override public List getLoadedChunks(@IslandChunkFlags int flags) { List chunks = new LinkedList<>(); for (Dimension dimension : Dimension.values()) { try { chunks.addAll(getLoadedChunks(dimension, flags)); } catch (NullPointerException ignored) { } } return Collections.unmodifiableList(chunks); } @Override public List getLoadedChunks(Dimension dimension) { return getLoadedChunks(dimension, 0); } @Override public List getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); return new SequentialListBuilder().filter(Objects::nonNull).build( IslandUtils.getChunkCoords(this, worldInfo, flags), plugin.getNMSChunks()::getChunkIfLoaded); } @Override public List> getAllChunksAsync(Dimension dimension) { return getAllChunksAsync(dimension, 0); } @Override public List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags) { return getAllChunksAsync(dimension, flags, null); } @Override public List> getAllChunksAsync(Dimension dimension, @Nullable Consumer onChunkLoad) { return getAllChunksAsync(dimension, 0, onChunkLoad); } @Override public List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags, @Nullable Consumer onChunkLoad) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); return IslandUtils.getAllChunksAsync(this, worldInfo, flags, ChunkLoadReason.API_REQUEST, onChunkLoad); } @Override public void resetChunks() { resetChunks((Runnable) null); } @Override public void resetChunks(@Nullable Runnable onFinish) { resetChunks(0, onFinish); } @Override public void resetChunks(Dimension dimension) { resetChunks(dimension, 0); } @Override public void resetChunks(Dimension dimension, @Nullable Runnable onFinish) { resetChunks(dimension, 0, onFinish); } @Override public void resetChunks(@IslandChunkFlags int flags) { resetChunks(flags, null); } @Override public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) { final int realFlags = flags | IslandChunkFlags.NO_EMPTY_CHUNKS; List dimensionList = new LinkedList<>(); for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && wasSchematicGenerated(dimension)) { dimensionList.add(dimension); } } List customWorlds = plugin.getGrid().getRegisteredWorlds(); SynchronizedTasks synchronizedTasks = new SynchronizedTasks(dimensionList.size() + customWorlds.size(), onFinish); customWorlds.forEach(registeredWorld -> { WorldInfo worldInfo = WorldInfo.of(registeredWorld); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); if (!chunkPositions.isEmpty()) { IslandUtils.deleteChunks(this, chunkPositions, synchronizedTasks::notifyTaskComplete); } else { synchronizedTasks.notifyTaskComplete(); } }); dimensionList.forEach(dimension -> { IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> { result.ifLeft(world -> { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); if (!chunkPositions.isEmpty()) { IslandUtils.deleteChunks(this, chunkPositions, synchronizedTasks::notifyTaskComplete); } else { synchronizedTasks.notifyTaskComplete(); } }).ifRight(error -> { synchronizedTasks.notifyTaskComplete(); throw new RuntimeException(error); }); }); }); synchronizedTasks.waitAllAsync(); } @Override public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) { resetChunks(dimension, flags, null); } @Override public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> { result.ifRight(error -> { throw new RuntimeException(error); }).ifLeft(world -> { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, flags | IslandChunkFlags.NO_EMPTY_CHUNKS); if (!chunkPositions.isEmpty()) { IslandUtils.deleteChunks(this, chunkPositions, onFinish); } else if (onFinish != null) { onFinish.run(); } }); }); } @Override public boolean isInside(Location location) { return isInside(location, 0); } @Override public boolean isInside(Location location, int extraRadius) { return isInside(location, (double) extraRadius); } @Override public boolean isInside(Location location, double extraRadius) { Preconditions.checkNotNull(location, "location parameter cannot be null."); return isIslandWorld(location) && this.entireArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override public boolean isInside(BlockPosition blockPosition) { return isInside(blockPosition, 0D); } @Override public boolean isInside(BlockPosition blockPosition, int extraRadius) { return isInside(blockPosition, (double) extraRadius); } @Override public boolean isInside(BlockPosition blockPosition, double extraRadius) { Preconditions.checkNotNull(blockPosition, "blockPosition parameter cannot be null."); return this.entireArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius); } @Override public boolean isInside(WorldPosition worldPosition) { return isInside(worldPosition, 0D); } @Override public boolean isInside(WorldPosition worldPosition, int extraRadius) { return isInside(worldPosition, (double) extraRadius); } @Override public boolean isInside(WorldPosition worldPosition, double extraRadius) { Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); return this.entireArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius); } @Override public boolean isInside(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); return isInside(chunk.getWorld(), chunk.getX(), chunk.getZ()); } @Override public boolean isInside(World world, int chunkX, int chunkZ) { return isInside(world, chunkX, chunkZ, 0D); } @Override public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) { return isInside(world, chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) { Preconditions.checkNotNull(world, "world parameter cannot be null."); return isIslandWorld(world) && isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { return isInside(worldInfo, chunkX, chunkZ, 0D); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { return isInside(worldInfo, chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); return isIslandWorld(worldInfo) && isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInside(int chunkX, int chunkZ) { return isInside(chunkX, chunkZ, 0D); } @Override public boolean isInside(int chunkX, int chunkZ, int extraRadius) { return isInside(chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInside(int chunkX, int chunkZ, double extraRadius) { return this.entireArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4); } @Override public boolean isInsideRange(Location location) { return isInsideRange(location, 0); } @Override public boolean isInsideRange(Location location, int extraRadius) { return isInsideRange(location, (double) extraRadius); } @Override public boolean isInsideRange(Location location, double extraRadius) { Preconditions.checkNotNull(location, "location parameter cannot be null."); return isIslandWorld(location) && this.protectedArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override public boolean isInsideRange(BlockPosition blockPosition) { return isInsideRange(blockPosition, 0D); } @Override public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) { return isInsideRange(blockPosition, (double) extraRadius); } @Override public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) { Preconditions.checkNotNull(blockPosition, "blockPosition parameter cannot be null."); return this.protectedArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius); } @Override public boolean isInsideRange(WorldPosition worldPosition) { return isInsideRange(worldPosition, 0D); } @Override public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) { return isInsideRange(worldPosition, (double) extraRadius); } @Override public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) { Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); return this.protectedArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius); } @Override public boolean isInsideRange(Chunk chunk) { return isInsideRange(chunk.getWorld(), chunk.getX(), chunk.getZ()); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ) { return isInsideRange(world, chunkX, chunkZ, 0D); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) { return isInsideRange(world, chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) { Preconditions.checkNotNull(world, "world parameter cannot be null."); return isIslandWorld(world) && isInsideRange(chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) { return isInsideRange(worldInfo, chunkX, chunkZ, 0D); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { return isInsideRange(worldInfo, chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); return isIslandWorld(worldInfo) && isInsideRange(chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(int chunkX, int chunkZ) { return isInsideRange(chunkX, chunkZ, 0D); } @Override public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) { return isInsideRange(chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) { return this.protectedArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4); } private boolean isIslandWorld(Location location) { return isIslandWorld(LazyWorldLocation.getWorldName(location)); } private boolean isIslandWorld(@Nullable World world) { return world != null && isIslandWorld(world.getName()); } private boolean isIslandWorld(@Nullable WorldInfo worldInfo) { return worldInfo != null && isIslandWorld(worldInfo.getName()); } private boolean isIslandWorld(@Nullable String worldName) { if (worldName == null) return false; return plugin.getGrid().getIslandsWorldInfo(this, worldName) != null; } @Override public boolean isNormalEnabled() { return isDimensionEnabled(Dimension.getByName("NORMAL")); } @Override public void setNormalEnabled(boolean enabled) { setDimensionEnabled(Dimension.getByName("NORMAL"), enabled); } @Override public boolean isNetherEnabled() { return isDimensionEnabled(Dimension.getByName("NETHER")); } @Override public void setNetherEnabled(boolean enabled) { setDimensionEnabled(Dimension.getByName("NETHER"), enabled); } @Override public boolean isEndEnabled() { return isDimensionEnabled(Dimension.getByName("THE_END")); } @Override public void setEndEnabled(boolean enabled) { setDimensionEnabled(Dimension.getByName("THE_END"), enabled); } @Override public boolean isDimensionEnabled(Dimension dimension) { return plugin.getProviders().getWorldsProvider().isDimensionUnlocked(dimension) || unlockedWorlds.readAndGet(unlockedWorlds -> unlockedWorlds.contains(dimension)); } @Override public void setDimensionEnabled(Dimension dimension, boolean enabled) { Log.debug(Debug.SET_DIMENSION_ENABLED, owner.getName(), dimension.getName(), enabled); boolean updated = this.unlockedWorlds.writeAndGet(unlockedWorlds -> { return enabled ? unlockedWorlds.add(dimension) : unlockedWorlds.remove(dimension); }); if (updated) IslandsDatabaseBridge.saveUnlockedWorlds(this); } @Override public Set getUnlockedWorlds() { return Collections.unmodifiableSet(this.unlockedWorlds.readAndGet(unlockedWorlds -> unlockedWorlds.collect(Dimension.values()))); } /* * Permissions related methods */ @Override public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(sender, "sender parameter cannot be null."); Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); return sender instanceof ConsoleCommandSender || hasPermission(plugin.getPlayers().getSuperiorPlayer(sender), islandPrivilege); } @Override public boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); PermissionNode playerNode = getPermissionNode(superiorPlayer); return superiorPlayer.hasBypassModeEnabled() || superiorPlayer.hasBypassPermission(islandPrivilege) || superiorPlayer.hasPermissionWithoutOP("superior.admin.bypass.*") || (playerNode != null && playerNode.hasPermission(islandPrivilege)); } @Override public boolean hasPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); return getRequiredPlayerRole(islandPrivilege).getWeight() <= playerRole.getWeight(); } @Override public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege, boolean value) { if (value) this.setPermission(playerRole, islandPrivilege); } @Override public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); Log.debug(Debug.SET_PERMISSION, owner.getName(), playerRole, islandPrivilege); Integer oldRoleId = rolePermissions.put(islandPrivilege, playerRole.getId()); if (oldRoleId != null && oldRoleId == playerRole.getId()) return; if (islandPrivilege == IslandPrivileges.FLY) { getAllPlayersInside().forEach(this::updateIslandFly); } else if (islandPrivilege == IslandPrivileges.VILLAGER_TRADING) { getAllPlayersInside().forEach(superiorPlayer -> IslandUtils.updateTradingMenus(this, superiorPlayer)); } IslandsDatabaseBridge.saveRolePermission(this, playerRole, islandPrivilege); } @Override public void resetPermissions() { Log.debug(Debug.RESET_PERMISSIONS, owner.getName()); if (rolePermissions.isEmpty()) return; rolePermissions.clear(); getAllPlayersInside().forEach(superiorPlayer -> { updateIslandFly(superiorPlayer); IslandUtils.updateTradingMenus(this, superiorPlayer); }); IslandsDatabaseBridge.clearRolePermissions(this); plugin.getMenus().refreshPermissions(this); } @Override public void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); Log.debug(Debug.SET_PERMISSION, owner.getName(), superiorPlayer.getName(), islandPrivilege, value); PlayerPrivilegeNode privilegeNode = playerPermissions.computeIfAbsent(superiorPlayer, s -> new PlayerPrivilegeNode(superiorPlayer, this)); privilegeNode.setPermission(islandPrivilege, value); superiorPlayer.runIfOnline(player -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (isInside(player.getLocation(wrapper.getHandle()))) { if (islandPrivilege == IslandPrivileges.FLY) { updateIslandFly(superiorPlayer); } else if (islandPrivilege == IslandPrivileges.VILLAGER_TRADING) { IslandUtils.updateTradingMenus(this, superiorPlayer); } } } }); IslandsDatabaseBridge.savePlayerPermission(this, superiorPlayer, islandPrivilege, value); plugin.getMenus().refreshPermissions(this, superiorPlayer); } @Override public void resetPermissions(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Log.debug(Debug.RESET_PERMISSIONS, owner.getName(), superiorPlayer.getName()); PlayerPrivilegeNode oldPrivilegeNode = playerPermissions.remove(superiorPlayer); if (oldPrivilegeNode == null) return; if (superiorPlayer.isOnline()) { updateIslandFly(superiorPlayer); IslandUtils.updateTradingMenus(this, superiorPlayer); } IslandsDatabaseBridge.clearPlayerPermission(this, superiorPlayer); plugin.getMenus().refreshPermissions(this, superiorPlayer); } @Override public PrivilegeNodeAbstract getPermissionNode(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); return playerPermissions.getOrDefault(superiorPlayer, new PlayerPrivilegeNode(superiorPlayer, this)); } @Override public PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); Integer playerRoleId = rolePermissions.get(islandPrivilege); if (playerRoleId != null) return plugin.getRoles().getPlayerRoleFromId(playerRoleId); return plugin.getRoles().getRoles().stream() .filter(_playerRole -> { if (!plugin.getSettings().isCoopMembers() && _playerRole == SPlayerRole.coopRole()) return false; return ((SPlayerRole) _playerRole).getDefaultPermissions().hasPermission(islandPrivilege); }) .min(Comparator.comparingInt(PlayerRole::getWeight)).orElse(SPlayerRole.lastRole()); } /* * General methods */ @Override public Map getPlayerPermissions() { return Collections.unmodifiableMap(playerPermissions); } @Override public Map getRolePermissions() { return Collections.unmodifiableMap(this.rolePermissions.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> plugin.getRoles().getPlayerRoleFromId(entry.getValue()) ))); } @Override public boolean isSpawn() { return false; } @Override public String getName() { return plugin.getSettings().getIslandNames().isColorSupport() ? getFormattedName() : getStrippedName(); } @Override public void setName(String islandName) { Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); String strippedName = Formatters.STRIP_COLOR_FORMATTER.format(islandName); Log.debug(Debug.SET_NAME, owner.getName(), strippedName); String oldName = this.strippedName; setNameInternal(islandName); if (Objects.equals(strippedName, oldName)) return; plugin.getGrid().getIslandsContainer().updateIslandName(this, oldName); IslandsDatabaseBridge.saveName(this); } private void setNameInternal(String name) { this.formattedName = Formatters.COLOR_FORMATTER.format(name); this.strippedName = Formatters.STRIP_COLOR_FORMATTER.format(name); } @Override public String getRawName() { return getStrippedName(); } @Override public String getStrippedName() { return this.strippedName; } @Override public String getFormattedName() { return this.formattedName; } @Override public String getDescription() { return description; } @Override public void setDescription(String description) { Preconditions.checkNotNull(description, "description parameter cannot be null."); Log.debug(Debug.SET_DESCRIPTION, owner.getName(), description); if (Objects.equals(this.description, description)) return; this.description = description; IslandsDatabaseBridge.saveDescription(this); } @Override public void disbandIsland() { long profilerId = Profiler.start(ProfileType.DISBAND_ISLAND, 2); forEachIslandMember(EMPTY_IGNORED_MEMBERS, false, islandMember -> { removeMemberSafe(islandMember, MemberRemoveReason.DISBAND); }); this.activeTasks.write(activeTasks -> { activeTasks.forEach(BukkitTask::cancel); }); this.bankInterestTask.set((BukkitTask) null); invitedPlayers.forEach(invitedPlayer -> invitedPlayer.removeInvite(this)); coopPlayers.forEach(coopPlayer -> coopPlayer.removeCoop(this)); if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); plugin.getProviders().depositMoney(getOwner(), islandBank.getBalance().multiply(disbandRefund)); } plugin.getMissions().getIslandMissions().forEach(this::resetMission); resetChunks(IslandChunkFlags.ONLY_PROTECTED, () -> Profiler.end(profilerId)); plugin.getGrid().deleteIsland(this); Profiler.end(profilerId); } @Override public boolean transferIsland(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); if (superiorPlayer.equals(owner)) return false; SuperiorPlayer previousOwner = getOwner(); if (!PluginEventsFactory.callIslandTransferEvent(this, previousOwner, superiorPlayer)) return false; Log.debug(Debug.TRANSFER_ISLAND, owner.getName(), superiorPlayer.getName()); //Kick member without saving to database members.write(members -> members.remove(superiorPlayer)); superiorPlayer.setPlayerRole(SPlayerRole.lastRole()); //Add member without saving to database members.write(members -> members.add(previousOwner)); PlayerRole previousRole = SPlayerRole.lastRole().getPreviousRole(); previousOwner.setPlayerRole(previousRole == null ? SPlayerRole.lastRole() : previousRole); //Changing owner of the island. owner = superiorPlayer; IslandsDatabaseBridge.saveIslandLeader(this); IslandsDatabaseBridge.addMember(this, previousOwner, getCreationTime()); plugin.getMissions().getIslandMissions().forEach(mission -> mission.transferData(previousOwner, owner)); return true; } @Override public void replacePlayers(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer) { Preconditions.checkNotNull(originalPlayer, "originalPlayer parameter cannot be null."); Preconditions.checkState(originalPlayer != newPlayer, "originalPlayer and newPlayer cannot equal."); Log.debug(Debug.REPLACE_PLAYER, owner, originalPlayer, newPlayer); if (owner.equals(originalPlayer)) { if (newPlayer == null) { Log.debugResult(Debug.REPLACE_PLAYER, "Action", "Disband Island"); this.disbandIsland(); } else { Log.debugResult(Debug.REPLACE_PLAYER, "Action", "Replace Owner"); owner = newPlayer; } } else if (isMember(originalPlayer)) { Log.debugResult(Debug.REPLACE_PLAYER, "Action", "Replace Member"); members.write(members -> { members.remove(originalPlayer); if (newPlayer != null) members.add(newPlayer); }); } replaceVisitor(originalPlayer, newPlayer); replaceBannedPlayer(originalPlayer, newPlayer); replacePermissions(originalPlayer, newPlayer); } @Override public void calcIslandWorth(@Nullable SuperiorPlayer asker) { calcIslandWorth(asker, null); } @Override public void calcIslandWorth(@Nullable SuperiorPlayer asker, @Nullable Runnable callback) { Log.debug(Debug.CALCULATE_ISLAND, owner.getName(), asker); long lastUpdateTime = getLastTimeUpdate(); if (lastUpdateTime != -1 && (System.currentTimeMillis() / 1000) - lastUpdateTime >= 600) { Log.debugResult(Debug.CALCULATE_ISLAND, "Result Cooldown", owner.getName()); finishCalcIsland(asker, callback, getIslandLevel(), getWorth()); return; } registerTask(BukkitExecutor.ensureMain(() -> { calcIslandWorthInternal(asker, callback); })); } @Override public IslandCalculationAlgorithm getCalculationAlgorithm() { return this.calculationAlgorithm; } @Override public void updateBorder() { Log.debug(Debug.UPDATE_BORDER, owner.getName()); getAllPlayersInside().forEach(superiorPlayer -> superiorPlayer.updateWorldBorder(this)); } @Override public void updateIslandFly(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); IslandUtils.updateIslandFly(this, superiorPlayer); } @Override public int getIslandSize() { if (plugin.getSettings().isBuildOutsideIsland()) return (int) Math.round(plugin.getSettings().getMaxIslandSize() * 1.5); return this.islandSize.readAndGet(IntValue::get); } @Override public void setIslandSize(int islandSize) { islandSize = Math.max(1, islandSize); Preconditions.checkArgument(islandSize <= plugin.getSettings().getMaxIslandSize(), "Border size " + islandSize + " cannot be larger than max island size: " + plugin.getSettings().getMaxIslandSize()); Log.debug(Debug.SET_SIZE, owner.getName(), islandSize); if (islandSize == getIslandSizeRaw()) return; setIslandSizeInternal(IntValue.fixed(islandSize)); IslandsDatabaseBridge.saveSize(this); } private void setIslandSizeInternal(IntValue islandSize) { boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class); MutableObject> oldChunks = new MutableObject<>(null); if (cropGrowthEnabled) { // We first collect all the chunks that are currently being ticked oldChunks.setValue(getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED)); } // Changing the size of the island this.islandSize.set(islandSize); if (cropGrowthEnabled) { // We now collect the new chunks after the size was changed List newChunks = getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED); registerTask(BukkitExecutor.ensureMain(() -> { // We stop all old chunks from being ticked. oldChunks.getValue().forEach(chunk -> plugin.getNMSChunks().startTickingChunk(this, chunk, true)); // We start ticking all the new chunks newChunks.forEach(chunk -> plugin.getNMSChunks().startTickingChunk(this, chunk, false)); })); } this.protectedArea.update(this.center, getIslandSize()); updateBorder(); } @Override public int getIslandSizeRaw() { return this.islandSize.readAndGet(islandSize -> islandSize.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override public String getDiscord() { return discord; } @Override public void setDiscord(String discord) { Preconditions.checkNotNull(discord, "discord parameter cannot be null."); Log.debug(Debug.SET_DISCORD, owner.getName(), discord); if (Objects.equals(discord, this.discord)) return; this.discord = discord; IslandsDatabaseBridge.saveDiscord(this); } @Override public String getPaypal() { return paypal; } @Override public void setPaypal(String paypal) { Preconditions.checkNotNull(paypal, "paypal parameter cannot be null."); Log.debug(Debug.SET_PAYPAL, owner.getName(), paypal); if (Objects.equals(paypal, this.paypal)) return; this.paypal = paypal; IslandsDatabaseBridge.savePaypal(this); } @Override public Biome getBiome() { if (biome == null) { biomeGetterTask.set(this::getBiomeAsyncTask); return IslandUtils.getDefaultWorldBiome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); } return biome; } private CompletableFuture getBiomeAsyncTask(CompletableFuture currentTask) { if (currentTask != null) return currentTask; Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); BlockPosition centerBlockPosition = getCenterPosition(); CompletableFuture newTask = new CompletableFuture<>(); IslandWorlds.accessIslandWorldAsync(this, defaultWorldDimension, true, islandWorldResult -> { if (islandWorldResult.getRight() != null) { newTask.completeExceptionally(islandWorldResult.getRight()); return; } World world = islandWorldResult.getLeft(); ChunkPosition centerChunkPosition = ChunkPosition.of(world, centerBlockPosition.getX() >> 4, centerBlockPosition.getZ() >> 4); ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null) .thenApply(chunk -> centerBlockPosition.toLocation(world).getBlock().getBiome()) .whenComplete((biome, error) -> { if (error != null) newTask.completeExceptionally(error); else { this.biome = biome; biomeGetterTask.set((CompletableFuture) null); newTask.complete(biome); } }); }); return newTask; } @Override public void setBiome(Biome biome) { setBiome(biome, true); } @Override public void setBiome(Biome biome, boolean updateBlocks) { Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Log.debug(Debug.SET_BIOME, owner.getName(), biome, updateBlocks); this.biome = biome; if (!updateBlocks) return; IslandWorlds.accessIslandWorldsAsync(this, false, result -> { result.ifLeft(world -> { WorldInfo worldInfo = WorldInfo.of(world); Biome worldBiome = plugin.getSettings().getWorlds().getDefaultWorldDimension() == worldInfo.getDimension() ? biome : IslandUtils.getDefaultWorldBiome(worldInfo.getDimension()); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, 0); List playersToUpdate; try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(this)) { playersToUpdate = strategy.getPlayers(worldInfo); } plugin.getNMSChunks().setBiome(chunkPositions, worldBiome, playersToUpdate); }); }); try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(this)) { for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { WorldInfo worldInfo = WorldInfo.of(registeredWorld); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, 0); List playersToUpdate = strategy.getPlayers(worldInfo); plugin.getNMSChunks().setBiome(chunkPositions, biome, playersToUpdate); } } } @Override public boolean isLocked() { return isLocked; } @Override public void setLocked(boolean locked) { Log.debug(Debug.SET_LOCKED, owner.getName(), locked); if (this.isLocked == locked) return; this.isLocked = locked; if (this.isLocked) { for (SuperiorPlayer victimPlayer : getAllPlayersInside()) { if (!hasPermission(victimPlayer, IslandPrivileges.CLOSE_BYPASS)) { victimPlayer.teleport(plugin.getGrid().getSpawnIsland()); Message.ISLAND_WAS_CLOSED.send(victimPlayer); } } } IslandsDatabaseBridge.saveLockedStatus(this); } @Override public boolean isIgnored() { return isTopIslandsIgnored; } @Override public void setIgnored(boolean ignored) { Log.debug(Debug.SET_IGNORED, owner.getName(), ignored); if (this.isTopIslandsIgnored == ignored) return; this.isTopIslandsIgnored = ignored; // We want top islands to get sorted again even if only 1 island exists plugin.getGrid().setForceSort(true); IslandsDatabaseBridge.saveIgnoredStatus(this); } @Override public void sendMessage(String message) { sendMessage(message, EMPTY_IGNORED_MEMBERS); } @Override public void sendMessage(String message, UUID... ignoredMembers) { Preconditions.checkNotNull(message, "message parameter cannot be null."); Preconditions.checkNotNull(ignoredMembers, "ignoredMembers parameter cannot be null."); Log.debug(Debug.SEND_MESSAGE, owner.getName(), message, Arrays.toString(ignoredMembers)); forEachIslandMember(ignoredMembers, false, islandMember -> { String playerMessage = message; if (!Text.isBlank(playerMessage)) playerMessage = placeholdersService.get().parsePlaceholders(islandMember.asOfflinePlayer(), playerMessage); Message.CUSTOM.send(islandMember, playerMessage, false); }); } @Override public void sendMessage(IMessageComponent messageComponent) { sendMessage(messageComponent, EMPTY_MESSAGE_ARGS); } @Override public void sendMessage(IMessageComponent messageComponent, Object... args) { this.sendMessage(messageComponent, Collections.emptyList(), args); } @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers) { sendMessage(messageComponent, ignoredMembers, EMPTY_MESSAGE_ARGS); } @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers, Object... args) { Preconditions.checkNotNull(messageComponent, "messageComponent parameter cannot be null."); Preconditions.checkNotNull(ignoredMembers, "ignoredMembers parameter cannot be null."); Log.debug(Debug.SEND_MESSAGE, owner.getName(), messageComponent.getMessage(args), ignoredMembers, Arrays.asList(args)); Set ignoredMembersSet = ignoredMembers.isEmpty() ? Collections.emptySet() : new HashSet<>(ignoredMembers); forEachIslandMember(ignoredMembersSet, false, islandMember -> messageComponent.sendMessage(islandMember.asPlayer(), args)); } @Override public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut) { sendTitle(title, subtitle, fadeIn, duration, fadeOut, EMPTY_IGNORED_MEMBERS); } @Override public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers) { Preconditions.checkNotNull(ignoredMembers, "ignoredMembers parameter cannot be null."); Log.debug(Debug.SEND_TITLE, owner.getName(), title, subtitle, fadeIn, duration, fadeOut, Arrays.toString(ignoredMembers)); forEachIslandMember(ignoredMembers, true, islandMember -> { String playerTitle = title; String playerSubtitle = subtitle; Player player = islandMember.asPlayer(); if (!Text.isBlank(playerTitle)) playerTitle = placeholdersService.get().parsePlaceholders(player, playerTitle); if (!Text.isBlank(playerSubtitle)) playerSubtitle = placeholdersService.get().parsePlaceholders(player, playerSubtitle); plugin.getNMSPlayers().sendTitle(player, playerTitle, playerSubtitle, fadeIn, duration, fadeOut); }); } @Override public void executeCommand(String command, boolean onlyOnlineMembers) { executeCommand(command, onlyOnlineMembers, EMPTY_IGNORED_MEMBERS); } @Override public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) { Preconditions.checkNotNull(command, "command parameter cannot be null."); Preconditions.checkNotNull(ignoredMembers, "ignoredMembers parameter cannot be null."); Log.debug(Debug.EXECUTE_ISLAND_COMMANDS, owner.getName(), command, onlyOnlineMembers, Arrays.toString(ignoredMembers)); registerTask(BukkitExecutor.ensureMain(() -> { forEachIslandMember(ignoredMembers, onlyOnlineMembers, islandMember -> { String playerCommand = command; if (!Text.isBlank(playerCommand)) { playerCommand = placeholdersService.get().parsePlaceholders(islandMember.asOfflinePlayer(), playerCommand) .replace("{player-name}", islandMember.getName()); } Bukkit.dispatchCommand(Bukkit.getConsoleSender(), playerCommand); }); })); } @Override public boolean isBeingRecalculated() { return beingRecalculated; } @Override public void updateLastTime() { setLastTimeUpdate(System.currentTimeMillis() / 1000); } @Override public void setCurrentlyActive() { setCurrentlyActive(true); } @Override public void setCurrentlyActive(boolean active) { Log.debug(Debug.ISLAND_ACTIVE, getOwner().getName(), active); this.currentlyActive = active; } @Override public boolean isCurrentlyActive() { return this.currentlyActive; } @Override public long getLastTimeUpdate() { return this.currentlyActive ? -1 : lastTimeUpdate; } @Override public void setLastTimeUpdate(long lastTimeUpdate) { Log.debug(Debug.SET_ISLAND_LAST_TIME_UPDATED, owner.getName(), lastTimeUpdate); if (this.lastTimeUpdate == lastTimeUpdate) return; this.lastTimeUpdate = lastTimeUpdate; if (!isCurrentlyActive()) IslandsDatabaseBridge.saveLastTimeUpdate(this); } @Override public IslandBank getIslandBank() { return islandBank; } @Override public BigDecimal getBankLimit() { return this.bankLimit.readAndGet(Value::get); } /* * Bank related methods */ @Override public void setBankLimit(BigDecimal bankLimit) { Preconditions.checkNotNull(bankLimit, "bankLimit parameter cannot be null."); Log.debug(Debug.SET_BANK_LIMIT, owner.getName(), bankLimit); if (Objects.equals(bankLimit, getBankLimitRaw())) return; if (bankLimit.compareTo(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE) <= 0) { this.bankLimit.set(Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE)); getUpgrades().forEach((upgradeName, level) -> { Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName); if (upgrade != null) { UpgradeLevel upgradeLevel = upgrade.getUpgradeLevel(level); if (upgradeLevel.getBankLimit().compareTo(getBankLimit()) > 0) { this.bankLimit.set(Value.syncedFixed(upgradeLevel.getBankLimit())); } } }); } else { this.bankLimit.set(Value.fixed(bankLimit)); } // Trying to give interest again if the last one failed. if (hasGiveInterestFailed()) giveInterest(false); IslandsDatabaseBridge.saveBankLimit(this); } @Override public BigDecimal getBankLimitRaw() { return this.bankLimit.readAndGet(bankLimit -> bankLimit.getNonSynced(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE)); } @Override public boolean giveInterest(boolean checkOnlineOwner) { Log.debug(Debug.GIVE_BANK_INTEREST, owner.getName()); long currentTime = System.currentTimeMillis() / 1000; int bankInterestRecentActive = BuiltinModules.BANK.getConfiguration().getBankInterestRecentActive(); if (checkOnlineOwner && bankInterestRecentActive > 0 && !owner.isOnline() && currentTime - owner.getLastTimeStatus() > bankInterestRecentActive) { Log.debugResult(Debug.GIVE_BANK_INTEREST, "Return Cooldown", owner.getName()); return false; } int bankInterestPercentage = BuiltinModules.BANK.getConfiguration().getBankInterestPercentage(); BigDecimal balance = islandBank.getBalance().max(BigDecimal.ONE); BigDecimal balanceToGive = balance.multiply(new BigDecimal(bankInterestPercentage / 100D)); // If the money that will be given exceeds limit, we want to give money later. if (!islandBank.canDepositMoney(balanceToGive)) { Log.debugResult(Debug.GIVE_BANK_INTEREST, "Return Cannot Deposit Money", owner.getName()); giveInterestFailed = true; return false; } Log.debugResult(Debug.GIVE_BANK_INTEREST, "Return Success", owner.getName()); giveInterestFailed = false; islandBank.depositAdminMoney(Bukkit.getConsoleSender(), balanceToGive); setLastInterestTime(currentTime); return true; } @Override public long getLastInterestTime() { return lastInterest; } @Override public void setLastInterestTime(long lastInterest) { if (this.lastInterest == lastInterest) return; if (BuiltinModules.BANK.getConfiguration().isBankInterestEnabled()) { long ticksToNextInterest = BuiltinModules.BANK.getConfiguration().getBankInterestInterval() * 20L; resetBankInterestTask(ticksToNextInterest); } this.lastInterest = lastInterest; IslandsDatabaseBridge.saveLastInterestTime(this); } @Override public long getNextInterest() { long currentTime = System.currentTimeMillis() / 1000; int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval(); return bankInterestInterval - (currentTime - lastInterest); } private void resetBankInterestTask(long ticksToNextInterest) { this.bankInterestTask.set(bankInterestTask -> { if (bankInterestTask != null) bankInterestTask.cancel(); return registerTask(BukkitExecutor.sync(() -> giveInterest(true), ticksToNextInterest)); }); } /* * Worth related methods */ @Override public void handleBlockPlace(Block block) { handleBlockPlace(block, 1); } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block) { return handleBlockPlaceWithResult(block, 1); } @Override public void handleBlockPlace(Key key) { handleBlockPlace(key, 1); } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key) { return handleBlockPlaceWithResult(key, 1); } @Override public void handleBlockPlace(Block block, @Size int amount) { handleBlockPlace(block, amount, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount) { return handleBlockPlaceWithResult(block, amount, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public void handleBlockPlace(Key key, @Size int amount) { handleBlockPlace(key, amount, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount) { return handleBlockPlaceWithResult(key, amount, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public void handleBlockPlace(Block block, @Size int amount, @IslandBlockFlags int flags) { Preconditions.checkNotNull(block, "block parameter cannot be null."); handleBlockPlace(Keys.of(block), amount, flags); } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount, @IslandBlockFlags int flags) { Preconditions.checkNotNull(block, "block parameter cannot be null."); return handleBlockPlaceWithResult(Keys.of(block), amount, flags); } @Override public void handleBlockPlace(Key key, @Size int amount, @IslandBlockFlags int flags) { handleBlockPlaceWithResult(key, amount, flags); } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @IslandBlockFlags int flags) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkArgument(amount > 0, "amount parameter must be positive."); BigInteger amountBig = BigInteger.valueOf(amount); return handleBlockPlaceInternal(key, amountBig, flags); } private BlockChangeResult handleBlockPlaceInternal(Key key, @Size BigInteger amount, @IslandBlockFlags int flags) { boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0; boolean trackedBlock = accessBlocksTracker(rawBlocks, blocksTracker -> blocksTracker.trackBlock(key, amount)); if (!trackedBlock) return BlockChangeResult.MISSING_BLOCK_VALUE; BigInteger newTotalBlocksCount = this.currentTotalBlockCounts.updateAndGet(count -> count.add(amount)); BigDecimal oldWorth = getWorth(); BigDecimal oldLevel = getIslandLevel(); BlockValue blockValue = plugin.getBlockValues().getBlockValue(key); BigDecimal blockWorth = blockValue.getWorth(); BigDecimal blockLevel = blockValue.getLevel(); boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0; boolean updateLastTimeStatus = (flags & IslandBlockFlags.UPDATE_LAST_TIME_STATUS) != 0; if (blockWorth.compareTo(BigDecimal.ZERO) != 0) { islandWorth.updateAndGet(islandWorth -> islandWorth.add(blockWorth.multiply(new BigDecimal(amount)))); if (saveBlockCounts) plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this); } if (blockLevel.compareTo(BigDecimal.ZERO) != 0) { islandLevel.updateAndGet(islandLevel -> islandLevel.add(blockLevel.multiply(new BigDecimal(amount)))); if (saveBlockCounts) plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this); } if (updateLastTimeStatus) updateLastTime(); if (saveBlockCounts) saveBlockCounts(newTotalBlocksCount, oldWorth, oldLevel); return BlockChangeResult.SUCCESS; } @Override @Deprecated public void handleBlockPlace(Block block, @Size int amount, boolean save) { int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS; if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS; handleBlockPlace(block, amount, flags); } @Override @Deprecated public void handleBlockPlace(Key key, @Size int amount, boolean save) { int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS; if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS; handleBlockPlace(key, amount, flags); } @Override @Deprecated public void handleBlockPlace(Key key, @Size BigInteger amount, boolean save) { Preconditions.checkNotNull(key, "key argument cannot be null"); Preconditions.checkNotNull(amount, "amount argument cannot be null"); int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS; if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS; handleBlockPlace(key, amount, flags); } @Override @Deprecated public void handleBlockPlace(Key key, @Size BigInteger amount, boolean save, boolean updateLastTimeStatus) { Preconditions.checkNotNull(key, "key argument cannot be null"); Preconditions.checkNotNull(amount, "amount argument cannot be null"); int flags = 0; if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS; if (updateLastTimeStatus) flags |= IslandBlockFlags.UPDATE_LAST_TIME_STATUS; handleBlockPlace(key, amount, flags); } @Deprecated private void handleBlockPlace(Key key, @Size BigInteger amount, @IslandBlockFlags int flags) { BigInteger MAX_INT_VALUE = BigInteger.valueOf(Integer.MAX_VALUE); while (amount.compareTo(MAX_INT_VALUE) > 0) { handleBlockPlace(key, Integer.MAX_VALUE, flags); amount = amount.subtract(MAX_INT_VALUE); } handleBlockPlace(key, amount.intValueExact(), flags); } @Override public void handleBlocksPlace(Map blocks) { handleBlocksPlace(blocks, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public Map handleBlocksPlaceWithResult(Map blocks) { return handleBlocksPlaceWithResult(blocks, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public void handleBlocksPlace(Map blocks, @IslandBlockFlags int flags) { handleBlocksPlaceWithResult(blocks, flags); } @Override public Map handleBlocksPlaceWithResult(Map blocks, @IslandBlockFlags int flags) { Preconditions.checkNotNull(blocks, "blocks parameter cannot be null."); if (blocks.isEmpty()) return KeyMaps.createEmptyMap(); BigDecimal oldWorth = getWorth(); BigDecimal oldLevel = getIslandLevel(); boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0; KeyMap result = accessBlocksTracker(rawBlocks, blocksTracker -> { KeyMap resultMap = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); blocks.forEach((blockKey, amount) -> { BlockChangeResult blockResult = handleBlockPlaceWithResult(blockKey, amount, 0); if (blockResult != BlockChangeResult.SUCCESS) resultMap.put(blockKey, blockResult); }); return resultMap.isEmpty() ? KeyMaps.createEmptyMap() : KeyMaps.unmodifiableKeyMap(resultMap); }); boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0; boolean updateLastTimeStatus = (flags & IslandBlockFlags.UPDATE_LAST_TIME_STATUS) != 0; if (saveBlockCounts) saveBlockCounts(this.currentTotalBlockCounts.get(), oldWorth, oldLevel); if (updateLastTimeStatus) updateLastTime(); return result; } @Override public void handleBlockBreak(Block block) { handleBlockBreak(block, 1); } @Override public BlockChangeResult handleBlockBreakWithResult(Block block) { return handleBlockBreakWithResult(block, 1); } @Override public void handleBlockBreak(Key key) { handleBlockBreak(key, 1); } @Override public BlockChangeResult handleBlockBreakWithResult(Key key) { return handleBlockBreakWithResult(key, 1); } @Override public void handleBlockBreak(Block block, @Size int amount) { handleBlockBreak(block, amount, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount) { return handleBlockBreakWithResult(block, amount, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public void handleBlockBreak(Key key, @Size int amount) { handleBlockBreak(key, amount, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount) { return handleBlockBreakWithResult(key, amount, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public void handleBlockBreak(Block block, @Size int amount, @IslandBlockFlags int flags) { Preconditions.checkNotNull(block, "block parameter cannot be null."); handleBlockBreak(Keys.of(block), amount, flags); } @Override public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount, int flags) { Preconditions.checkNotNull(block, "block parameter cannot be null."); return handleBlockBreakWithResult(Keys.of(block), amount, flags); } @Override public void handleBlockBreak(Key key, @Size int amount, @IslandBlockFlags int flags) { handleBlockBreakWithResult(key, amount, flags); } @Override public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, int flags) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkArgument(amount > 0, "amount parameter must be positive."); BigInteger amountBig = BigInteger.valueOf(amount); boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0; boolean untrackedBlocks = accessBlocksTracker(rawBlocks, blocksTracker -> blocksTracker.untrackBlock(key, amountBig)); if (!untrackedBlocks) return BlockChangeResult.MISSING_BLOCK_VALUE; BigInteger newTotalBlocksCount = this.currentTotalBlockCounts.updateAndGet(count -> count.subtract(amountBig)); BigDecimal oldWorth = getWorth(), oldLevel = getIslandLevel(); BlockValue blockValue = plugin.getBlockValues().getBlockValue(key); BigDecimal blockWorth = blockValue.getWorth(); BigDecimal blockLevel = blockValue.getLevel(); boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0; boolean updateLastTimeStatus = (flags & IslandBlockFlags.UPDATE_LAST_TIME_STATUS) != 0; if (blockWorth.compareTo(BigDecimal.ZERO) != 0) { this.islandWorth.updateAndGet(islandWorth -> islandWorth.subtract(blockWorth.multiply(new BigDecimal(amount)))); if (saveBlockCounts) plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this); } if (blockLevel.compareTo(BigDecimal.ZERO) != 0) { this.islandLevel.updateAndGet(islandLevel -> islandLevel.subtract(blockLevel.multiply(new BigDecimal(amount)))); if (saveBlockCounts) plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this); } if (updateLastTimeStatus) updateLastTime(); if (saveBlockCounts) saveBlockCounts(newTotalBlocksCount, oldWorth, oldLevel); return BlockChangeResult.SUCCESS; } @Override @Deprecated public void handleBlockBreak(Block block, @Size int amount, boolean save) { int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS; if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS; handleBlockBreak(block, amount, flags); } @Override @Deprecated public void handleBlockBreak(Key key, @Size int amount, boolean save) { int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS; if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS; handleBlockBreak(key, amount, flags); } @Override @Deprecated public void handleBlockBreak(Key key, @Size BigInteger amount, boolean save) { Preconditions.checkNotNull(key, "key argument cannot be null"); Preconditions.checkNotNull(amount, "amount argument cannot be null"); int flags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS; if (save) flags |= IslandBlockFlags.SAVE_BLOCK_COUNTS; BigInteger MAX_INT_VALUE = BigInteger.valueOf(Integer.MAX_VALUE); while (amount.compareTo(MAX_INT_VALUE) > 0) { handleBlockBreak(key, Integer.MAX_VALUE, flags); amount = amount.subtract(MAX_INT_VALUE); } handleBlockBreak(key, amount.intValueExact(), flags); } @Override public void handleBlocksBreak(Map blocks) { handleBlocksBreak(blocks, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public Map handleBlocksBreakWithResult(Map blocks) { return handleBlocksBreakWithResult(blocks, IslandBlockFlags.SAVE_BLOCK_COUNTS | IslandBlockFlags.UPDATE_LAST_TIME_STATUS); } @Override public void handleBlocksBreak(Map blocks, @IslandBlockFlags int flags) { handleBlocksBreakWithResult(blocks, flags); } @Override public Map handleBlocksBreakWithResult(Map blocks, int flags) { Preconditions.checkNotNull(blocks, "blocks parameter cannot be null."); if (blocks.isEmpty()) return KeyMaps.createEmptyMap(); BigDecimal oldWorth = getWorth(); BigDecimal oldLevel = getIslandLevel(); boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0; KeyMap result = accessBlocksTracker(rawBlocks, blocksTracker -> { KeyMap resultMap = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); blocks.forEach((blockKey, amount) -> { BlockChangeResult blockResult = handleBlockBreakWithResult(blockKey, amount, 0); if (blockResult != BlockChangeResult.SUCCESS) resultMap.put(blockKey, blockResult); }); return resultMap.isEmpty() ? KeyMaps.createEmptyMap() : KeyMaps.unmodifiableKeyMap(resultMap); }); boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0; boolean updateLastTimeStatus = (flags & IslandBlockFlags.UPDATE_LAST_TIME_STATUS) != 0; if (saveBlockCounts) saveBlockCounts(this.currentTotalBlockCounts.get(), oldWorth, oldLevel); if (updateLastTimeStatus) updateLastTime(); return result; } @Override public boolean isChunkDirty(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); return this.isChunkDirty(world.getName(), chunkX, chunkZ); } @Override public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null."); return isChunkDirty(plugin.getGrid().getIslandsWorldInfo(this, worldName), chunkX, chunkZ); } @Override public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) { Preconditions.checkArgument(worldInfo != null && isInside(chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); } } @Override public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); markChunkDirty(WorldInfo.of(world), chunkX, chunkZ, save); } @Override public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk {" + worldInfo.getName() + "," + chunkX + "," + chunkZ + "} must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markDirty(chunkPosition, save); } } @Override public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); markChunkEmpty(WorldInfo.of(world), chunkX, chunkZ, save); } @Override public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk {" + worldInfo.getName() + "," + chunkX + "," + chunkZ + "} must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markEmpty(chunkPosition, save); } } @Override public BigInteger getBlockCountAsBigInteger(Key key) { return this.blocksTracker.getBlockCount(key); } @Override public Map getBlockCountsAsBigInteger() { return this.blocksTracker.getBlockCounts(); } @Override public BigInteger getExactBlockCountAsBigInteger(Key key) { return this.blocksTracker.getExactBlockCount(key); } @Override public void clearBlockCounts() { blocksTracker.clearBlockCounts(); this.currentTotalBlockCounts.set(BigInteger.ZERO); islandWorth.set(BigDecimal.ZERO); islandLevel.set(BigDecimal.ZERO); plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this); plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this); } @Override public IslandBlocksTrackerAlgorithm getBlocksTracker() { return this.blocksTracker; } @Override public BigDecimal getWorth() { double bankWorthRate = BuiltinModules.BANK.getConfiguration().getBankWorthRate(); BigDecimal islandWorth = this.islandWorth.get(); BigDecimal islandBank = this.islandBank.getBalance(); BigDecimal bonusWorth = this.bonusWorth.get(); BigDecimal finalIslandWorth = (bankWorthRate <= 0 ? getRawWorth() : islandWorth.add( islandBank.multiply(BigDecimal.valueOf(bankWorthRate)))).add(bonusWorth); if (!plugin.getSettings().isNegativeWorth() && finalIslandWorth.compareTo(BigDecimal.ZERO) < 0) return BigDecimal.ZERO; return finalIslandWorth; } @Override public BigDecimal getRawWorth() { return islandWorth.get(); } @Override public BigDecimal getBonusWorth() { return bonusWorth.get(); } @Override public void setBonusWorth(BigDecimal bonusWorth) { Preconditions.checkNotNull(bonusWorth, "bonusWorth parameter cannot be null."); Log.debug(Debug.SET_BONUS_WORTH, owner.getName(), bonusWorth); BigDecimal oldBonusWorth = this.bonusWorth.getAndSet(bonusWorth); if (Objects.equals(oldBonusWorth, bonusWorth)) return; plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_WORTH, this); plugin.getGrid().sortIslands(SortingTypes.BY_WORTH); IslandsDatabaseBridge.saveBonusWorth(this); } @Override public BigDecimal getBonusLevel() { return bonusLevel.get(); } @Override public void setBonusLevel(BigDecimal bonusLevel) { Preconditions.checkNotNull(bonusLevel, "bonusLevel parameter cannot be null."); Log.debug(Debug.SET_BONUS_LEVEL, owner.getName(), bonusLevel); BigDecimal oldBonusLevel = this.bonusLevel.getAndSet(bonusLevel); if (Objects.equals(oldBonusLevel, bonusLevel)) return; plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_LEVEL, this); plugin.getGrid().sortIslands(SortingTypes.BY_LEVEL); IslandsDatabaseBridge.saveBonusLevel(this); } @Override public BigDecimal getIslandLevel() { BigDecimal bonusLevel = this.bonusLevel.get(); BigDecimal islandLevel = this.islandLevel.get().add(bonusLevel); if (plugin.getSettings().isRoundedIslandLevels()) { islandLevel = islandLevel.setScale(0, plugin.getSettings().getIslandLevelRoundingMode()); } if (!plugin.getSettings().isNegativeLevel() && islandLevel.compareTo(BigDecimal.ZERO) < 0) islandLevel = BigDecimal.ZERO; return islandLevel; } @Override public BigDecimal getRawLevel() { BigDecimal islandLevel = this.islandLevel.get(); if (plugin.getSettings().isRoundedIslandLevels()) { islandLevel = islandLevel.setScale(0, plugin.getSettings().getIslandLevelRoundingMode()); } if (!plugin.getSettings().isNegativeLevel() && islandLevel.compareTo(BigDecimal.ZERO) < 0) islandLevel = BigDecimal.ZERO; return islandLevel; } @Override public UpgradeLevel getUpgradeLevel(Upgrade upgrade) { Preconditions.checkNotNull(upgrade, "upgrade parameter cannot be null."); return upgrade.getUpgradeLevel(getUpgrades().getOrDefault(upgrade.getName(), 1)); } @Override public void setUpgradeLevel(Upgrade upgrade, int level) { Preconditions.checkNotNull(upgrade, "upgrade parameter cannot be null."); Log.debug(Debug.SET_UPGRADE, owner.getName(), upgrade.getName(), level); int currentLevel = getUpgradeLevel(upgrade).getLevel(); if (currentLevel == level) return; this.upgrades.setUpgradeLevel(upgrade, level); lastUpgradeTime = System.currentTimeMillis(); IslandsDatabaseBridge.saveUpgrade(this, upgrade, level); UpgradeLevel upgradeLevel = getUpgradeLevel(upgrade); // Level was downgraded, we need to clear the values of that level and sync all upgrades again if (currentLevel > level) { syncUpgrades(false); } else { syncUpgrade((SUpgradeLevel) upgradeLevel, false); } plugin.getMenus().refreshUpgrades(this); } @Override public Map getUpgrades() { return this.upgrades.getUpgrades(); } @Override public void syncUpgrades() { syncUpgrades(true); } /* * Upgrade related methods */ @Override public void updateUpgrades() { clearUpgrades(false); // We want to sync the default upgrade first, then the actual upgrades syncUpgrade(DefaultUpgradeLevel.getInstance(), false); // Syncing all real upgrades plugin.getUpgrades().getUpgrades().forEach(upgrade -> syncUpgrade((SUpgradeLevel) getUpgradeLevel(upgrade), false)); } @Override public long getLastTimeUpgrade() { return lastUpgradeTime; } @Override public boolean hasActiveUpgradeCooldown() { long lastTimeUpgrade = getLastTimeUpgrade(); long currentTime = System.currentTimeMillis(); long upgradeCooldown = plugin.getSettings().getUpgradeCooldown(); return upgradeCooldown > 0 && lastTimeUpgrade > 0 && currentTime - lastTimeUpgrade <= upgradeCooldown; } @Override public double getCropGrowthMultiplier() { return this.cropGrowth.readAndGet(DoubleValue::get); } @Override public void setCropGrowthMultiplier(double cropGrowth) { cropGrowth = Math.max(1, cropGrowth); Log.debug(Debug.SET_CROP_GROWTH, owner.getName(), cropGrowth); if (cropGrowth == getCropGrowthRaw()) return; DoubleValue oldCropGrowth = this.cropGrowth.set(DoubleValue.fixed(cropGrowth)); if (cropGrowth == DoubleValue.getNonSynced(oldCropGrowth, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveCropGrowth(this); notifyCropGrowthChange(cropGrowth); } @Override public double getCropGrowthRaw() { return this.cropGrowth.readAndGet(cropGrowth -> cropGrowth.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override public double getSpawnerRatesMultiplier() { return this.spawnerRates.readAndGet(DoubleValue::get); } @Override public void setSpawnerRatesMultiplier(double spawnerRates) { spawnerRates = Math.max(1, spawnerRates); Log.debug(Debug.SET_SPAWNER_RATES, owner.getName(), spawnerRates); DoubleValue oldSpawnerRates = this.spawnerRates.set(DoubleValue.fixed(spawnerRates)); if (spawnerRates == DoubleValue.getNonSynced(oldSpawnerRates, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveSpawnerRates(this); } @Override public double getSpawnerRatesRaw() { return this.spawnerRates.readAndGet(spawnerRates -> spawnerRates.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override public double getMobDropsMultiplier() { return this.mobDrops.readAndGet(DoubleValue::get); } @Override public void setMobDropsMultiplier(double mobDrops) { mobDrops = Math.max(1, mobDrops); Log.debug(Debug.SET_MOB_DROPS, owner.getName(), mobDrops); DoubleValue oldMobDrops = this.mobDrops.set(DoubleValue.fixed(mobDrops)); if (mobDrops == DoubleValue.getNonSynced(oldMobDrops, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveMobDrops(this); } @Override public double getMobDropsRaw() { return this.mobDrops.readAndGet(mobDrops -> mobDrops.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override public int getBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); IntValue blockLimit = blockLimits.get(key); return blockLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : blockLimit.get(); } @Override public int getExactBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); IntValue blockLimit = blockLimits.getRaw(key, null); return blockLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : blockLimit.get(); } @Override public Key getBlockLimitKey(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return blockLimits.getKey(key, key); } @Override public Map getBlocksLimits() { KeyMap blockLimits = KeyMap.createKeyMap(); this.blockLimits.forEach((block, limit) -> blockLimits.put(block, limit.get())); return Collections.unmodifiableMap(blockLimits); } @Override public Map getCustomBlocksLimits() { return Collections.unmodifiableMap(this.blockLimits.entrySet().stream() .filter(entry -> !entry.getValue().isSynced()) .collect(KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get()))); } @Override public void clearBlockLimits() { Log.debug(Debug.CLEAR_BLOCK_LIMITS, owner.getName()); if (blockLimits.isEmpty()) return; blockLimits.clear(); IslandsDatabaseBridge.clearBlockLimits(this); } @Override public void setBlockLimit(Key key, int limit) { Preconditions.checkNotNull(key, "key parameter cannot be null."); int finalLimit = Math.max(0, limit); Log.debug(Debug.SET_BLOCK_LIMIT, owner.getName(), key, finalLimit); IntValue oldLimit = blockLimits.put(key, IntValue.fixed(finalLimit)); if (limit == IntValue.getNonSynced(oldLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; plugin.getBlockValues().addCustomBlockKey(key); IslandsDatabaseBridge.saveBlockLimit(this, key, limit); } @Override public void removeBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Log.debug(Debug.REMOVE_BLOCK_LIMIT, owner.getName(), key); IntValue oldBlockLimit = blockLimits.remove(key); if (oldBlockLimit == null) return; IslandsDatabaseBridge.removeBlockLimit(this, key); } @Override public boolean hasReachedBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return hasReachedBlockLimit(key, 1); } @Override public boolean hasReachedBlockLimit(Key key, @Size int amount) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkArgument(amount >= 0, "amount parameter must be non-negative."); int blockLimit = getExactBlockLimit(key); //Checking for the specific provided key. if (blockLimit >= 0) { return getBlockCountAsBigInteger(key).add(BigInteger.valueOf(amount)) .compareTo(BigInteger.valueOf(blockLimit)) > 0; } //Getting the global key values. key = ((BaseKey) key).toGlobalKey(); blockLimit = getBlockLimit(key); return blockLimit >= 0 && getBlockCountAsBigInteger(key) .add(BigInteger.valueOf(amount)).compareTo(BigInteger.valueOf(blockLimit)) > 0; } @Override public int getEntityLimit(EntityType entityType) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null."); return getEntityLimit(Keys.of(entityType)); } @Override public int getEntityLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); IntValue entityLimit = entityLimits.get(key); return entityLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : entityLimit.get(); } @Override public Map getEntitiesLimitsAsKeys() { return Collections.unmodifiableMap(this.entityLimits.entrySet().stream().collect( KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get()) )); } @Override public Map getCustomEntitiesLimits() { return Collections.unmodifiableMap(this.entityLimits.entrySet().stream() .filter(entry -> !entry.getValue().isSynced()) .collect(KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get()))); } @Override public void clearEntitiesLimits() { Log.debug(Debug.CLEAR_ENTITY_LIMITS, owner.getName()); if (entityLimits.isEmpty()) return; entityLimits.clear(); IslandsDatabaseBridge.clearEntityLimits(this); } @Override public void setEntityLimit(EntityType entityType, int limit) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null."); setEntityLimit(Keys.of(entityType), limit); } @Override public void setEntityLimit(Key key, int limit) { Preconditions.checkNotNull(key, "key parameter cannot be null."); int finalLimit = Math.max(0, limit); Log.debug(Debug.SET_ENTITY_LIMIT, owner.getName(), key, finalLimit); IntValue oldEntityLimit = entityLimits.put(key, IntValue.fixed(limit)); if (limit == IntValue.getNonSynced(oldEntityLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveEntityLimit(this, key, limit); } @Override public void removeEntityLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Log.debug(Debug.REMOVE_ENTITY_LIMIT, owner.getName(), key); IntValue oldEntityLimit = entityLimits.remove(key); if (oldEntityLimit == null) return; IslandsDatabaseBridge.removeEntityLimit(this, key); } @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null."); return hasReachedEntityLimit(Keys.of(entityType)); } @Override public CompletableFuture hasReachedEntityLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return hasReachedEntityLimit(key, 1); } @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType, @Size int amount) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null."); return hasReachedEntityLimit(Keys.of(entityType), amount); } @Override public CompletableFuture hasReachedEntityLimit(Key key, @Size int amount) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkArgument(amount >= 0, "amount parameter must be non-negative."); int entityLimit = getEntityLimit(key); if (entityLimit < 0) return CompletableFuture.completedFuture(false); return CompletableFuture.completedFuture(this.entitiesTracker.getEntityCount(key) + amount > entityLimit); } @Override public IslandEntitiesTrackerAlgorithm getEntitiesTracker() { return this.entitiesTracker; } @Override public int getTeamLimit() { return this.teamLimit.readAndGet(IntValue::get); } @Override public void setTeamLimit(int teamLimit) { teamLimit = Math.max(0, teamLimit); Log.debug(Debug.SET_TEAM_LIMIT, owner.getName(), teamLimit); IntValue oldTeamLimit = this.teamLimit.set(IntValue.fixed(teamLimit)); if (teamLimit == IntValue.getNonSynced(oldTeamLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveTeamLimit(this); } @Override public int getTeamLimitRaw() { return this.teamLimit.readAndGet(teamLimit -> teamLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override public int getWarpsLimit() { return this.warpsLimit.readAndGet(IntValue::get); } @Override public void setWarpsLimit(int warpsLimit) { warpsLimit = Math.max(0, warpsLimit); Log.debug(Debug.SET_WARPS_LIMIT, owner.getName(), warpsLimit); IntValue oldWarpsLimit = this.warpsLimit.set(IntValue.fixed(warpsLimit)); if (warpsLimit == IntValue.getNonSynced(oldWarpsLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveWarpsLimit(this); } @Override public int getWarpsLimitRaw() { return this.warpsLimit.readAndGet(warpsLimit -> warpsLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override public void setPotionEffect(PotionEffectType type, int level) { // Legacy support for levels can be set to <= 0 for removing the effect. // Nowadays, removePotionEffect exists. if (level <= 0) { removePotionEffect(type); return; } Preconditions.checkNotNull(type, "potionEffectType parameter cannot be null."); Log.debug(Debug.SET_ISLAND_EFFECT, owner.getName(), type.getName(), level); IntValue oldPotionLevel = islandEffects.put(type, IntValue.fixed(level)); if (level == IntValue.getNonSynced(oldPotionLevel, IslandUpgradeConstants.SYNCED_VALUE)) return; registerTask(BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); assert player != null; if (oldPotionLevel != null && oldPotionLevel.get() > level) player.removePotionEffect(type); PotionEffect potionEffect = new PotionEffect(type, Integer.MAX_VALUE, level - 1); player.addPotionEffect(potionEffect, true); }))); IslandsDatabaseBridge.saveIslandEffect(this, type, level); } @Override public void removePotionEffect(PotionEffectType type) { Preconditions.checkNotNull(type, "potionEffectType parameter cannot be null."); Log.debug(Debug.REMOVE_ISLAND_EFFECT, owner.getName(), type.getName()); IntValue oldEffectLevel = islandEffects.remove(type); if (oldEffectLevel == null) return; registerTask(BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.removePotionEffect(type); }))); IslandsDatabaseBridge.removeIslandEffect(this, type); } @Override public int getPotionEffectLevel(PotionEffectType type) { Preconditions.checkNotNull(type, "potionEffectType parameter cannot be null."); IntValue islandEffect = islandEffects.get(type); return islandEffect == null ? 0 : islandEffect.get(); } @Override public Map getPotionEffects() { Map islandEffects = new ArrayMap<>(); this.islandEffects.forEach((potionEffectType, levelValue) -> { int level = levelValue.get(); if (level > 0) islandEffects.put(potionEffectType, level); }); return islandEffects.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandEffects); } @Override public Map getCustomPotionEffects() { Map islandEffects = new ArrayMap<>(); this.islandEffects.forEach((potionEffectType, levelValue) -> { int level = levelValue.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE); if (level > 0) islandEffects.put(potionEffectType, level); }); return islandEffects.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandEffects); } @Override public void applyEffects(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class)) return; applyEffectsNoUpgradeCheck(superiorPlayer); } @Override public void applyEffects() { if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class)) getAllPlayersInside().forEach(this::applyEffectsNoUpgradeCheck); } @Override public void removeEffects(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class)) removeEffectsNoUpgradeCheck(superiorPlayer); } @Override public void removeEffects() { if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class)) getAllPlayersInside().forEach(this::removeEffectsNoUpgradeCheck); } @Override public void clearEffects() { Log.debug(Debug.CLEAR_ISLAND_EFFECTS, owner.getName()); if (islandEffects.isEmpty()) return; islandEffects.clear(); removeEffects(); IslandsDatabaseBridge.clearIslandEffects(this); } @Override public void setRoleLimit(PlayerRole playerRole, int limit) { // Legacy support for limits can be set to < 0 for removing the limit. // Nowadays, removeRoleLimit exists. if (limit < 0) { removeRoleLimit(playerRole); return; } Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); Log.debug(Debug.SET_ROLE_LIMIT, owner.getName(), playerRole.getName(), limit); IntValue oldRoleLimit = roleLimits.writeAndGet(roleLimits -> roleLimits.put(playerRole.getId(), IntValue.fixed(limit))); if (limit == IntValue.getNonSynced(oldRoleLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveRoleLimit(this, playerRole, limit); } @Override public void removeRoleLimit(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); Log.debug(Debug.REMOVE_ROLE_LIMIT, owner.getName(), playerRole.getName()); IntValue oldRoleLimit = roleLimits.writeAndGet(roleLimits -> roleLimits.remove(playerRole.getId())); if (oldRoleLimit == null) return; IslandsDatabaseBridge.removeRoleLimit(this, playerRole); } @Override public int getRoleLimit(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); IntValue roleLimit = roleLimits.readAndGet(roleLimits -> roleLimits.get(playerRole.getId())); return roleLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : roleLimit.get(); } @Override public int getRoleLimitRaw(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); return IntValue.getNonSynced(roleLimits.readAndGet(roleLimits -> roleLimits.get(playerRole.getId())), IslandUpgradeConstants.SYNCED_VALUE); } @Override public Map getRoleLimits() { if (this.roleLimits.readAndGet(Int2ObjectMapView::isEmpty)) return Collections.emptyMap(); Map roleLimits = new HashMap<>(); this.roleLimits.read(roleLimitsMap -> { Iterator> iterator = roleLimitsMap.entryIterator(); while (iterator.hasNext()) { Int2ObjectMapView.Entry entry = iterator.next(); roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get()); } }); return Collections.unmodifiableMap(roleLimits); } @Override public Map getCustomRoleLimits() { if (this.roleLimits.readAndGet(Int2ObjectMapView::isEmpty)) return Collections.emptyMap(); Map roleLimits = new HashMap<>(); this.roleLimits.read(roleLimitsMap -> { Iterator> iterator = roleLimitsMap.entryIterator(); while (iterator.hasNext()) { Int2ObjectMapView.Entry entry = iterator.next(); if (!entry.getValue().isSynced()) roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get()); } }); return Collections.unmodifiableMap(roleLimits); } @Override public WarpCategory createWarpCategory(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Log.debug(Debug.CREATE_WARP_CATEGORY, owner.getName(), name); WarpCategory warpCategory = warpCategories.get(name.toLowerCase(Locale.ENGLISH)); if (warpCategory == null) { Log.debugResult(Debug.CREATE_WARP_CATEGORY, "Result New Category", name); List occupiedSlots = warpCategories.values().stream().map(WarpCategory::getSlot).collect(Collectors.toList()); int slot = 0; while (occupiedSlots.contains(slot)) ++slot; warpCategory = loadWarpCategory(name, slot, null); IslandsDatabaseBridge.saveWarpCategory(this, warpCategory); plugin.getMenus().refreshWarpCategories(this); } else { Log.debugResult(Debug.CREATE_WARP_CATEGORY, "Result Already Exists", name); } return warpCategory; } @Override public WarpCategory getWarpCategory(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); return warpCategories.get(name.toLowerCase(Locale.ENGLISH)); } @Override public WarpCategory getWarpCategory(int slot) { return warpCategories.values().stream().filter(warpCategory -> warpCategory.getSlot() == slot) .findAny().orElse(null); } @Override public void renameCategory(WarpCategory warpCategory, String newName) { Preconditions.checkNotNull(warpCategory, "warpCategory parameter cannot be null."); Preconditions.checkNotNull(newName, "newName parameter cannot be null."); warpCategories.remove(warpCategory.getName().toLowerCase(Locale.ENGLISH)); warpCategories.put(newName.toLowerCase(Locale.ENGLISH), warpCategory); warpCategory.setName(newName); } @Override public void deleteCategory(WarpCategory warpCategory) { Preconditions.checkNotNull(warpCategory, "warpCategory parameter cannot be null."); Log.debug(Debug.DELETE_WARP_CATEGORY, owner.getName(), warpCategory.getName()); boolean validCategoryRemoval = warpCategories.remove(warpCategory.getName().toLowerCase(Locale.ENGLISH)) != null; if (!validCategoryRemoval) return; IslandsDatabaseBridge.removeWarpCategory(this, warpCategory); boolean shouldSaveWarps = !warpCategory.getWarps().isEmpty(); if (shouldSaveWarps) { new LinkedList<>(warpCategory.getWarps()).forEach(islandWarp -> deleteWarp(islandWarp.getName())); plugin.getMenus().destroyWarps(warpCategory); } plugin.getMenus().destroyWarpCategories(this); } @Override public Map getWarpCategories() { return Collections.unmodifiableMap(warpCategories); } @Override public IslandWarp createWarp(String name, Location location, @Nullable WarpCategory warpCategory) { Preconditions.checkNotNull(location, "location parameter cannot be null."); if (!(location instanceof LazyWorldLocation)) Preconditions.checkNotNull(location.getWorld(), "location's world cannot be null."); WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, LazyWorldLocation.getWorldName(location)); WorldPosition worldPosition = SWorldPosition.of(location); return createIslandInternal(name, worldInfo, worldPosition, warpCategory); } @Override public IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, @Nullable WarpCategory warpCategory) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); Preconditions.checkNotNull(position, "position parameter cannot be null."); return createIslandInternal(name, worldInfo, position, warpCategory); } private IslandWarp createIslandInternal(String name, WorldInfo worldInfo, WorldPosition worldPosition, @Nullable WarpCategory warpCategory) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkState(getWarp(name) == null, "Warp already exists: " + name); Log.debug(Debug.CREATE_WARP, owner.getName(), name, worldInfo, worldPosition, warpCategory); IslandWarp islandWarp = loadIslandWarp(name, worldInfo, worldPosition, warpCategory, !plugin.getSettings().isPublicWarps(), null); IslandsDatabaseBridge.saveWarp(this, islandWarp); plugin.getMenus().refreshGlobalWarps(); plugin.getMenus().refreshWarps(islandWarp.getCategory()); return islandWarp; } /* * Warps related methods */ @Override public void renameWarp(IslandWarp islandWarp, String newName) { Preconditions.checkNotNull(islandWarp, "islandWarp parameter cannot be null."); Preconditions.checkNotNull(newName, "newName parameter cannot be null."); Preconditions.checkArgument(IslandUtils.isWarpNameLengthValid(newName), "Warp names must cannot be longer than 255 chars."); Preconditions.checkState(getWarp(newName) == null, "Cannot rename warps to an already existing warps."); warpsByName.remove(islandWarp.getName().toLowerCase(Locale.ENGLISH)); warpsByName.put(newName.toLowerCase(Locale.ENGLISH), islandWarp); islandWarp.setName(newName); } @Override public IslandWarp getWarp(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); return this.warpsByLocation.readAndGet(warpsByLocation -> warpsByLocation.get(location)); } @Override public IslandWarp getWarp(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); return warpsByName.get(name.toLowerCase(Locale.ENGLISH)); } @Override public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) { warpPlayer(superiorPlayer, warpName, false); } @Override public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(warpName, "warp parameter cannot be null."); IslandWarp islandWarp = getWarp(warpName); if (islandWarp == null) { Message.INVALID_WARP.send(superiorPlayer, warpName); return; } if (!force && !superiorPlayer.hasBypassModeEnabled() && plugin.getSettings().getChargeOnWarp() > 0) { if (plugin.getProviders().getEconomyProvider().getBalance(superiorPlayer) .compareTo(BigDecimal.valueOf(plugin.getSettings().getChargeOnWarp())) < 0) { Message.NOT_ENOUGH_MONEY_TO_WARP.send(superiorPlayer); return; } plugin.getProviders().getEconomyProvider().withdrawMoney(superiorPlayer, plugin.getSettings().getChargeOnWarp()); } EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getWarpsWarmup(), unused -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp)); } @Override public void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); IslandWarp islandWarp = this.warpsByLocation.writeAndGet( warpsByLocation -> warpsByLocation.remove(location)); if (islandWarp == null) return; deleteWarp(islandWarp.getName()); if (superiorPlayer != null) Message.DELETE_WARP.send(superiorPlayer, islandWarp.getName()); } @Override public void deleteWarp(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Log.debug(Debug.DELETE_WARP, owner.getName(), name); IslandWarp islandWarp = warpsByName.remove(name.toLowerCase(Locale.ENGLISH)); WarpCategory warpCategory = islandWarp == null ? null : islandWarp.getCategory(); if (islandWarp != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { Location location = islandWarp.getLocation(wrapper.getHandle()); this.warpsByLocation.write(warpsByLocation -> warpsByLocation.remove(location)); } warpCategory.getWarps().remove(islandWarp); IslandsDatabaseBridge.removeWarp(this, islandWarp); if (warpCategory.getWarps().isEmpty()) deleteCategory(warpCategory); } plugin.getMenus().refreshGlobalWarps(); if (warpCategory != null) plugin.getMenus().refreshWarps(warpCategory); } @Override public Map getIslandWarps() { return Collections.unmodifiableMap(warpsByName); } @Override public Rating getRating(SuperiorPlayer superiorPlayer) { return ratings.getOrDefault(superiorPlayer.getUniqueId(), Rating.UNKNOWN); } @Override public void setRating(SuperiorPlayer superiorPlayer, Rating rating) { // Legacy support for rating can be set to UNKNOWN in order to remove rating. // Nowadays, removeRating exists. if (rating == Rating.UNKNOWN) { removeRating(superiorPlayer); return; } Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(rating, "rating parameter cannot be null."); Log.debug(Debug.SET_RATING, owner.getName(), superiorPlayer.getName(), rating); Rating oldRating = ratings.put(superiorPlayer.getUniqueId(), rating); if (rating == oldRating) return; plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this); IslandsDatabaseBridge.saveRating(this, superiorPlayer, rating, System.currentTimeMillis()); plugin.getMenus().refreshIslandRatings(this); } @Override public void removeRating(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Log.debug(Debug.REMOVE_RATING, owner.getName(), superiorPlayer.getName()); Rating oldRating = ratings.remove(superiorPlayer.getUniqueId()); if (oldRating == null) return; plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this); IslandsDatabaseBridge.removeRating(this, superiorPlayer); plugin.getMenus().refreshIslandRatings(this); } @Override public double getTotalRating() { double avg = 0; for (Rating rating : ratings.values()) avg += rating.getValue(); return avg == 0 ? 0 : avg / getRatingAmount(); } @Override public int getRatingAmount() { return ratings.size(); } @Override public Map getRatings() { return Collections.unmodifiableMap(ratings); } @Override public void removeRatings() { Log.debug(Debug.REMOVE_RATINGS, owner.getName()); if (ratings.isEmpty()) return; ratings.clear(); plugin.getGrid().getIslandsContainer().notifyChange(SortingTypes.BY_RATING, this); IslandsDatabaseBridge.clearRatings(this); plugin.getMenus().refreshIslandRatings(this); } @Override public boolean hasSettingsEnabled(IslandFlag settings) { Preconditions.checkNotNull(settings, "settings parameter cannot be null."); return islandFlags.getOrDefault(settings, (byte) (DEFAULT_FLAGS_CACHE.contains(settings) ? 1 : 0)) == 1; } @Override public Map getAllSettings() { return Collections.unmodifiableMap(islandFlags); } @Override public void enableSettings(IslandFlag settings) { Preconditions.checkNotNull(settings, "settings parameter cannot be null."); Log.debug(Debug.ENABLE_ISLAND_FLAG, owner.getName(), settings.getName()); Byte oldStatus = islandFlags.put(settings, (byte) 1); if (Objects.equals(oldStatus, 1)) return; boolean disableTime = false; boolean disableWeather = false; //Updating times / weather if necessary switch (settings.getName()) { case "ALWAYS_DAY": getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.setPlayerTime(0, false); }); disableTime = true; break; case "ALWAYS_MIDDLE_DAY": getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.setPlayerTime(6000, false); }); disableTime = true; break; case "ALWAYS_NIGHT": getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.setPlayerTime(14000, false); }); disableTime = true; break; case "ALWAYS_MIDDLE_NIGHT": getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.setPlayerTime(18000, false); }); disableTime = true; break; case "ALWAYS_SHINY": getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.setPlayerWeather(WeatherType.CLEAR); }); disableWeather = true; break; case "ALWAYS_RAIN": getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.setPlayerWeather(WeatherType.DOWNFALL); }); disableWeather = true; break; case "PVP": if (plugin.getSettings().isTeleportOnPvPEnable()) getIslandVisitors().forEach(superiorPlayer -> { superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); Message.ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE.send(superiorPlayer); }); break; } if (disableTime) { if (settings != IslandFlags.ALWAYS_DAY && islandFlags.remove(IslandFlags.ALWAYS_DAY) != null) IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_DAY); if (settings != IslandFlags.ALWAYS_MIDDLE_DAY && islandFlags.remove(IslandFlags.ALWAYS_MIDDLE_DAY) != null) IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_MIDDLE_DAY); if (settings != IslandFlags.ALWAYS_NIGHT && islandFlags.remove(IslandFlags.ALWAYS_NIGHT) != null) IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_NIGHT); if (settings != IslandFlags.ALWAYS_MIDDLE_NIGHT && islandFlags.remove(IslandFlags.ALWAYS_MIDDLE_NIGHT) != null) IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_MIDDLE_NIGHT); } if (disableWeather) { if (settings != IslandFlags.ALWAYS_RAIN && islandFlags.remove(IslandFlags.ALWAYS_RAIN) != null) IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_RAIN); if (settings != IslandFlags.ALWAYS_SHINY && islandFlags.remove(IslandFlags.ALWAYS_SHINY) != null) IslandsDatabaseBridge.removeIslandFlag(this, IslandFlags.ALWAYS_SHINY); } IslandsDatabaseBridge.saveIslandFlag(this, settings, 1); plugin.getMenus().refreshSettings(this); } /* * Ratings related methods */ @Override public void disableSettings(IslandFlag settings) { Preconditions.checkNotNull(settings, "settings parameter cannot be null."); Log.debug(Debug.DISABLE_ISLAND_FLAG, owner.getName(), settings.getName()); Byte oldStatus = islandFlags.put(settings, (byte) 0); if (Objects.equals(oldStatus, 0)) return; switch (settings.getName()) { case "ALWAYS_DAY": case "ALWAYS_MIDDLE_DAY": case "ALWAYS_NIGHT": case "ALWAYS_MIDDLE_NIGHT": getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.resetPlayerTime(); }); break; case "ALWAYS_RAIN": case "ALWAYS_SHINY": getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.resetPlayerWeather(); }); break; } IslandsDatabaseBridge.saveIslandFlag(this, settings, 0); plugin.getMenus().refreshSettings(this); } @Override public void resetSettings() { Log.debug(Debug.RESET_ISLAND_FLAGS, owner.getName()); if (islandFlags.isEmpty()) return; islandFlags.clear(); Long time = null; WeatherType weather = null; boolean enablePvP = false; for (String islandFlag : plugin.getSettings().getDefaultSettings()) { switch (islandFlag) { case "ALWAYS_DAY": time = 0L; break; case "ALWAYS_MIDDLE_DAY": time = 6000L; break; case "ALWAYS_NIGHT": time = 14000L; break; case "ALWAYS_MIDDLE_NIGHT": time = 18000L; break; case "ALWAYS_SHINY": weather = WeatherType.CLEAR; break; case "ALWAYS_RAIN": weather = WeatherType.DOWNFALL; break; case "PVP": enablePvP = true; break; } } boolean teleportOnPvPEnable = plugin.getSettings().isTeleportOnPvPEnable(); for (SuperiorPlayer superiorPlayer : getAllPlayersInside()) { Player player = superiorPlayer.asPlayer(); if (player != null) { if (time == null) player.resetPlayerTime(); else player.setPlayerTime(time, false); if (weather == null) player.resetPlayerWeather(); else player.setPlayerWeather(weather); if (enablePvP && teleportOnPvPEnable && isVisitor(superiorPlayer, false)) { superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); Message.ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE.send(superiorPlayer); } } } IslandsDatabaseBridge.clearIslandFlags(this); plugin.getMenus().refreshSettings(this); } @Override public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) { setGeneratorPercentage(key, percentage, dimension, null, false); } @Override public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension, @Nullable SuperiorPlayer caller, boolean callEvent) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Log.debug(Debug.SET_GENERATOR_PERCENTAGE, owner.getName(), key, percentage, dimension.getName(), caller, callEvent); KeyMap worldGeneratorRates = this.cobbleGeneratorValues.writeAndGet(cobbleGeneratorValues -> cobbleGeneratorValues.computeIfAbsent(dimension, e -> KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL))); Preconditions.checkArgument(percentage >= 0 && percentage <= 100, "Percentage must be between 0 and 100 - got " + percentage + "."); if (percentage == 0) { if (callEvent && !PluginEventsFactory.callIslandRemoveGeneratorRateEvent(this, caller, key, dimension)) return false; removeGeneratorAmount(key, dimension); } else if (percentage == 100) { KeyMap cobbleGeneratorValuesOriginal = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); cobbleGeneratorValuesOriginal.putAll(worldGeneratorRates); worldGeneratorRates.clear(); int generatorRate = 1; if (callEvent) { PluginEvent event = PluginEventsFactory.callIslandChangeGeneratorRateEvent(this, caller, key, dimension, generatorRate); if (event.isCancelled()) { // Restore the original values worldGeneratorRates.putAll(cobbleGeneratorValuesOriginal); return false; } generatorRate = event.getArgs().generatorRate; } setGeneratorAmount(key, generatorRate, dimension); } else { //Removing the key from the generator removeGeneratorAmount(key, dimension); int totalAmount = getGeneratorTotalAmount(dimension); double realPercentage = percentage / 100D; double amount = (realPercentage * totalAmount) / (1 - realPercentage); if (amount < 1) { worldGeneratorRates.entrySet().forEach(entry -> { int newAmount = entry.getValue().get() * 10; if (entry.getValue().isSynced()) { entry.setValue(IntValue.syncedFixed(newAmount)); } else { entry.setValue(IntValue.fixed(newAmount)); } }); amount *= 10; } PluginEvent event = PluginEventsFactory.callIslandChangeGeneratorRateEvent(this, caller, key, dimension, (int) Math.round(amount)); if (event.isCancelled()) return false; setGeneratorAmount(key, event.getArgs().generatorRate, dimension); } return true; } @Override public int getGeneratorPercentage(Key key, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); int totalAmount = getGeneratorTotalAmount(dimension); return totalAmount == 0 ? 0 : (getGeneratorAmount(key, dimension) * 100) / totalAmount; } @Override public Map getGeneratorPercentages(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); return getGeneratorAmounts(dimension).keySet().stream().collect(Collectors.toMap(key -> key, key -> getGeneratorAmount(Keys.ofMaterialAndData(key), dimension))); } @Override public void setGeneratorAmount(Key key, @Size int amount, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Preconditions.checkArgument(amount >= 0, "amount parameter must be non-negative."); Log.debug(Debug.SET_GENERATOR_RATE, owner.getName(), key, amount, dimension); KeyMap worldGeneratorRates = this.cobbleGeneratorValues.writeAndGet(cobbleGeneratorValues -> cobbleGeneratorValues.computeIfAbsent(dimension, e -> KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL))); IntValue oldGeneratorRate = worldGeneratorRates.put(key, IntValue.fixed(amount)); if (amount == IntValue.getNonSynced(oldGeneratorRate, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveGeneratorRate(this, dimension, key, amount); } @Override public void removeGeneratorAmount(Key key, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Log.debug(Debug.REMOVE_GENERATOR_RATE, owner.getName(), key, dimension); KeyMap worldGeneratorRates = this.cobbleGeneratorValues.readAndGet( cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension)); if (worldGeneratorRates == null) return; IntValue oldGeneratorRate = worldGeneratorRates.get(key); if (oldGeneratorRate == null || oldGeneratorRate.get() <= 0) return; if (oldGeneratorRate.isSynced()) { // In case the old rate was upgrade-synced, we want to keep it in DB and cache as a 0 rate. IslandsDatabaseBridge.saveGeneratorRate(this, dimension, key, 0); worldGeneratorRates.put(key, IntValue.fixed(0)); } else { IslandsDatabaseBridge.removeGeneratorRate(this, dimension, key); worldGeneratorRates.remove(key); } } @Override public int getGeneratorAmount(Key key, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); KeyMap worldGeneratorRates = this.cobbleGeneratorValues.readAndGet( cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension)); if (worldGeneratorRates == null) return 0; IntValue generatorRate = worldGeneratorRates.get(key); return generatorRate == null ? 0 : generatorRate.get(); } @Override public int getGeneratorTotalAmount(Dimension dimension) { int totalAmount = 0; for (int amt : getGeneratorAmounts(dimension).values()) totalAmount += amt; return totalAmount; } @Override public Map getGeneratorAmounts(Dimension dimension) { KeyMap worldGeneratorRates = this.cobbleGeneratorValues.readAndGet( cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension)); if (worldGeneratorRates == null) return Collections.emptyMap(); Map generatorAmountsResult = new HashMap<>(); worldGeneratorRates.forEach((blockKey, valueAmount) -> { int amount = valueAmount.get(); if (amount > 0) { generatorAmountsResult.put(blockKey.toString(), amount); } }); return generatorAmountsResult.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(generatorAmountsResult); } @Override public Map getCustomGeneratorAmounts(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); KeyMap worldGeneratorRates = this.cobbleGeneratorValues.readAndGet( cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension)); if (worldGeneratorRates == null) return Collections.emptyMap(); return Collections.unmodifiableMap(worldGeneratorRates.entrySet().stream() .filter(entry -> !entry.getValue().isSynced()) .collect(KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get()))); } @Override public void clearGeneratorAmounts(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Log.debug(Debug.CLEAR_GENERATOR_RATES, owner.getName(), dimension.getName()); KeyMap worldGeneratorRates = this.cobbleGeneratorValues.readAndGet( cobbleGeneratorValues -> cobbleGeneratorValues.get(dimension)); if (worldGeneratorRates != null && !worldGeneratorRates.isEmpty()) { worldGeneratorRates.clear(); IslandsDatabaseBridge.clearGeneratorRates(this, dimension); } } @Nullable @Override public Key generateBlock(Location location, boolean optimizeDefaultBlock) { Preconditions.checkNotNull(location, "location parameter cannot be null."); Preconditions.checkNotNull(location.getWorld(), "location's world cannot be null."); Preconditions.checkArgument(isInside(location), "location must be inside island"); Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(location.getWorld()); return generateBlock(location, dimension, optimizeDefaultBlock); } @Override public Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock) { Preconditions.checkNotNull(location, "location parameter cannot be null."); Preconditions.checkNotNull(location.getWorld(), "location's world cannot be null."); Preconditions.checkNotNull(dimension, "environment parameter cannot be null."); Log.debug(Debug.GENERATE_BLOCK, owner.getName(), location, dimension.getName(), optimizeDefaultBlock); int totalGeneratorAmounts = getGeneratorTotalAmount(dimension); if (totalGeneratorAmounts == 0) { Log.debugResult(Debug.GENERATE_BLOCK, "Return No Generator Rates", "null"); return null; } Map generatorAmounts = getGeneratorAmounts(dimension); GeneratorType generatorType = GeneratorType.fromDimension(dimension); Key defaultBlockKey = generatorType.getDefaultBlock(); Key newStateKey = defaultBlockKey; if (totalGeneratorAmounts == 1) { newStateKey = Keys.ofMaterialAndData(generatorAmounts.keySet().iterator().next()); } else { int generatedIndex = ThreadLocalRandom.current().nextInt(totalGeneratorAmounts); int currentIndex = 0; for (Map.Entry entry : generatorAmounts.entrySet()) { currentIndex += entry.getValue(); if (generatedIndex < currentIndex) { newStateKey = Keys.ofMaterialAndData(entry.getKey()); break; } } } PluginEvent event = PluginEventsFactory.callIslandGenerateBlockEvent(this, location, newStateKey); if (event.isCancelled()) { Log.debugResult(Debug.GENERATE_BLOCK, "Return Event Cancelled", "null"); return null; } Key generatedBlock = event.getArgs().block; if (optimizeDefaultBlock && generatedBlock.equals(defaultBlockKey)) { Log.debugResult(Debug.GENERATE_BLOCK, "Return Default Block", generatedBlock); return generatedBlock; } // If the block is a custom block, and the event was cancelled - we need to call the handleBlockPlace manually. handleBlockPlace(generatedBlock, 1); // Checking whether the plugin should set the block in the world. if (event.getArgs().placeBlock) { int combinedId; try { Material generateBlockType = Material.valueOf(generatedBlock.getGlobalKey()); byte blockData = generatedBlock.getSubKey().isEmpty() ? 0 : Byte.parseByte(generatedBlock.getSubKey()); combinedId = plugin.getNMSAlgorithms().getCombinedId(generateBlockType, blockData); } catch (IllegalArgumentException error) { Log.error("Invalid block for generating block: ", generatedBlock); combinedId = plugin.getNMSAlgorithms().getCombinedId( ((MaterialKey) defaultBlockKey).getMaterial(), (byte) 0); } plugin.getNMSWorld().setBlock(location, combinedId); } plugin.getNMSWorld().playGeneratorSound(location); Log.debugResult(Debug.GENERATE_BLOCK, "Return", generatedBlock); return generatedBlock; } @Override public boolean wasSchematicGenerated(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); return this.generatedSchematics.readAndGet(generatedSchematics -> generatedSchematics.contains(dimension)); } @Override public void setSchematicGenerate(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); setSchematicGenerate(dimension, true); } @Override public void setSchematicGenerate(Dimension dimension, boolean generated) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Log.debug(Debug.SET_SCHEMATIC, dimension.getName(), generated); boolean updated = this.generatedSchematics.writeAndGet(generatedSchematics -> generated ? generatedSchematics.add(dimension) : generatedSchematics.remove(dimension)); if (!updated) return; IslandsDatabaseBridge.saveGeneratedSchematics(this); } @Override public Set getGeneratedSchematics() { return Collections.unmodifiableSet(this.generatedSchematics.readAndGet(generatedSchematics -> generatedSchematics.collect(Dimension.values()))); } @Override public String getSchematicName() { return this.schematicName == null ? "" : this.schematicName; } @Override public int getPosition(SortingType sortingType) { return plugin.getGrid().getIslandPosition(this, sortingType); } @Override public IslandChest[] getChest() { return islandChests.readAndGet(islandChests -> Arrays.copyOf(islandChests, islandChests.length)); } /* * Generator related methods */ @Override public int getChestSize() { return islandChests.readAndGet(islandChests -> islandChests.length); } @Override public void setChestRows(int index, int rows) { IslandChest[] islandChests = this.islandChests.get(); int oldSize = islandChests.length; boolean updatedIslandChests = false; if (index >= oldSize) { updatedIslandChests = true; islandChests = Arrays.copyOf(islandChests, index + 1); this.islandChests.set(islandChests); for (int i = oldSize; i <= index; i++) { (islandChests[i] = new SIslandChest(this, i)).setRows(plugin.getSettings().getIslandChests().getDefaultSize()); } } IslandChest islandChest = islandChests[index]; if (!updatedIslandChests && islandChest.getRows() == rows) return; islandChests[index].setRows(rows); IslandsDatabaseBridge.markIslandChestsToBeSaved(this, islandChests[index]); } private void calcIslandWorthInternal(@Nullable SuperiorPlayer asker, @Nullable Runnable callback) { try { this.beingRecalculated = true; plugin.getGrid().startCalcTask(); runCalcIslandWorthInternal(asker, callback); } catch (Throwable error) { // In case of an error, we get out of the recalculate state. this.beingRecalculated = false; plugin.getGrid().stopCalcTask(); throw error; } } private void runCalcIslandWorthInternal(@Nullable SuperiorPlayer asker, @Nullable Runnable callback) { Log.debug(Debug.CALCULATE_ISLAND, owner.getName(), asker); BigDecimal oldWorth = getWorth(); BigDecimal oldLevel = getIslandLevel(); CompletableFuture calculationResult; try { // Legacy support // noinspection deprecation calculationResult = calculationAlgorithm.calculateIsland(); } catch (UnsupportedOperationException ex) { calculationResult = calculationAlgorithm.calculateIsland(this); } calculationResult.whenComplete((result, error) -> { beingRecalculated = false; boolean isLastActiveTask = plugin.getGrid().stopCalcTask(); if (error != null) { if (error instanceof TimeoutException) { if (asker != null) Message.ISLAND_WORTH_TIME_OUT.send(asker); } else { Log.entering(owner.getName(), asker); Log.error(error, "An unexpected error occurred while calculating island worth:"); if (asker != null) Message.ISLAND_WORTH_ERROR.send(asker); } return; } clearBlockCounts(); result.getBlockCounts().forEach((blockKey, amount) -> handleBlockPlaceInternal(blockKey, amount, 0)); BigDecimal newIslandLevel = getIslandLevel(); BigDecimal newIslandWorth = getWorth(); finishCalcIsland(asker, callback, newIslandLevel, newIslandWorth); plugin.getMenus().refreshValues(this); plugin.getMenus().refreshCounts(this); saveBlockCounts(this.currentTotalBlockCounts.get(), oldWorth, oldLevel, true, isLastActiveTask); updateLastTime(); }); } private boolean hasGiveInterestFailed() { return this.giveInterestFailed; } private void applyEffectsNoUpgradeCheck(SuperiorPlayer superiorPlayer) { Player player = superiorPlayer.asPlayer(); if (player != null) { getPotionEffects().forEach((potionEffectType, level) -> player.addPotionEffect( new PotionEffect(potionEffectType, Integer.MAX_VALUE, level - 1), true)); } } private void removeEffectsNoUpgradeCheck(SuperiorPlayer superiorPlayer) { Player player = superiorPlayer.asPlayer(); if (player != null) getPotionEffects().keySet().forEach(player::removePotionEffect); } private WarpCategory loadWarpCategory(String name, int slot, @Nullable ItemStack icon) { WarpCategory warpCategory = new SWarpCategory(getUniqueId(), name, slot, icon); warpCategories.put(name.toLowerCase(Locale.ENGLISH), warpCategory); return warpCategory; } public IslandWarp loadIslandWarp(String name, WorldInfo worldInfo, WorldPosition worldPosition, @Nullable WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) { if (warpCategory == null) warpCategory = warpCategories.values().stream().findFirst().orElseGet(() -> createWarpCategory("Default Category")); IslandWarp islandWarp = new SIslandWarp(name, worldInfo, worldPosition, warpCategory, isPrivate, icon); islandWarp.getCategory().getWarps().add(islandWarp); String warpName = islandWarp.getName().toLowerCase(Locale.ENGLISH); if (warpsByName.containsKey(warpName)) deleteWarp(warpName); warpsByName.put(warpName, islandWarp); this.warpsByLocation.write(warpsByLocation -> warpsByLocation.put(LazyWorldLocation.of(worldInfo, worldPosition), islandWarp)); return islandWarp; } @Override public DatabaseBridge getDatabaseBridge() { return databaseBridge; } @Override public PersistentDataContainer getPersistentDataContainer() { if (persistentDataContainer == null) persistentDataContainer = plugin.getFactory().createPersistentDataContainer(this); return persistentDataContainer; } @Override public boolean isPersistentDataContainerEmpty() { return persistentDataContainer == null || persistentDataContainer.isEmpty(); } @Override public void savePersistentDataContainer() { IslandsDatabaseBridge.executeFutureSaves(this, IslandsDatabaseBridge.FutureSave.PERSISTENT_DATA); } /* * Schematic methods */ private void replaceVisitor(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer) { uniqueVisitors.write(uniqueVisitors -> { Iterator iterator = uniqueVisitors.iterator(); while (iterator.hasNext()) { UniqueVisitor uniqueVisitor = iterator.next(); if (uniqueVisitor.getSuperiorPlayer().equals(originalPlayer)) { Log.debugResult(Debug.REPLACE_PLAYER, "Action", "Replace Visitor"); if (newPlayer == null) { iterator.remove(); } else { uniqueVisitor.setSuperiorPlayer(newPlayer); } } } }); } private void replaceBannedPlayer(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer) { if (bannedPlayers.remove(originalPlayer)) { Log.debugResult(Debug.REPLACE_PLAYER, "Action", "Replace Banned Player"); if (newPlayer != null) bannedPlayers.add(newPlayer); } } private void replacePermissions(SuperiorPlayer originalPlayer, @Nullable SuperiorPlayer newPlayer) { PlayerPrivilegeNode playerPermissionNode = playerPermissions.remove(originalPlayer); if (playerPermissionNode != null) { Log.debugResult(Debug.REPLACE_PLAYER, "Action", "Replace Permissions"); if (newPlayer != null) playerPermissions.put(newPlayer, playerPermissionNode); } } private void saveBlockCounts(BigInteger currentTotalBlocksCount, BigDecimal oldWorth, BigDecimal oldLevel) { saveBlockCounts(currentTotalBlocksCount, oldWorth, oldLevel, false, true); } private void saveBlockCounts(BigInteger currentTotalBlocksCount, BigDecimal oldWorth, BigDecimal oldLevel, boolean forceBlocksCountSave, boolean sortIslands) { BigDecimal newWorth = getWorth(); BigDecimal newLevel = getIslandLevel(); if (oldLevel.compareTo(newLevel) != 0 || oldWorth.compareTo(newWorth) != 0) { registerTask(BukkitExecutor.async(() -> PluginEventsFactory.callIslandWorthUpdateEvent(this, oldWorth, oldLevel, newWorth, newLevel), 0L)); } BigInteger deltaBlockCounts = this.lastSavedBlockCounts.subtract(currentTotalBlocksCount); if (deltaBlockCounts.compareTo(BigInteger.ZERO) < 0) deltaBlockCounts = deltaBlockCounts.negate(); if (forceBlocksCountSave || deltaBlockCounts.compareTo(plugin.getSettings().getBlockCountsSaveThreshold()) >= 0) { this.lastSavedBlockCounts = currentTotalBlocksCount; IslandsDatabaseBridge.saveBlockCounts(this); plugin.getMenus().refreshValues(this); plugin.getMenus().refreshCounts(this); if (sortIslands) { plugin.getGrid().sortIslands(SortingTypes.BY_WORTH); plugin.getGrid().sortIslands(SortingTypes.BY_LEVEL); } } else { IslandsDatabaseBridge.markBlockCountsToBeSaved(this); } } public void syncUpgrades(boolean overrideCustom) { clearUpgrades(overrideCustom); // We want to sync the default upgrade first, then the actual upgrades syncUpgrade(DefaultUpgradeLevel.getInstance(), overrideCustom); // Syncing all real upgrades plugin.getUpgrades().getUpgrades().forEach(upgrade -> syncUpgrade((SUpgradeLevel) getUpgradeLevel(upgrade), overrideCustom)); } /* * Island top methods */ private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { Location location = islandWarp.getLocation(wrapper.getHandle()); if (location.getWorld() == null) { Location clonedLocation = location.clone(); IslandWorlds.accessIslandWorldAsync(this, location, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { clonedLocation.setWorld(world); warpPlayerWithoutWarmupWorldLoaded(superiorPlayer, islandWarp, clonedLocation); }); }); } else { warpPlayerWithoutWarmupWorldLoaded(superiorPlayer, islandWarp, location); } } } private void warpPlayerWithoutWarmupWorldLoaded(SuperiorPlayer superiorPlayer, IslandWarp islandWarp, Location location) { // Warp doesn't exist anymore. if (getWarp(islandWarp.getName()) == null) { Message.INVALID_WARP.send(superiorPlayer, islandWarp.getName()); deleteWarp(islandWarp.getName()); return; } superiorPlayer.setTeleportTask(null); if (!isInsideRange(location) || !WorldBlocks.isSafeBlock(location.getBlock())) { Message.UNSAFE_WARP.send(superiorPlayer); if (plugin.getSettings().getDeleteUnsafeWarps()) deleteWarp(islandWarp.getName()); return; } superiorPlayer.teleport(location, success -> { if (success) { Message.TELEPORTED_TO_WARP.send(superiorPlayer); if (superiorPlayer.isShownAsOnline()) { IslandUtils.sendMessage(this, Message.TELEPORTED_TO_WARP_ANNOUNCEMENT, Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName(), islandWarp.getName()); } } }); } /* * Vault related methods */ @Override public void completeMission(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(mission.getIslandMission(), "mission parameter must be island-mission."); this.changeAmountMissionsCompletedInternal(mission, false, counter -> counter.inc(1)); } @Override public void resetMission(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(mission.getIslandMission(), "mission parameter must be island-mission."); this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.inc(-1)); } @Override public boolean hasCompletedMission(Mission mission) { return getAmountMissionCompleted(mission) > 0; } @Override public boolean canCompleteMissionAgain(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); if (!mission.getIslandMission()) return false; Optional missionDataOptional = plugin.getMissions().getMissionData(mission); if (missionDataOptional.isPresent()) { int resetAmount = missionDataOptional.get().getResetAmount(); return resetAmount <= 0 || getAmountMissionCompleted(mission) < resetAmount; } return false; } @Override public int getAmountMissionCompleted(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Counter finishCount = mission.getIslandMission() ? completedMissions.get(new MissionReference(mission)) : null; return finishCount == null ? 0 : finishCount.get(); } @Override public void setAmountMissionCompleted(Mission mission, int finishCount) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(mission.getIslandMission(), "mission parameter must be island-mission."); this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.set(finishCount)); } private void changeAmountMissionsCompletedInternal(Mission mission, boolean clearData, Function action) { String missionName = mission.getName(); MissionReference missionReference = new MissionReference(mission); Counter finishCount = completedMissions.computeIfAbsent(missionReference, r -> new Counter(0)); int oldFinishCount = action.apply(finishCount); int newFinishCount = finishCount.get(); Log.debug(Debug.SET_ISLAND_MISSION_COMPLETED, missionName, finishCount); if (clearData) mission.clearData(getOwner()); if (newFinishCount > 0) { if (newFinishCount == oldFinishCount) return; IslandsDatabaseBridge.saveMission(this, mission, newFinishCount); } else { completedMissions.remove(missionReference); if (oldFinishCount <= 0) return; IslandsDatabaseBridge.removeMission(this, mission); } plugin.getMenus().refreshMissionsCategory(mission.getMissionCategory()); } @Override public List> getCompletedMissions() { return new SequentialListBuilder() .filter(MissionReference::isValid) .map(completedMissions.keySet(), MissionReference::getMission); } @Override public Map, Integer> getCompletedMissionsWithAmounts() { Map, Integer> completedMissions = new LinkedHashMap<>(); this.completedMissions.forEach((mission, finishCount) -> { if (mission.isValid()) completedMissions.put(mission.getMission(), finishCount.get()); }); return completedMissions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(completedMissions); } /* * Object related methods */ @Override public int hashCode() { return this.uuid.hashCode(); } /* * Private methods */ @Override public boolean equals(Object obj) { return obj instanceof Island && (this == obj || this.uuid.equals(((Island) obj).getUniqueId())); } @Override @SuppressWarnings("all") public int compareTo(Island other) { if (other == null) return -1; SortingType sortingType = SortingTypes.getIslandTopSorting(); Comparator comparator = sortingType.getComparator(); int result = comparator.compare(this, other); if (result != 0) return result; return getOwner().getName().compareTo(other.getOwner().getName()); } private IslandChest[] createDefaultIslandChests() { IslandChest[] islandChests = new IslandChest[plugin.getSettings().getIslandChests().getDefaultPages()]; for (int i = 0; i < islandChests.length; i++) { if (islandChests[i] == null) { islandChests[i] = new SIslandChest(this, i); islandChests[i].setRows(plugin.getSettings().getIslandChests().getDefaultSize()); } } return islandChests; } private void startBankInterest() { if (!BuiltinModules.BANK.getConfiguration().isBankInterestEnabled()) return; int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval(); long currentTime = System.currentTimeMillis() / 1000; long ticksToNextInterest = (bankInterestInterval - (currentTime - this.lastInterest)) * 20; if (ticksToNextInterest <= 0) { giveInterest(true); } else { resetBankInterestTask(ticksToNextInterest); } } private void checkMembersDuplication() { members.write(members -> { Iterator iterator = members.iterator(); while (iterator.hasNext()) { SuperiorPlayer superiorPlayer = iterator.next(); if (superiorPlayer.equals(owner) || !this.equals(superiorPlayer.getIsland())) { iterator.remove(); IslandsDatabaseBridge.removeMember(this, superiorPlayer); } } }); } private void updateOldUpgradeValues() { this.blockLimits.forEach((block, limit) -> { Integer defaultValue = plugin.getSettings().getDefaultValues().getBlockLimits().get(block); if (defaultValue != null && (int) limit.get() == defaultValue) this.blockLimits.put(block, IntValue.syncedFixed(defaultValue)); }); this.entityLimits.forEach((entity, limit) -> { Integer defaultValue = plugin.getSettings().getDefaultValues().getEntityLimits().get(entity); if (defaultValue != null && (int) limit.get() == defaultValue) this.entityLimits.put(entity, IntValue.syncedFixed(defaultValue)); }); this.cobbleGeneratorValues.write(cobbleGeneratorValues -> { for (Dimension dimension : Dimension.values()) { Map defaultGenerator = plugin.getSettings().getDefaultValues().getRealGeneratorsMap().get(dimension); if (defaultGenerator != null) { KeyMap worldGeneratorRates = cobbleGeneratorValues.get(dimension); if (worldGeneratorRates == null) continue; worldGeneratorRates.forEach((key, rate) -> { Integer defaultValue = defaultGenerator.get(key); if (defaultValue != null && (int) rate.get() == defaultValue) worldGeneratorRates.put(key, IntValue.syncedFixed(defaultValue)); }); } } }); if (getIslandSize() == plugin.getSettings().getDefaultValues().getIslandSize()) this.islandSize.set(DefaultUpgradeLevel.getInstance().getBorderSizeUpgradeValue()); if (getWarpsLimit() == plugin.getSettings().getDefaultValues().getWarpsLimit()) this.warpsLimit.set(DefaultUpgradeLevel.getInstance().getWarpsLimitUpgradeValue()); if (getTeamLimit() == plugin.getSettings().getDefaultValues().getTeamLimit()) this.teamLimit.set(DefaultUpgradeLevel.getInstance().getTeamLimitUpgradeValue()); if (getCoopLimit() == plugin.getSettings().getDefaultValues().getCoopLimit()) this.coopLimit.set(DefaultUpgradeLevel.getInstance().getCoopLimitUpgradeValue()); if (getCropGrowthMultiplier() == plugin.getSettings().getDefaultValues().getCropGrowth()) this.cropGrowth.set(DefaultUpgradeLevel.getInstance().getCropGrowthUpgradeValue()); if (getSpawnerRatesMultiplier() == plugin.getSettings().getDefaultValues().getSpawnerRates()) this.spawnerRates.set(DefaultUpgradeLevel.getInstance().getSpawnerRatesUpgradeValue()); if (getMobDropsMultiplier() == plugin.getSettings().getDefaultValues().getMobDrops()) this.mobDrops.set(DefaultUpgradeLevel.getInstance().getMobDropsUpgradeValue()); } private void clearUpgrades(boolean overrideCustom) { if (overrideCustom || this.islandSize.get().isSynced()) { setIslandSizeInternal(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); } warpsLimit.set(warpsLimit -> { if (overrideCustom || warpsLimit.isSynced()) { return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return warpsLimit; }); teamLimit.set(teamLimit -> { if (overrideCustom || teamLimit.isSynced()) { return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return teamLimit; }); coopLimit.set(coopLimit -> { if (overrideCustom || coopLimit.isSynced()) { return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return coopLimit; }); cropGrowth.set(cropGrowth -> { if (overrideCustom || cropGrowth.isSynced()) { notifyCropGrowthChange(IslandUpgradeConstants.SYNCED_VALUE); return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return cropGrowth; }); spawnerRates.set(spawnerRates -> { if (overrideCustom || spawnerRates.isSynced()) { return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return spawnerRates; }); mobDrops.set(mobDrops -> { if (overrideCustom || mobDrops.isSynced()) { return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return mobDrops; }); bankLimit.set(bankLimit -> { if (overrideCustom || bankLimit.isSynced()) { return Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE); } return bankLimit; }); blockLimits.entrySet().stream() .filter(entry -> overrideCustom || entry.getValue().isSynced()) .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); entityLimits.entrySet().stream() .filter(entry -> overrideCustom || entry.getValue().isSynced()) .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); cobbleGeneratorValues.write(cobbleGeneratorValues -> { cobbleGeneratorValues.values().forEach(cobbleGeneratorValue -> { cobbleGeneratorValue.entrySet().stream() .filter(entry -> overrideCustom || entry.getValue().isSynced()) .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); }); }); islandEffects.entrySet().stream() .filter(entry -> overrideCustom || entry.getValue().isSynced()) .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); roleLimits.write(roleLimits -> { Iterator> iterator = roleLimits.entryIterator(); while (iterator.hasNext()) { Int2ObjectMapView.Entry entry = iterator.next(); if (overrideCustom || entry.getValue().isSynced()) entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); } }); if (overrideCustom) IslandsDatabaseBridge.clearIslandSettings(this); } private void syncUpgrade(SUpgradeLevel upgradeLevel, boolean overrideCustom) { if (upgradeLevel.hasCropGrowth()) { cropGrowth.set(cropGrowth -> { if (overrideCustom || cropGrowth.isSynced()) { notifyCropGrowthChange(upgradeLevel.getCropGrowth()); return upgradeLevel.getCropGrowthUpgradeValue(); } return cropGrowth; }); } if (upgradeLevel.hasSpawnerRates()) { spawnerRates.set(spawnerRates -> { if (overrideCustom || spawnerRates.isSynced()) return upgradeLevel.getSpawnerRatesUpgradeValue(); return spawnerRates; }); } if (upgradeLevel.hasMobDrops()) { mobDrops.set(mobDrops -> { if (overrideCustom || mobDrops.isSynced()) return upgradeLevel.getMobDropsUpgradeValue(); return mobDrops; }); } if (upgradeLevel.hasTeamLimit()) { teamLimit.set(teamLimit -> { if (overrideCustom || teamLimit.isSynced()) return upgradeLevel.getTeamLimitUpgradeValue(); return teamLimit; }); } if (upgradeLevel.hasWarpsLimit()) { warpsLimit.set(warpsLimit -> { if (overrideCustom || warpsLimit.isSynced()) return upgradeLevel.getWarpsLimitUpgradeValue(); return warpsLimit; }); } if (upgradeLevel.hasCoopLimit()) { coopLimit.set(coopLimit -> { if (overrideCustom || coopLimit.isSynced()) return upgradeLevel.getCoopLimitUpgradeValue(); return coopLimit; }); } if (upgradeLevel.hasBorderSize()) { IntValue islandSize = this.islandSize.get(); if (overrideCustom || islandSize.isSynced()) setIslandSizeInternal(upgradeLevel.getBorderSizeUpgradeValue()); } if (upgradeLevel.hasBankLimit()) { bankLimit.set(bankLimit -> { if (overrideCustom || bankLimit.isSynced()) return upgradeLevel.getBankLimitUpgradeValue(); return bankLimit; }); } for (Map.Entry entry : upgradeLevel.getBlockLimitsUpgradeValue().entrySet()) { IntValue currentValue = blockLimits.getRaw(entry.getKey(), null); if (currentValue == null || overrideCustom || currentValue.isSynced()) { if (entry.getValue().get() < 0) { blockLimits.remove(entry.getKey()); } else { blockLimits.put(entry.getKey(), entry.getValue()); } } } for (Map.Entry entry : upgradeLevel.getEntityLimitsUpgradeValue().entrySet()) { IntValue currentValue = entityLimits.getRaw(entry.getKey(), null); if (currentValue == null || overrideCustom || currentValue.isSynced()) { if (entry.getValue().get() < 0) { entityLimits.remove(entry.getKey()); } else { entityLimits.put(entry.getKey(), entry.getValue()); } } } EnumerateMap> upgradeGeneratorRates = upgradeLevel.getGeneratorUpgradeValue(); if (!upgradeGeneratorRates.isEmpty()) { this.cobbleGeneratorValues.write(cobbleGeneratorValues -> { for (Dimension dimension : Dimension.values()) { Map upgradeLevelGeneratorRates = upgradeGeneratorRates.get(dimension); if (upgradeLevelGeneratorRates == null) continue; KeyMap worldGeneratorRates = cobbleGeneratorValues.get(dimension); if (worldGeneratorRates != null && !upgradeLevelGeneratorRates.isEmpty()) { KeyMap worldGeneratorRatesCopy = worldGeneratorRates; worldGeneratorRatesCopy.removeIf(key -> worldGeneratorRatesCopy.get(key).isSynced()); } for (Map.Entry entry : upgradeLevelGeneratorRates.entrySet()) { Key block = entry.getKey(); IntValue rate = entry.getValue(); IntValue currentValue = worldGeneratorRates == null ? null : worldGeneratorRates.get(block); if (currentValue == null || overrideCustom || currentValue.isSynced()) { if (rate.get() < 0) { worldGeneratorRates.remove(block); } else { if (worldGeneratorRates == null) { worldGeneratorRates = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); cobbleGeneratorValues.put(dimension, worldGeneratorRates); } worldGeneratorRates.put(block, rate); } } } } }); } boolean editedIslandEffects = false; for (Map.Entry entry : upgradeLevel.getPotionEffectsUpgradeValue().entrySet()) { IntValue currentValue = islandEffects.get(entry.getKey()); if (currentValue == null || overrideCustom || currentValue.isSynced()) { if (entry.getValue().get() < 0) { islandEffects.remove(entry.getKey()); } else { islandEffects.put(entry.getKey(), entry.getValue()); } editedIslandEffects = true; } } if (editedIslandEffects) { applyEffects(); } roleLimits.write(roleLimits -> { for (Map.Entry entry : upgradeLevel.getRoleLimitsUpgradeValue().entrySet()) { IntValue currentValue = roleLimits.get(entry.getKey().getId()); if (currentValue == null || overrideCustom || currentValue.isSynced()) { if (entry.getValue().get() < 0) { roleLimits.remove(entry.getKey().getId()); } else { roleLimits.put(entry.getKey().getId(), entry.getValue()); } } } }); } private void updateIslandChests() { List islandChestList = new ArrayList<>(Arrays.asList(this.islandChests.get())); boolean updatedChests = false; while (islandChestList.size() < plugin.getSettings().getIslandChests().getDefaultPages()) { IslandChest newIslandChest = new SIslandChest(this, islandChestList.size()); newIslandChest.setRows(plugin.getSettings().getIslandChests().getDefaultSize()); islandChestList.add(newIslandChest); updatedChests = true; } if (updatedChests) { this.islandChests.set(islandChestList.toArray(new IslandChest[0])); } } private void finishCalcIsland(SuperiorPlayer asker, Runnable callback, BigDecimal islandLevel, BigDecimal islandWorth) { PluginEventsFactory.callIslandWorthCalculatedEvent(this, asker, islandLevel, islandWorth); if (asker != null) Message.ISLAND_WORTH_RESULT.send(asker, islandWorth, islandLevel); if (callback != null) callback.run(); } private void forEachIslandMember(UUID[] ignoredMembersArray, boolean onlyOnline, Consumer islandMemberConsumer) { Set ignoredMembersSet; if (ignoredMembersArray.length == 0) { ignoredMembersSet = Collections.emptySet(); } else { ignoredMembersSet = new HashSet<>(); Collections.addAll(ignoredMembersSet, ignoredMembersArray); } forEachIslandMember(ignoredMembersSet, onlyOnline, islandMemberConsumer); } private void forEachIslandMember(Set ignoredMembers, boolean onlyOnline, Consumer islandMemberConsumer) { for (SuperiorPlayer islandMember : getIslandMembers(true)) { if (!ignoredMembers.contains(islandMember.getUniqueId()) && (!onlyOnline || islandMember.isOnline())) { islandMemberConsumer.accept(islandMember); } } } private void notifyCropGrowthChange(double newCropGrowth) { if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class)) return; // If the world is not loaded, we can skip this final int flags = IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS; double newCropGrowthMultiplier = newCropGrowth - 1; IslandWorlds.accessIslandWorldsAsync(this, false, result -> { result.ifLeft(world -> { WorldInfo worldInfo = WorldInfo.of(world); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, flags); if (!chunkPositions.isEmpty()) plugin.getNMSChunks().updateCropsTicker(chunkPositions, newCropGrowthMultiplier); }); }); } private Location worldPositionToLocation(Dimension dimension, WorldPosition worldPosition) { return IslandWorlds.setWorldToLocation(this, dimension, worldPosition); } private R accessBlocksTracker(boolean rawBlocks, Function function) { if (!rawBlocks) return function.apply(this.blocksTracker); try { this.blocksTracker.setLoadingDataMode(true); return function.apply(this.blocksTracker); } finally { this.blocksTracker.setLoadingDataMode(false); } } private BukkitTask registerTask(@Nullable BukkitTask bukkitTask) { if (bukkitTask != null) { this.activeTasks.write(activeTasks -> activeTasks.add(bukkitTask)); } return bukkitTask; } public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SIsland::onSettingsUpdate); } private static void onSettingsUpdate() { DEFAULT_FLAGS_CACHE = new EnumerateSet<>(IslandFlag.values()); plugin.getSettings().getDefaultSettings().forEach(islandFlagName -> { try { DEFAULT_FLAGS_CACHE.add(IslandFlag.getByName(islandFlagName)); } catch (Throwable ignored) { } }); } private static WorldPosition adjustPositionToCenterOfBlock(@Nullable WorldPosition worldPosition) { if (worldPosition == null) return null; boolean changed = false; BlockPosition blockPosition = worldPosition.toBlockPosition(); double x = worldPosition.getX(); double z = worldPosition.getZ(); if (worldPosition.getX() - 0.5 != blockPosition.getX()) { x = blockPosition.getX() + 0.5; changed = true; } if (worldPosition.getZ() - 0.5 != blockPosition.getZ()) { z = blockPosition.getZ() + 0.5; changed = true; } return !changed ? worldPosition : SWorldPosition.of(x, worldPosition.getY(), z, worldPosition.getYaw(), worldPosition.getPitch()); } public static class UniqueVisitor { private final Pair pair; private SuperiorPlayer superiorPlayer; private long lastVisitTime; public UniqueVisitor(SuperiorPlayer superiorPlayer, long lastVisitTime) { this.superiorPlayer = superiorPlayer; this.lastVisitTime = lastVisitTime; this.pair = new Pair<>(superiorPlayer, lastVisitTime); } public SuperiorPlayer getSuperiorPlayer() { return superiorPlayer; } public void setSuperiorPlayer(SuperiorPlayer superiorPlayer) { this.superiorPlayer = superiorPlayer; this.pair.setKey(superiorPlayer); } public long getLastVisitTime() { return lastVisitTime; } public void setLastVisitTime(long lastVisitTime) { this.lastVisitTime = lastVisitTime; this.pair.setValue(lastVisitTime); } public Pair toPair() { return this.pair; } @Override public int hashCode() { return Objects.hash(superiorPlayer, lastVisitTime); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UniqueVisitor that = (UniqueVisitor) o; return lastVisitTime == that.lastVisitTime && superiorPlayer.equals(that.superiorPlayer); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/SIslandChest.java ================================================ package com.bgsoftware.superiorskyblock.island; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import java.util.Arrays; import java.util.concurrent.atomic.AtomicBoolean; public class SIslandChest implements IslandChest { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final AtomicBoolean updateFlag = new AtomicBoolean(false); private final Island island; private final int index; private Inventory inventory = Bukkit.createInventory(this, 9, plugin.getSettings().getIslandChests().getChestTitle()); private int contentsUpdateCounter = 0; public SIslandChest(Island island, int index) { this.island = island; this.index = index; } public static SIslandChest createChest(Island island, int index, ItemStack[] contents) { SIslandChest islandChest = new SIslandChest(island, index); islandChest.inventory = Bukkit.createInventory(islandChest, contents.length, plugin.getSettings().getIslandChests().getChestTitle()); islandChest.inventory.setContents(contents); return islandChest; } @Override public Island getIsland() { return island; } @Override public int getIndex() { return index; } @Override public int getRows() { return inventory.getSize() / 9; } @Override public void setRows(int rows) { BukkitExecutor.ensureMain(() -> { try { updateFlag.set(true); ItemStack[] oldContents = inventory.getContents(); Inventory oldInventory = inventory; inventory = Bukkit.createInventory(this, 9 * rows, plugin.getSettings().getIslandChests().getChestTitle()); inventory.setContents(Arrays.copyOf(oldContents, 9 * rows)); inventory.getViewers().forEach(humanEntity -> { if (humanEntity.getOpenInventory().getTopInventory().equals(oldInventory)) humanEntity.openInventory(inventory); }); } finally { updateFlag.set(false); } }); } @Override public ItemStack[] getContents() { return inventory.getContents(); } @Override public void openChest(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); superiorPlayer.runIfOnline(player -> player.openInventory(getInventory())); } @Override public Inventory getInventory() { return inventory; } public boolean isUpdating() { return updateFlag.get(); } public void updateContents() { if (++contentsUpdateCounter >= 50) { contentsUpdateCounter = 0; IslandsDatabaseBridge.saveIslandChest(island, this); } else { IslandsDatabaseBridge.markIslandChestsToBeSaved(island, this); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java ================================================ package com.bgsoftware.superiorskyblock.island; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.annotations.Size; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.BlockChangeResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PermissionNode; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.IslandArea; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.WorldInfoImpl; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.bridge.EmptyDatabaseBridge; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.persistence.EmptyPersistentDataContainer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.island.cache.IslandCacheImpl; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.island.privilege.PrivilegeNodeAbstract; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.google.common.base.Preconditions; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.PriorityQueue; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public class SpawnIsland implements Island { private static final UUID spawnUUID = new UUID(0, 0); private static final LazyReference ownerPlayer = new LazyReference() { @Override protected SSuperiorPlayer create() { return new SSuperiorPlayer((SuperiorPlayerBuilderImpl) SuperiorPlayer.newBuilder().setUniqueId(spawnUUID)); } }; private static final IslandChest[] EMPTY_ISLAND_CHESTS = new IslandChest[0]; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static EnumerateSet DEFAULT_SPAWN_FLAGS_CACHE; private static EnumerateSet DEFAULT_SPAWN_PRIVILEGES_CACHE; public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SpawnIsland::onSettingsUpdate); } private static void onSettingsUpdate() { DEFAULT_SPAWN_FLAGS_CACHE = new EnumerateSet<>(IslandFlag.values()); plugin.getSettings().getSpawn().getSettings().forEach(flagName -> { try { DEFAULT_SPAWN_FLAGS_CACHE.add(IslandFlag.getByName(flagName)); } catch (Throwable ignored) { } }); DEFAULT_SPAWN_PRIVILEGES_CACHE = new EnumerateSet<>(IslandPrivilege.values()); plugin.getSettings().getSpawn().getPermissions().forEach(privilegeName -> { try { DEFAULT_SPAWN_PRIVILEGES_CACHE.add(IslandPrivilege.getByName(privilegeName)); } catch (Throwable ignored) { } }); } private final PriorityQueue playersInside = new PriorityQueue<>(SortingComparators.PLAYER_NAMES_COMPARATOR); private final DirtyChunksContainer dirtyChunksContainer; private final LazyReference islandCache = new LazyReference() { @Override protected IslandCache create() { return new IslandCacheImpl(SpawnIsland.this); } }; private final WorldPosition center; private final World spawnWorld; private final WorldInfo spawnWorldInfo; private final int islandSize; private final IslandArea islandArea = new IslandArea(); private Biome biome = Biome.PLAINS; public SpawnIsland() throws ManagerLoadException { String spawnLocation = plugin.getSettings().getSpawn().getLocation(); Location centerLocation = Serializers.LOCATION_SPACED_CENTERED_SERIALIZER.deserialize(spawnLocation); if (centerLocation == null) { throw new ManagerLoadException("The spawn location could not be parsed", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } String worldName = spawnLocation.split(", ")[0]; if (centerLocation.getWorld() == null) plugin.getProviders().runWorldsListeners(worldName); this.spawnWorld = centerLocation.getWorld(); if (this.spawnWorld == null) throw new ManagerLoadException("The spawn location is in invalid world.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); this.islandSize = plugin.getSettings().getSpawn().getSize(); this.center = SWorldPosition.of(centerLocation); this.islandArea.update(this.center.toBlockPosition(), this.islandSize); this.spawnWorldInfo = new WorldInfoImpl(this.spawnWorld.getName(), Dimensions.fromEnvironment(this.spawnWorld.getEnvironment())); this.dirtyChunksContainer = new DirtyChunksContainer(this); BukkitExecutor.sync(() -> biome = getCenter(null /* unused */).getBlock().getBiome()); } @Override public SuperiorPlayer getOwner() { return ownerPlayer.get(); } @Override public UUID getUniqueId() { return spawnUUID; } @Override public long getCreationTime() { return -1; } @Override public String getCreationTimeDate() { return ""; } @Override public void updateDatesFormatter() { // Do nothing. } @Override public IslandCache getCache() { return this.islandCache.get(); } @Override public List getIslandMembers(boolean includeOwner) { return Collections.emptyList(); } @Override public List getIslandMembers(PlayerRole... playerRoles) { return Collections.emptyList(); } @Override public List getBannedPlayers() { return Collections.emptyList(); } @Override public List getIslandVisitors() { return getIslandVisitors(true); } @Override public List getIslandVisitors(boolean vanishPlayers) { return Collections.emptyList(); } @Override public List getAllPlayersInside() { return new SequentialListBuilder().build(playersInside); } @Override public List getUniqueVisitors() { return Collections.emptyList(); } @Override public List> getUniqueVisitorsWithTimes() { return Collections.emptyList(); } @Override public void inviteMember(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public void revokeInvite(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public boolean isInvited(SuperiorPlayer superiorPlayer) { return false; } @Override public List getInvitedPlayers() { return Collections.emptyList(); } @Override public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { // Do nothing. } @Override @Deprecated public void kickMember(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason) { // Do nothing. } @Override public boolean isMember(SuperiorPlayer superiorPlayer) { return false; } @Override public void banMember(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public void banMember(SuperiorPlayer superiorPlayer, SuperiorPlayer whom) { // Do nothing. } @Override public void unbanMember(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public boolean isBanned(SuperiorPlayer superiorPlayer) { return false; } @Override public void addCoop(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public void removeCoop(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public boolean isCoop(SuperiorPlayer superiorPlayer) { return false; } @Override public List getCoopPlayers() { return Collections.emptyList(); } @Override public int getCoopLimit() { return 0; } @Override public void setCoopLimit(int coopLimit) { // Do nothing. } @Override public void setPlayerInside(SuperiorPlayer superiorPlayer, boolean inside) { if (inside) playersInside.add(superiorPlayer); else playersInside.remove(superiorPlayer); } @Override public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean includeCoopStatus) { return true; } @Override public Location getCenter(Dimension unused) { return this.center.toLocation(this.spawnWorld); } @Override public BlockPosition getCenterPosition() { return this.center.toBlockPosition(); } @Override public CompletableFuture accessIslandWorld(Dimension unused) { return CompletableFuture.completedFuture(this.spawnWorld); } public World getSpawnWorld() { return spawnWorld; } public WorldInfo getSpawnWorldInfo() { return spawnWorldInfo; } @Override public Location getIslandHome(Dimension unused) { return getCenter(null /*unused*/); } @Override public WorldPosition getIslandHomePosition(Dimension unused) { return getCenterPosition().toWorldPosition(); } @Override public Map getIslandHomesAsDimensions() { return Collections.singletonMap( plugin.getSettings().getWorlds().getDefaultWorldDimension(), getIslandHome(null /*unused*/)); } @Override @Deprecated public Map getIslandHomes() { return Collections.singletonMap( plugin.getSettings().getWorlds().getDefaultWorldDimension(), getIslandHomePosition(null /*unused*/)); } @Override public void setIslandHome(Location homeLocation) { // Do nothing. } @Override public void setIslandHome(Dimension dimension, Location homeLocation) { // Do nothing. } @Override public void setIslandHome(Dimension dimension, WorldPosition homePosition) { // Do nothing. } @Override public Location getVisitorsLocation(Dimension unused) { return this.getIslandHome(null /*unused*/); } @Override public WorldPosition getVisitorsPosition(Dimension unused) { return getIslandHomePosition(null /*unused*/); } @Override public void setVisitorsLocation(Location visitorsLocation) { // Do nothing. } @Override public void setVisitorsLocation(Dimension dimension, WorldPosition visitorsPosition) { // Do nothing. } @Override public Location getMinimum() { return this.getMinimumPosition().toWorldPosition().toLocation(this.spawnWorld); } @Override public BlockPosition getMinimumPosition() { return getCenterPosition().offset(-this.islandSize, 0, -this.islandSize); } @Override public Location getMinimumProtected() { return this.getMinimum(); } @Override public BlockPosition getMinimumProtectedPosition() { return this.getMinimumPosition(); } @Override public Location getMaximum() { return this.getMaximumPosition().toWorldPosition().toLocation(this.spawnWorld); } @Override public BlockPosition getMaximumPosition() { return getCenterPosition().offset(this.islandSize, 0, this.islandSize); } @Override public Location getMaximumProtected() { return this.getMaximum(); } @Override public BlockPosition getMaximumProtectedPosition() { return this.getMaximumPosition(); } @Override public List getAllChunks() { return getAllChunks(0); } @Override public List getAllChunks(@IslandChunkFlags int flags) { return getAllChunks(plugin.getSettings().getWorlds().getDefaultWorldDimension(), flags); } @Override @Deprecated public List getAllChunks(Dimension unused) { return getAllChunks((Dimension) null /*unused*/, 0); } @Override public List getAllChunks(Dimension unused, @IslandChunkFlags int flags) { boolean onlyProtected = (flags & IslandChunkFlags.ONLY_PROTECTED) != 0; boolean noEmptyChunks = (flags & IslandChunkFlags.NO_EMPTY_CHUNKS) != 0; Location min = onlyProtected ? getMinimumProtected() : getMinimum(); Location max = onlyProtected ? getMaximumProtected() : getMaximum(); Chunk minChunk = min.getChunk(); Chunk maxChunk = max.getChunk(); List chunks = new LinkedList<>(); for (int x = minChunk.getX(); x <= maxChunk.getX(); x++) { for (int z = minChunk.getZ(); z <= maxChunk.getZ(); z++) { boolean addChunk; try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, x, z)) { addChunk = !noEmptyChunks || this.dirtyChunksContainer.isMarkedDirty(chunkPosition); } if (addChunk) chunks.add(minChunk.getWorld().getChunkAt(x, z)); } } return Collections.unmodifiableList(chunks); } @Override public List getLoadedChunks() { return getLoadedChunks(0); } @Override public List getLoadedChunks(@IslandChunkFlags int flags) { return getLoadedChunks(plugin.getSettings().getWorlds().getDefaultWorldDimension(), flags); } @Override public List getLoadedChunks(Dimension unused) { return getLoadedChunks((Dimension) null /*unused*/, 0); } @Override public List getLoadedChunks(Dimension unused, @IslandChunkFlags int flags) { boolean onlyProtected = (flags & IslandChunkFlags.ONLY_PROTECTED) != 0; boolean noEmptyChunks = (flags & IslandChunkFlags.NO_EMPTY_CHUNKS) != 0; Location min = onlyProtected ? getMinimumProtected() : getMinimum(); Location max = onlyProtected ? getMaximumProtected() : getMaximum(); List chunks = new LinkedList<>(); for (int chunkX = min.getBlockX() >> 4; chunkX <= max.getBlockX() >> 4; chunkX++) { for (int chunkZ = min.getBlockZ() >> 4; chunkZ <= max.getBlockZ() >> 4; chunkZ++) { boolean addChunk; try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { addChunk = this.spawnWorld.isChunkLoaded(chunkX, chunkZ) && (!noEmptyChunks || this.dirtyChunksContainer.isMarkedDirty(chunkPosition)); } if (addChunk) chunks.add(this.spawnWorld.getChunkAt(chunkX, chunkZ)); } } return Collections.unmodifiableList(chunks); } @Override public List> getAllChunksAsync(Dimension unused) { return getAllChunksAsync((Dimension) null /*unused*/, 0); } @Override public List> getAllChunksAsync(Dimension unused, @IslandChunkFlags int flags) { return getAllChunksAsync((Dimension) null /*unused*/, flags, null); } @Override public List> getAllChunksAsync(Dimension unused, @Nullable Consumer onChunkLoad) { return getAllChunksAsync((Dimension) null /*unused*/, 0, onChunkLoad); } @Override public List> getAllChunksAsync(Dimension unused, @IslandChunkFlags int flags, @Nullable Consumer onChunkLoad) { return IslandUtils.getAllChunksAsync(this, spawnWorldInfo, flags, ChunkLoadReason.API_REQUEST, onChunkLoad); } @Override public void resetChunks() { // Do nothing. } @Override public void resetChunks(@Nullable Runnable onFinish) { // Do nothing. } @Override public void resetChunks(Dimension dimension) { // Do nothing. } @Override public void resetChunks(Dimension dimension, @Nullable Runnable onFinish) { // Do nothing. } @Override public void resetChunks(@IslandChunkFlags int flags) { // Do nothing. } @Override public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) { // Do nothing. } @Override public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) { // Do nothing. } @Override public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish) { // Do nothing. } @Override public boolean isInside(Location location) { return isInside(location, 0D); } @Override public boolean isInside(Location location, int extraRadius) { return isInside(location, (double) extraRadius); } @Override public boolean isInside(Location location, double extraRadius) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null || !bukkitWorld.equals(this.spawnWorld)) return false; return this.islandArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override public boolean isInside(BlockPosition blockPosition) { return isInside(blockPosition, 0D); } @Override public boolean isInside(BlockPosition blockPosition, int extraRadius) { return isInside(blockPosition, (double) extraRadius); } @Override public boolean isInside(BlockPosition blockPosition, double extraRadius) { return this.islandArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius); } @Override public boolean isInside(WorldPosition worldPosition) { return isInside(worldPosition, 0D); } @Override public boolean isInside(WorldPosition worldPosition, int extraRadius) { return isInside(worldPosition, (double) extraRadius); } @Override public boolean isInside(WorldPosition worldPosition, double extraRadius) { return this.islandArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius); } @Override public boolean isInside(Chunk chunk) { return isInside(chunk.getWorld(), chunk.getX(), chunk.getZ()); } @Override public boolean isInside(World world, int chunkX, int chunkZ) { return isInside(world, chunkX, chunkZ, 0D); } @Override public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) { return isInside(world, chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) { return world.equals(this.spawnWorld) && isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { return isInside(worldInfo, chunkX, chunkZ, 0D); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { return isInside(worldInfo, chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { return this.spawnWorldInfo.getName().equals(worldInfo.getName()) && isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInside(int chunkX, int chunkZ) { return isInside(chunkX, chunkZ, 0D); } @Override public boolean isInside(int chunkX, int chunkZ, int extraRadius) { return isInside(chunkX, chunkZ, (double) extraRadius); } @Override public boolean isInside(int chunkX, int chunkZ, double extraRadius) { return this.islandArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4); } @Override public boolean isInsideRange(Location location) { return isInside(location); } @Override public boolean isInsideRange(Location location, int extraRadius) { return isInside(location, extraRadius); } @Override public boolean isInsideRange(Location location, double extraRadius) { return isInside(location, extraRadius); } @Override public boolean isInsideRange(BlockPosition blockPosition) { return isInside(blockPosition); } @Override public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) { return isInside(blockPosition, extraRadius); } @Override public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) { return isInside(blockPosition, extraRadius); } @Override public boolean isInsideRange(WorldPosition worldPosition) { return isInside(worldPosition); } @Override public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) { return isInside(worldPosition, extraRadius); } @Override public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) { return isInside(worldPosition, extraRadius); } @Override public boolean isInsideRange(Chunk chunk) { return isInside(chunk); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ) { return isInside(world, chunkX, chunkZ); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) { return isInside(world, chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) { return isInside(world, chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) { return isInside(worldInfo, chunkX, chunkZ); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { return isInside(worldInfo, chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { return isInside(worldInfo, chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(int chunkX, int chunkZ) { return isInside(chunkX, chunkZ); } @Override public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) { return isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) { return isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isNormalEnabled() { return false; } @Override public void setNormalEnabled(boolean enabled) { // Do nothing. } @Override public boolean isNetherEnabled() { return false; } @Override public void setNetherEnabled(boolean enabled) { // Do nothing. } @Override public boolean isEndEnabled() { return false; } @Override public void setEndEnabled(boolean enabled) { // Do nothing. } @Override public boolean isDimensionEnabled(Dimension dimension) { return false; } @Override public void setDimensionEnabled(Dimension dimension, boolean enabled) { // Do nothing. } @Override public Collection getUnlockedWorlds() { return Collections.emptyList(); } @Override public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege) { return sender instanceof ConsoleCommandSender || hasPermission(plugin.getPlayers().getSuperiorPlayer(sender), islandPrivilege); } @Override public boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege) { boolean checkForProtection = islandPrivilege != IslandPrivileges.FLY; return (checkForProtection && !plugin.getSettings().getSpawn().isProtected()) || superiorPlayer.hasBypassModeEnabled() || superiorPlayer.hasBypassPermission(islandPrivilege) || superiorPlayer.hasPermissionWithoutOP("superior.admin.bypass.*") || hasPermission(SPlayerRole.guestRole(), islandPrivilege); } @Override public boolean hasPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) { return getRequiredPlayerRole(islandPrivilege).getWeight() <= playerRole.getWeight(); } @Override public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege, boolean value) { // Do nothing. } @Override public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege) { // Do nothing. } @Override public void resetPermissions() { // Do nothing. } @Override public void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value) { // Do nothing. } @Override public void resetPermissions(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public PrivilegeNodeAbstract getPermissionNode(SuperiorPlayer superiorPlayer) { return PlayerPrivilegeNode.EmptyPlayerPermissionNode.INSTANCE; } @Override public PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege) { return DEFAULT_SPAWN_PRIVILEGES_CACHE.contains(islandPrivilege) ? SPlayerRole.guestRole() : SPlayerRole.lastRole(); } @Override public Map getPlayerPermissions() { return Collections.emptyMap(); } @Override public Map getRolePermissions() { return Collections.emptyMap(); } @Override public boolean isSpawn() { return true; } @Override public String getName() { return ""; } @Override public void setName(String islandName) { // Do nothing. } @Override public String getRawName() { return ""; } @Override public String getStrippedName() { return ""; } @Override public String getFormattedName() { return ""; } @Override public String getDescription() { return ""; } @Override public void setDescription(String description) { // Do nothing. } @Override public void disbandIsland() { // Do nothing. } @Override public boolean transferIsland(SuperiorPlayer superiorPlayer) { return false; } @Override public void replacePlayers(SuperiorPlayer originalPlayer, SuperiorPlayer newPlayer) { // Do nothing. } @Override public void calcIslandWorth(SuperiorPlayer asker) { // Do nothing. } @Override public void calcIslandWorth(SuperiorPlayer asker, Runnable callback) { // Do nothing. } @Override public IslandCalculationAlgorithm getCalculationAlgorithm() { return SpawnIslandCalculationAlgorithm.getInstance(); } @Override public void updateBorder() { getAllPlayersInside().forEach(superiorPlayer -> superiorPlayer.updateWorldBorder(this)); } @Override public void updateIslandFly(SuperiorPlayer superiorPlayer) { IslandUtils.updateIslandFly(this, superiorPlayer); } @Override public int getIslandSize() { return islandSize; } @Override public void setIslandSize(int islandSize) { // Do nothing. } @Override public int getIslandSizeRaw() { return islandSize; } @Override public String getDiscord() { return ""; } @Override public void setDiscord(String discord) { // Do nothing. } @Override public String getPaypal() { return ""; } @Override public void setPaypal(String paypal) { // Do nothing. } @Override public Biome getBiome() { return biome; } @Override public void setBiome(Biome biome) { // Do nothing. } @Override public void setBiome(Biome biome, boolean updateBlocks) { // Do nothing. } @Override public boolean isLocked() { return false; } @Override public void setLocked(boolean locked) { // Do nothing. } @Override public boolean isIgnored() { return false; } @Override public void setIgnored(boolean ignored) { // Do nothing. } @Override public void sendMessage(String message) { // Do nothing. } @Override public void sendMessage(String message, UUID... ignoredMembers) { // Do nothing. } @Override public void sendMessage(IMessageComponent messageComponent) { // Do nothing. } @Override public void sendMessage(IMessageComponent messageComponent, Object... args) { // Do nothing. } @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers) { // Do nothing. } @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers, Object... args) { // Do nothing. } @Override public void sendTitle(String title, String subtitle, int fadeIn, int duration, int fadeOut) { // Do nothing. } @Override public void sendTitle(String title, String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers) { // Do nothing. } @Override public void executeCommand(String command, boolean onlyOnlineMembers) { // Do nothing. } @Override public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) { // Do nothing. } @Override public boolean isBeingRecalculated() { return false; } @Override public void updateLastTime() { // Do nothing. } @Override public void setCurrentlyActive() { // Do nothing. } @Override public boolean isCurrentlyActive() { return true; } @Override public void setCurrentlyActive(boolean active) { // Do nothing. } @Override public long getLastTimeUpdate() { return -1; } @Override public void setLastTimeUpdate(long lastTimeUpdate) { // Do nothing. } @Override public IslandBank getIslandBank() { return null; } @Override public BigDecimal getBankLimit() { return IslandUpgradeConstants.NO_BANK_LIMIT_VALUE; } @Override public void setBankLimit(BigDecimal bankLimit) { // Do nothing. } @Override public BigDecimal getBankLimitRaw() { return IslandUpgradeConstants.NO_BANK_LIMIT_VALUE; } @Override public boolean giveInterest(boolean checkOnlineOwner) { return false; } @Override public long getLastInterestTime() { return -1; } @Override public void setLastInterestTime(long lastInterest) { // Do nothing. } @Override public long getNextInterest() { return -1; } @Override public void handleBlockPlace(Block block) { // Do nothing. } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block) { return BlockChangeResult.SUCCESS; } @Override public void handleBlockPlace(Key key) { // Do nothing. } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockPlace(Block block, @Size int amount) { // Do nothing. } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockPlace(Key key, @Size int amount) { // Do nothing. } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockPlace(Block block, @Size int amount, @IslandBlockFlags int flags) { // Do nothing. } @Override public BlockChangeResult handleBlockPlaceWithResult(Block block, @Size int amount, int flags) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockPlace(Key key, @Size int amount, @IslandBlockFlags int flags) { // Do nothing. } @Override public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @IslandBlockFlags int flags) { return BlockChangeResult.SPAWN_ISLAND; } @Override @Deprecated public void handleBlockPlace(Block block, @Size int amount, boolean save) { // Do nothing. } @Override @Deprecated public void handleBlockPlace(Key key, @Size int amount, boolean save) { // Do nothing. } @Override @Deprecated public void handleBlockPlace(Key key, BigInteger amount, boolean save) { // Do nothing. } @Override @Deprecated public void handleBlockPlace(Key key, BigInteger amount, boolean save, boolean updateLastTimeStatus) { // Do nothing. } @Override public void handleBlocksPlace(Map blocks) { // Do nothing. } @Override public Map handleBlocksPlaceWithResult(Map blocks) { return KeyMaps.createEmptyMap(); } @Override public void handleBlocksPlace(Map blocks, int flags) { // Do nothing. } @Override public Map handleBlocksPlaceWithResult(Map blocks, int flags) { return KeyMaps.createEmptyMap(); } @Override public void handleBlockBreak(Block block) { // Do nothing. } @Override public BlockChangeResult handleBlockBreakWithResult(Block block) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockBreak(Key key) { // Do nothing. } @Override public BlockChangeResult handleBlockBreakWithResult(Key key) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockBreak(Block block, @Size int amount) { // Do nothing. } @Override public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockBreak(Key key, @Size int amount) { // Do nothing. } @Override public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockBreak(Block block, @Size int amount, @IslandBlockFlags int flags) { // Do nothing. } @Override public BlockChangeResult handleBlockBreakWithResult(Block block, @Size int amount, int flags) { return BlockChangeResult.SPAWN_ISLAND; } @Override public void handleBlockBreak(Key key, @Size int amount, @IslandBlockFlags int flags) { // Do nothing. } @Override public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, int flags) { return BlockChangeResult.SPAWN_ISLAND; } @Override @Deprecated public void handleBlockBreak(Block block, @Size int amount, boolean save) { // Do nothing. } @Override @Deprecated public void handleBlockBreak(Key key, @Size int amount, boolean save) { // Do nothing. } @Override @Deprecated public void handleBlockBreak(Key key, BigInteger amount, boolean save) { // Do nothing. } @Override public void handleBlocksBreak(Map blocks) { // Do nothing. } @Override public Map handleBlocksBreakWithResult(Map blocks) { return KeyMaps.createEmptyMap(); } @Override public void handleBlocksBreak(Map blocks, @IslandBlockFlags int flags) { // Do nothing. } @Override public Map handleBlocksBreakWithResult(Map blocks, int flags) { return KeyMaps.createEmptyMap(); } @Override public boolean isChunkDirty(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); } } @Override public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null."); Preconditions.checkArgument(this.spawnWorldInfo.getName().equals(worldName) && isInside(chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); } } @Override public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); } } @Override public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markDirty(chunkPosition, save); } } @Override public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markDirty(chunkPosition, save); } } @Override public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markEmpty(chunkPosition, save); } } @Override public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markEmpty(chunkPosition, save); } } @Override public BigInteger getBlockCountAsBigInteger(Key key) { return BigInteger.ZERO; } @Override public Map getBlockCountsAsBigInteger() { return Collections.emptyMap(); } @Override public BigInteger getExactBlockCountAsBigInteger(Key key) { return BigInteger.ZERO; } @Override public void clearBlockCounts() { // Do nothing. } @Override public IslandBlocksTrackerAlgorithm getBlocksTracker() { return SpawnIslandBlocksTrackerAlgorithm.getInstance(); } @Override public BigDecimal getWorth() { return BigDecimal.ZERO; } @Override public BigDecimal getRawWorth() { return BigDecimal.ZERO; } @Override public BigDecimal getBonusWorth() { return BigDecimal.ZERO; } @Override public void setBonusWorth(BigDecimal bonusWorth) { // Do nothing. } @Override public BigDecimal getBonusLevel() { return BigDecimal.ZERO; } @Override public void setBonusLevel(BigDecimal bonusLevel) { // Do nothing. } @Override public BigDecimal getIslandLevel() { return getRawLevel(); } @Override public BigDecimal getRawLevel() { return BigDecimal.ZERO; } @Override public UpgradeLevel getUpgradeLevel(Upgrade upgrade) { return upgrade.getUpgradeLevel(1); } @Override public void setUpgradeLevel(Upgrade upgrade, int level) { // Do nothing. } @Override public Map getUpgrades() { return Collections.emptyMap(); } @Override public void syncUpgrades() { // Do nothing. } @Override public void updateUpgrades() { // Do nothing. } @Override public long getLastTimeUpgrade() { return -1; } @Override public boolean hasActiveUpgradeCooldown() { return false; } @Override public double getCropGrowthMultiplier() { return 1; } @Override public void setCropGrowthMultiplier(double cropGrowth) { // Do nothing. } @Override public double getCropGrowthRaw() { return 1; } @Override public double getSpawnerRatesMultiplier() { return 1; } @Override public void setSpawnerRatesMultiplier(double spawnerRates) { // Do nothing. } @Override public double getSpawnerRatesRaw() { return 1; } @Override public double getMobDropsMultiplier() { return 1; } @Override public void setMobDropsMultiplier(double mobDrops) { // Do nothing. } @Override public double getMobDropsRaw() { return 1; } @Override public int getBlockLimit(Key key) { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public int getExactBlockLimit(Key key) { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public Key getBlockLimitKey(Key key) { return key; } @Override public Map getBlocksLimits() { return Collections.emptyMap(); } @Override public Map getCustomBlocksLimits() { return Collections.emptyMap(); } @Override public void clearBlockLimits() { // Do nothing. } @Override public void setBlockLimit(Key key, int limit) { // Do nothing. } @Override public void removeBlockLimit(Key key) { // Do nothing. } @Override public boolean hasReachedBlockLimit(Key key) { return false; } @Override public boolean hasReachedBlockLimit(Key key, @Size int amount) { return false; } @Override public int getEntityLimit(EntityType entityType) { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public int getEntityLimit(Key key) { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public Map getEntitiesLimitsAsKeys() { return Collections.emptyMap(); } @Override public Map getCustomEntitiesLimits() { return Collections.emptyMap(); } @Override public void clearEntitiesLimits() { // Do nothing. } @Override public void setEntityLimit(EntityType entityType, int limit) { // Do nothing. } @Override public void setEntityLimit(Key key, int limit) { // Do nothing. } @Override public void removeEntityLimit(Key key) { // Do nothing. } @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType) { return hasReachedEntityLimit(entityType, 1); } @Override public CompletableFuture hasReachedEntityLimit(Key key) { return hasReachedEntityLimit(key, 1); } @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType, @Size int amount) { return CompletableFuture.completedFuture(false); } @Override public CompletableFuture hasReachedEntityLimit(Key key, @Size int amount) { return CompletableFuture.completedFuture(false); } @Override public IslandEntitiesTrackerAlgorithm getEntitiesTracker() { return SpawnIslandEntitiesTrackerAlgorithm.getInstance(); } @Override public int getTeamLimit() { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public void setTeamLimit(int teamLimit) { // Do nothing. } @Override public int getTeamLimitRaw() { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public int getWarpsLimit() { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public void setWarpsLimit(int warpsLimit) { // Do nothing. } @Override public int getWarpsLimitRaw() { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public void setPotionEffect(PotionEffectType type, int level) { // Do nothing. } @Override public void removePotionEffect(PotionEffectType type) { // Do nothing. } @Override public int getPotionEffectLevel(PotionEffectType type) { return 0; } @Override public Map getPotionEffects() { return Collections.emptyMap(); } @Override public Map getCustomPotionEffects() { return Collections.emptyMap(); } @Override public void applyEffects(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public void applyEffects() { // Do nothing. } @Override public void removeEffects(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public void removeEffects() { // Do nothing. } @Override public void clearEffects() { // Do nothing. } @Override public void setRoleLimit(PlayerRole playerRole, int limit) { // Do nothing. } @Override public void removeRoleLimit(PlayerRole playerRole) { // Do nothing. } @Override public int getRoleLimit(PlayerRole playerRole) { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public int getRoleLimitRaw(PlayerRole playerRole) { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public Map getRoleLimits() { return Collections.emptyMap(); } @Override public Map getCustomRoleLimits() { return Collections.emptyMap(); } @Override public WarpCategory createWarpCategory(String name) { return null; } @Override public WarpCategory getWarpCategory(String name) { return null; } @Override public WarpCategory getWarpCategory(int slot) { return null; } @Override public void renameCategory(WarpCategory warpCategory, String newName) { // Do nothing. } @Override public void deleteCategory(WarpCategory warpCategory) { // Do nothing. } @Override public Map getWarpCategories() { return Collections.emptyMap(); } @Override public IslandWarp createWarp(String name, Location location, WarpCategory warpCategory) { return null; } @Override public IslandWarp createWarp(String s, WorldInfo worldInfo, WorldPosition worldPosition, WarpCategory warpCategory) { return null; } @Override public void renameWarp(IslandWarp islandWarp, String newName) { // Do nothing. } @Override public IslandWarp getWarp(Location location) { return null; } @Override public IslandWarp getWarp(String name) { return null; } @Override public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) { // Do nothing. } @Override public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) { // Do nothing. } @Override public void deleteWarp(SuperiorPlayer superiorPlayer, Location location) { // Do nothing. } @Override public void deleteWarp(String name) { // Do nothing. } @Override public Map getIslandWarps() { return Collections.emptyMap(); } @Override public Rating getRating(SuperiorPlayer superiorPlayer) { return Rating.UNKNOWN; } @Override public void setRating(SuperiorPlayer superiorPlayer, Rating rating) { // Do nothing. } @Override public void removeRating(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public double getTotalRating() { return 0; } @Override public int getRatingAmount() { return 0; } @Override public Map getRatings() { return Collections.emptyMap(); } @Override public void removeRatings() { // Do nothing. } @Override public boolean hasSettingsEnabled(IslandFlag islandFlag) { return DEFAULT_SPAWN_FLAGS_CACHE.contains(islandFlag); } @Override public Map getAllSettings() { return Collections.emptyMap(); } @Override public void enableSettings(IslandFlag islandFlag) { // Do nothing. } @Override public void disableSettings(IslandFlag islandFlag) { // Do nothing. } @Override public void resetSettings() { // Do nothing. } @Override public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) { // Do nothing. } @Override public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension, @Nullable SuperiorPlayer caller, boolean callEvent) { return true; } @Override public int getGeneratorPercentage(Key key, Dimension dimension) { return 0; } @Override public Map getGeneratorPercentages(Dimension dimension) { return Collections.emptyMap(); } @Override public void setGeneratorAmount(Key key, @Size int amount, Dimension dimension) { // Do nothing. } @Override public void removeGeneratorAmount(Key key, Dimension dimension) { // Do nothing. } @Override public int getGeneratorAmount(Key key, Dimension dimension) { return 0; } @Override public int getGeneratorTotalAmount(Dimension dimension) { return 0; } @Override public Map getGeneratorAmounts(Dimension dimension) { return Collections.emptyMap(); } @Override public Map getCustomGeneratorAmounts(Dimension dimension) { return Collections.emptyMap(); } @Override public void clearGeneratorAmounts(Dimension dimension) { // Do nothing. } @Nullable @Override public Key generateBlock(Location location, boolean optimizeDefaultBlock) { return null; } @Override public Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock) { return null; } @Override public boolean wasSchematicGenerated(Dimension dimension) { return false; } @Override public void setSchematicGenerate(Dimension dimension) { // Do nothing. } @Override public void setSchematicGenerate(Dimension dimension, boolean generated) { // Do nothing. } @Override public Collection getGeneratedSchematics() { return Collections.emptySet(); } @Override public String getSchematicName() { return ""; } @Override public int getPosition(SortingType sortingType) { return -1; } @Override public IslandChest[] getChest() { return EMPTY_ISLAND_CHESTS; } @Override public int getChestSize() { return 0; } @Override public void setChestRows(int index, int rows) { // Do nothing. } @Override public int getCoopLimitRaw() { return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public DatabaseBridge getDatabaseBridge() { return EmptyDatabaseBridge.getInstance(); } @Override public PersistentDataContainer getPersistentDataContainer() { return EmptyPersistentDataContainer.getInstance(); } @Override public boolean isPersistentDataContainerEmpty() { return true; } @Override public void savePersistentDataContainer() { // Do nothing. } @Override public void completeMission(Mission mission) { // Do nothing. } @Override public void resetMission(Mission mission) { // Do nothing. } @Override public boolean hasCompletedMission(Mission mission) { return false; } @Override public boolean canCompleteMissionAgain(Mission mission) { return false; } @Override public int getAmountMissionCompleted(Mission mission) { return 0; } @Override public void setAmountMissionCompleted(Mission mission, int finishCount) { // Do nothing. } @Override public List> getCompletedMissions() { return Collections.emptyList(); } @Override public Map, Integer> getCompletedMissionsWithAmounts() { return Collections.emptyMap(); } @Override public int compareTo(Island o) { return 0; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.island.algorithm; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.MaterialKeySource; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.google.common.base.Preconditions; import java.math.BigInteger; import java.util.Collections; import java.util.Map; public class DefaultIslandBlocksTrackerAlgorithm implements IslandBlocksTrackerAlgorithm { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final KeyMap blockCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); private final Island island; private boolean loadingDataMode = false; public DefaultIslandBlocksTrackerAlgorithm(Island island) { this.island = island; } @Override public boolean trackBlock(Key key, BigInteger amount) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(amount, "amount parameter cannot be null."); if (amount.compareTo(BigInteger.ZERO) == 0) return false; if (!ServerVersion.isLegacy() && key instanceof MaterialKey && ((MaterialKey) key).getMaterialKeySource() == MaterialKeySource.ITEM) key = ((MaterialKey) key).toGlobalKey(); BlockValue blockValue = plugin.getBlockValues().getBlockValue(key); boolean increaseAmount = blockValue != BlockValue.ZERO; boolean hasBlockLimit = island.getBlockLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE; boolean valuesMenu = plugin.getBlockValues().isValuesMenu(key); if (increaseAmount || hasBlockLimit || valuesMenu) { Log.debug(Debug.BLOCK_PLACE, island.getOwner().getName(), key, amount); addCounts(key, amount); return true; } return false; } @Override public boolean untrackBlock(Key key, BigInteger amount) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(amount, "amount parameter cannot be null."); if (amount.compareTo(BigInteger.ZERO) == 0) return false; if (!ServerVersion.isLegacy() && key instanceof MaterialKey && ((MaterialKey) key).getMaterialKeySource() == MaterialKeySource.ITEM) key = ((MaterialKey) key).toGlobalKey(); BlockValue blockValue = plugin.getBlockValues().getBlockValue(key); boolean decreaseAmount = blockValue != BlockValue.ZERO; boolean hasBlockLimit = island.getBlockLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE; boolean valuesMenu = plugin.getBlockValues().isValuesMenu(key); if (decreaseAmount || hasBlockLimit || valuesMenu) { Log.debug(Debug.BLOCK_BREAK, island.getOwner().getName(), key, amount); Key valueKey = plugin.getBlockValues().getBlockKey(key); removeCounts(valueKey, amount); if (loadingDataMode) return true; Key limitKey = island.getBlockLimitKey(valueKey); Key globalKey = ((BaseKey) valueKey).toGlobalKey(); boolean limitCount = false; if (!limitKey.equals(valueKey)) { removeCounts(limitKey, amount); limitCount = true; } if (!globalKey.equals(valueKey) && (!limitCount || !globalKey.equals(limitKey))) { blockValue = plugin.getBlockValues().getBlockValue(globalKey); if (blockValue != BlockValue.ZERO) removeCounts(globalKey, amount); } return true; } return false; } @Override public BigInteger getBlockCount(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return blockCounts.getOrDefault(key, BigInteger.ZERO); } @Override public BigInteger getExactBlockCount(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return blockCounts.getRaw(key, BigInteger.ZERO); } @Override public Map getBlockCounts() { return Collections.unmodifiableMap(this.blockCounts); } @Override public void clearBlockCounts() { this.blockCounts.clear(); } @Override public void setLoadingDataMode(boolean loadingDataMode) { this.loadingDataMode = loadingDataMode; } private void addCounts(Key key, BigInteger amount) { Key valueKey = plugin.getBlockValues().getBlockKey(key); Log.debug(Debug.BLOCK_COUNT_INCREASE, island.getOwner().getName(), key, amount); BigInteger currentAmount = blockCounts.getRaw(valueKey, BigInteger.ZERO); blockCounts.put(valueKey, currentAmount.add(amount)); if (loadingDataMode) return; Key limitKey = island.getBlockLimitKey(valueKey); Key globalKey = ((BaseKey) valueKey).toGlobalKey(); boolean limitCount = false; if (!limitKey.equals(valueKey)) { Log.debugResult(Debug.BLOCK_COUNT_INCREASE, "Limit Key", limitKey); currentAmount = blockCounts.getRaw(limitKey, BigInteger.ZERO); blockCounts.put(limitKey, currentAmount.add(amount)); limitCount = true; } if (!globalKey.equals(valueKey) && (!limitCount || !globalKey.equals(limitKey))) { BlockValue blockValue = plugin.getBlockValues().getBlockValue(globalKey); if (blockValue != BlockValue.ZERO) { Log.debugResult(Debug.BLOCK_COUNT_INCREASE, "Global Key", globalKey); currentAmount = blockCounts.getRaw(globalKey, BigInteger.ZERO); blockCounts.put(globalKey, currentAmount.add(amount)); } } } private void removeCounts(Key key, BigInteger amount) { Log.debug(Debug.BLOCK_COUNT_DECREASE, island.getOwner().getName(), key, amount); BigInteger currentAmount = blockCounts.getRaw(key, BigInteger.ZERO); if (currentAmount.compareTo(amount) <= 0) blockCounts.remove(key); else blockCounts.put(key, currentAmount.subtract(amount)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.island.algorithm; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import org.bukkit.Location; import org.bukkit.World; import java.math.BigInteger; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; public class DefaultIslandCalculationAlgorithm implements IslandCalculationAlgorithm { public static final Synchronized> CACHED_CALCULATED_CHUNKS = Synchronized.of(new Chunk2ObjectMap<>()); private static final List> MINECART_BLOCK_TYPES = createMinecartBlockTypes(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final DefaultIslandCalculationAlgorithm INSTANCE = new DefaultIslandCalculationAlgorithm(); private DefaultIslandCalculationAlgorithm() { } public static DefaultIslandCalculationAlgorithm getInstance() { return INSTANCE; } @Override public CompletableFuture calculateIsland(Island island) { CompletableFuture result = new CompletableFuture<>(); BukkitExecutor.ensureMain(() -> calculateIslandInternal(island, result)); return result; } private void calculateIslandInternal(Island island, CompletableFuture result) { CompletableFutureList> chunksToLoad = new CompletableFutureList<>(plugin.getSettings().getRecalcTaskTimeout()); long profiler = Profiler.start(ProfileType.CALCULATE_ISLAND); Log.debug(Debug.CHUNK_CALCULATION_BLOCKS, island.getOwner().getName()); if (!plugin.getProviders().hasSnapshotsSupport()) { IslandUtils.getChunkCoords(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS) .forEach((worldInfo, worldChunks) -> { // Load the world. World world = plugin.getProviders().getWorldsProvider().getIslandsWorld(island, worldInfo.getDimension()); if (world != null) chunksToLoad.add(plugin.getNMSChunks().calculateChunks(worldChunks, CACHED_CALCULATED_CHUNKS)); }); } else { IslandUtils.getAllChunksAsync(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS, ChunkLoadReason.BLOCKS_RECALCULATE, plugin.getProviders()::takeSnapshots).forEach(completableFuture -> { CompletableFuture> calculateCompletable = new CompletableFuture<>(); completableFuture.whenComplete((chunk, ex) -> { try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { plugin.getNMSChunks().calculateChunks(Collections.singletonList(chunkPosition), CACHED_CALCULATED_CHUNKS) .whenComplete((pair, ex2) -> calculateCompletable.complete(pair)); } }); chunksToLoad.add(calculateCompletable); }); } BlockCountsTracker blockCounts = new BlockCountsTracker(); Set spawnersToCheck = new HashSet<>(); Set chunksToCheck = new HashSet<>(); BukkitExecutor.createTask().runAsync(v -> { chunksToLoad.forEachCompleted(worldCalculatedChunks -> worldCalculatedChunks.forEach(calculatedChunk -> { Log.debugResult(Debug.CHUNK_CALCULATION_BLOCKS, "Chunk Finished", calculatedChunk.getPosition()); // We want to remove spawners from the chunkInfo, as it will be used later calculatedChunk.getBlockCounts().removeIf(key -> key instanceof SpawnerKey); blockCounts.addCounts(calculatedChunk.getBlockCounts()); // Load spawners for (Location location : calculatedChunk.getSpawners()) { Pair spawnerInfo = plugin.getProviders().getSpawnersProvider().getSpawner(location); if (spawnerInfo.getValue() == null) { spawnersToCheck.add(new SpawnerInfo(location, spawnerInfo.getKey())); } else { Key spawnerKey = Keys.ofSpawner(spawnerInfo.getValue(), location); blockCounts.addCounts(spawnerKey, spawnerInfo.getKey()); } } ChunkPosition chunkPosition = calculatedChunk.getPosition(); if (!loadExternalBlocksForChunk(chunkPosition, blockCounts)) chunksToCheck.add(chunkPosition); // Load built-in stacked blocks plugin.getStackedBlocks().forEach(calculatedChunk.getPosition(), stackedBlock -> blockCounts.addCounts(stackedBlock.getBlockKey(), stackedBlock.getAmount() - 1)); plugin.getProviders().releaseSnapshots(calculatedChunk.getPosition()); }), result::completeExceptionally); }).runSync(v -> { Key blockKey; int blockCount; // Calculate spawner counts for (SpawnerInfo spawnerInfo : spawnersToCheck) { try { blockKey = Keys.of(spawnerInfo.location.getBlock()); blockCount = spawnerInfo.spawnerCount; if (blockCount <= 0) { Pair spawnersProviderInfo = plugin.getProviders() .getSpawnersProvider().getSpawner(spawnerInfo.location); blockCount = spawnersProviderInfo.getKey(); String entityType = spawnersProviderInfo.getValue(); if (entityType != null) { blockKey = Keys.ofSpawner(entityType, spawnerInfo.location); } } blockCounts.addCounts(blockKey, blockCount); } catch (Throwable ignored) { } } spawnersToCheck.clear(); // Calculate stacked block counts for (ChunkPosition chunkPosition : chunksToCheck) { loadExternalBlocksForChunk(chunkPosition, blockCounts); } // Calculate minecart block counts MINECART_BLOCK_TYPES.forEach(minecartTypes -> { int count = island.getEntitiesTracker().getEntityCount(minecartTypes.getKey()); if (count > 0) blockCounts.addCounts(minecartTypes.getValue(), count); }); chunksToCheck.clear(); Profiler.end(profiler); result.complete(blockCounts); }); } private static List> createMinecartBlockTypes() { List> minecartBlockTypes = new LinkedList<>(); minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_COMMAND, ConstantKeys.COMMAND_BLOCK)); minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_CHEST, ConstantKeys.CHEST)); minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_FURNACE, ConstantKeys.FURNACE)); minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_TNT, ConstantKeys.TNT)); minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_HOPPER, ConstantKeys.HOPPER)); minecartBlockTypes.add(new Pair<>(ConstantKeys.ENTITY_MINECART_MOB_SPAWNER, ConstantKeys.MOB_SPAWNER)); return Collections.unmodifiableList(minecartBlockTypes); } private boolean loadExternalBlocksForChunk(ChunkPosition chunkPosition, BlockCountsTracker blockCounts) { // Load stacked blocks Collection> stackedBlocks = plugin.getProviders().getStackedBlocksProvider() .getBlocks(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ()); if (stackedBlocks == null) return false; BlockCountsTracker chunkBlockCounts = new BlockCountsTracker(); for (ICustomBlocksProvider customBlocksProvider : plugin.getProviders().getCustomBlocksProviders()) { KeyMap customBlocksCounts = customBlocksProvider.getBlockCountsForChunk(chunkPosition); if (customBlocksCounts == null) return false; customBlocksCounts.forEach(chunkBlockCounts::addCounts); } chunkBlockCounts.blockCounts.forEach((block, count) -> blockCounts.addCounts(block, count.intValue())); for (Pair pair : stackedBlocks) { blockCounts.addCounts(pair.getKey(), pair.getValue() - 1); } return true; } private static class BlockCountsTracker implements IslandCalculationResult { private final KeyMap blockCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); @Override public Map getBlockCounts() { return blockCounts; } public void addCounts(Key blockKey, int amount) { blockCounts.put(blockKey, blockCounts.getRaw(blockKey, BigInteger.ZERO).add(BigInteger.valueOf(amount))); } public void addCounts(KeyMap other) { other.forEach((key, counter) -> addCounts(key, counter.get())); } } private static class SpawnerInfo { private final Location location; private final int spawnerCount; SpawnerInfo(Location location, int spawnerCount) { this.location = location; this.spawnerCount = spawnerCount; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.island.algorithm; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.block.BlockFace; import java.util.UUID; import java.util.concurrent.CompletableFuture; public class DefaultIslandCreationAlgorithm implements IslandCreationAlgorithm { private static final DefaultIslandCreationAlgorithm INSTANCE = new DefaultIslandCreationAlgorithm(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private DefaultIslandCreationAlgorithm() { } public static DefaultIslandCreationAlgorithm getInstance() { return INSTANCE; } @Override public CompletableFuture createIsland(UUID islandUUID, SuperiorPlayer owner, BlockPosition lastIsland, String islandName, Schematic schematic) { Preconditions.checkNotNull(islandUUID, "islandUUID parameter cannot be null."); Preconditions.checkNotNull(owner, "owner parameter cannot be null."); Preconditions.checkNotNull(lastIsland, "lastIsland parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); Preconditions.checkNotNull(schematic, "schematic parameter cannot be null."); return createIsland(Island.newBuilder() .setOwner(owner) .setUniqueId(islandUUID) .setName(islandName) .setSchematicName(schematic.getName()) , lastIsland); } @Override public CompletableFuture createIsland(Island.Builder builder, BlockPosition lastIsland) { Preconditions.checkNotNull(builder, "builder parameter cannot be null."); Preconditions.checkArgument(builder instanceof IslandBuilderImpl, "Cannot create an island from custom builder."); Preconditions.checkNotNull(lastIsland, "lastIsland parameter cannot be null."); try { return createIslandInternal((IslandBuilderImpl) builder, lastIsland); } catch (Throwable error) { CompletableFuture result = new CompletableFuture<>(); result.completeExceptionally(error); return result; } } private CompletableFuture createIslandInternal(IslandBuilderImpl builder, BlockPosition lastIsland) { Schematic schematic = builder.islandType == null ? null : plugin.getSchematics().getSchematic(builder.islandType); Preconditions.checkArgument(builder.owner != null, "Cannot create an island from builder with no valid owner."); Preconditions.checkArgument(schematic != null, "Cannot create an island from builder with invalid schematic name."); Log.debug(Debug.CREATE_ISLAND, builder.owner.getName(), schematic.getName(), lastIsland); // Making sure an island with the same name does not exist. if (!Text.isBlank(builder.islandName) && plugin.getGrid().getIsland(builder.islandName) != null) { Log.debugResult(Debug.CREATE_ISLAND, "Creation Failed", "Island with the name " + builder.islandName + " already exists."); return CompletableFuture.completedFuture(new IslandCreationResult(IslandCreationResult.Status.NAME_OCCUPIED, null, null, false)); } long profiler = Profiler.start(ProfileType.CREATE_ISLAND, schematic.getName()); Location islandLocation = plugin.getProviders().getWorldsProvider().getNextLocation( lastIsland, plugin.getSettings().getIslandHeight(), plugin.getSettings().getMaxIslandSize(), builder.owner.getUniqueId(), builder.uuid ); Log.debugResult(Debug.CREATE_ISLAND, "Next Island Position", islandLocation); Island island = builder.setCenter(islandLocation.add(0.5, 0, 0.5)).build(); island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.IDLE); PluginEvent event = PluginEventsFactory.callIslandCreateEvent(island, builder.owner, builder.islandType, plugin.getSettings().isTeleportOnCreate()); if (event.isCancelled()) { Log.debugResult(Debug.CREATE_ISLAND, "Creation Failed", "Event was cancelled for creating the island '" + builder.islandName + "'."); return CompletableFuture.completedFuture(new IslandCreationResult(IslandCreationResult.Status.EVENT_CANCELLED, null, null, false)); } CompletableFuture completableFuture = new CompletableFuture<>(); // Clone location as pasteSchematic uses the same location in later scheduled tasks Location location = islandLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(); schematic.pasteSchematic(island, location, () -> { plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, builder.owner.getUniqueId(), builder.uuid); completableFuture.complete(new IslandCreationResult(IslandCreationResult.Status.SUCCESS, island, islandLocation, event.getArgs().canTeleport)); island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); Profiler.end(profiler); }, error -> { island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, builder.owner.getUniqueId(), builder.uuid); completableFuture.completeExceptionally(error); Profiler.end(profiler); }); return completableFuture; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.island.algorithm; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.google.common.base.Preconditions; import org.bukkit.World; import org.bukkit.entity.EntityType; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; public class DefaultIslandEntitiesTrackerAlgorithm implements IslandEntitiesTrackerAlgorithm { private static final Set TRACKABLE_ENTITIES = initializeTrackableEntities(); private static final long CALCULATE_DELAY = TimeUnit.MINUTES.toMillis(5); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final KeyMap entityCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.ENTITY_TYPE); private final Island island; private volatile boolean beingRecalculated = false; private volatile long lastCalculateTime = 0L; public DefaultIslandEntitiesTrackerAlgorithm(Island island) { this.island = island; } @Override public boolean trackEntity(Key key, int amount) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Log.debug(Debug.ENTITY_SPAWN, island.getOwner().getName(), key, amount); if (beingRecalculated) { Log.debugResult(Debug.ENTITY_SPAWN, "Return", "Recalculating"); return false; } if (amount <= 0) { Log.debugResult(Debug.ENTITY_SPAWN, "Return", "Negative Amount"); return false; } if (!canTrackEntity(key)) { Log.debugResult(Debug.ENTITY_SPAWN, "Return", "Cannot Track Entity"); return false; } int currentAmount = entityCounts.getOrDefault(key, 0); entityCounts.put(key, currentAmount + amount); Log.debugResult(Debug.ENTITY_SPAWN, "Return", "Success"); return true; } @Override public boolean untrackEntity(Key key, int amount) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Log.debug(Debug.ENTITY_DESPAWN, island.getOwner().getName(), key, amount); if (beingRecalculated) { Log.debugResult(Debug.ENTITY_DESPAWN, "Return", "Recalculating"); return false; } if (amount <= 0) { Log.debugResult(Debug.ENTITY_DESPAWN, "Return", "Negative Amount"); return false; } if (!canTrackEntity(key)) { Log.debugResult(Debug.ENTITY_DESPAWN, "Return", "Cannot Untrack Entity"); return false; } int currentAmount = entityCounts.getOrDefault(key, -1); if (currentAmount != -1) { if (currentAmount > amount) { entityCounts.put(key, currentAmount - amount); } else { entityCounts.remove(key); } } Log.debugResult(Debug.ENTITY_DESPAWN, "Return", "Success"); return true; } @Override public int getEntityCount(Key key) { return entityCounts.getOrDefault(key, 0); } @Override public Map getEntitiesCounts() { return Collections.unmodifiableMap(entityCounts); } @Override public void clearEntityCounts() { this.entityCounts.clear(); } @Override public void recalculateEntityCounts() { if (beingRecalculated || !canRecalculateEntityCounts()) return; this.beingRecalculated = true; Log.debug(Debug.CHUNK_CALCULATION_ENTITIES, island.getOwner().getName()); try { this.lastCalculateTime = System.currentTimeMillis(); CompletableFutureList> chunkEntities = new CompletableFutureList<>(-1); IslandUtils.getChunkCoords(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS) .forEach(((worldInfo, worldChunks) -> { // Load the world. World world = plugin.getProviders().getWorldsProvider().getIslandsWorld(island, worldInfo.getDimension()); if (world != null) chunkEntities.add(plugin.getNMSChunks().calculateChunkEntities(worldChunks)); })); BukkitExecutor.async(() -> { try { KeyMap recalculatedEntityCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.ENTITY_TYPE); chunkEntities.forEachCompleted(worldCalculatedChunk -> worldCalculatedChunk.forEach(calculatedChunk -> { Log.debugResult(Debug.CHUNK_CALCULATION_ENTITIES, "Chunk Finished", calculatedChunk.getPosition()); calculatedChunk.getEntityCounts().forEach((entity, count) -> { if (canTrackEntity(entity)) recalculatedEntityCounts.computeIfAbsent(entity, i -> new Counter(0)).inc(count.get()); }); }), error -> { error.printStackTrace(); beingRecalculated = false; }); if (!beingRecalculated) return; clearEntityCounts(); if (!recalculatedEntityCounts.isEmpty()) { recalculatedEntityCounts.forEach((entity, count) -> { Log.debug(Debug.ENTITY_SPAWN, island.getOwner().getName(), entity, count.get()); this.entityCounts.put(entity, count.get()); }); } } finally { IslandsDatabaseBridge.saveEntityCounts(this.island); beingRecalculated = false; } }); } catch (Exception error) { IslandsDatabaseBridge.saveEntityCounts(this.island); beingRecalculated = false; throw error; } } @Override public boolean canRecalculateEntityCounts() { long currentTime = System.currentTimeMillis(); return currentTime - lastCalculateTime > CALCULATE_DELAY; } private boolean canTrackEntity(Key key) { if (island.getEntityLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE) return true; if (key instanceof EntityTypeKey) { return TRACKABLE_ENTITIES.contains(((EntityTypeKey) key).getEntityType()); } else { return key.toString().contains("MINECART"); } } private static Set initializeTrackableEntities() { EnumSet trackableEntities = EnumSet.noneOf(EntityType.class); for (EntityType entityType : EntityType.values()) { if (entityType.name().contains("MINECART")) { trackableEntities.add(entityType); } } return trackableEntities.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(trackableEntities); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/SpawnIslandBlocksTrackerAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.island.algorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.key.Key; import java.math.BigInteger; import java.util.Collections; import java.util.Map; public class SpawnIslandBlocksTrackerAlgorithm implements IslandBlocksTrackerAlgorithm { private static final SpawnIslandBlocksTrackerAlgorithm INSTANCE = new SpawnIslandBlocksTrackerAlgorithm(); private SpawnIslandBlocksTrackerAlgorithm() { } public static SpawnIslandBlocksTrackerAlgorithm getInstance() { return INSTANCE; } @Override public boolean trackBlock(Key key, BigInteger amount) { return false; } @Override public boolean untrackBlock(Key key, BigInteger amount) { return false; } @Override public BigInteger getBlockCount(Key key) { return BigInteger.ZERO; } @Override public BigInteger getExactBlockCount(Key key) { return BigInteger.ZERO; } @Override public Map getBlockCounts() { return Collections.emptyMap(); } @Override public void clearBlockCounts() { // Do nothing. } @Override public void setLoadingDataMode(boolean loadingDataMode) { // Do nothing. } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/SpawnIslandCalculationAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.island.algorithm; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import java.util.Collections; import java.util.concurrent.CompletableFuture; public class SpawnIslandCalculationAlgorithm implements IslandCalculationAlgorithm { private static final SpawnIslandCalculationAlgorithm INSTANCE = new SpawnIslandCalculationAlgorithm(); private static final IslandCalculationResult RESULT = Collections::emptyMap; private SpawnIslandCalculationAlgorithm() { } public static SpawnIslandCalculationAlgorithm getInstance() { return INSTANCE; } @Override public CompletableFuture calculateIsland(Island island) { return CompletableFuture.completedFuture(RESULT); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/SpawnIslandEntitiesTrackerAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.island.algorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.key.Key; import java.util.Collections; import java.util.Map; public class SpawnIslandEntitiesTrackerAlgorithm implements IslandEntitiesTrackerAlgorithm { private static final SpawnIslandEntitiesTrackerAlgorithm INSTANCE = new SpawnIslandEntitiesTrackerAlgorithm(); private SpawnIslandEntitiesTrackerAlgorithm() { } public static SpawnIslandEntitiesTrackerAlgorithm getInstance() { return INSTANCE; } @Override public boolean trackEntity(Key key, int amount) { return false; } @Override public boolean untrackEntity(Key key, int amount) { return false; } @Override public int getEntityCount(Key key) { return 0; } @Override public Map getEntitiesCounts() { return Collections.emptyMap(); } @Override public void clearEntityCounts() { // Do nothing. } @Override public void recalculateEntityCounts() { // Do nothing. } @Override public boolean canRecalculateEntityCounts() { return false; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/bank/SBankTransaction.java ================================================ package com.bgsoftware.superiorskyblock.island.bank; import com.bgsoftware.superiorskyblock.api.enums.BankAction; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Log; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Date; import java.util.Optional; import java.util.UUID; public class SBankTransaction implements BankTransaction { private final UUID player; private final BankAction bankAction; private final int position; private final long time; private final String date; private final String failureReason; private final BigDecimal amount; public SBankTransaction(UUID player, BankAction bankAction, int position, long time, String failureReason, BigDecimal amount) { this.player = player; this.bankAction = bankAction; this.position = position; this.time = time; this.date = Formatters.DATE_FORMATTER.format(new Date(time)); this.failureReason = failureReason == null ? "" : failureReason; this.amount = amount.setScale(2, RoundingMode.HALF_EVEN); } public static Optional fromDatabase(DatabaseResult resultSet) { Optional bankAction = resultSet.getEnum("bank_action", BankAction.class); if (!bankAction.isPresent()) { Log.warn("Cannot load bank transaction with invalid bank action, skipping..."); return Optional.empty(); } Optional amount = resultSet.getBigDecimal("amount"); if (!amount.isPresent()) { Log.warn("Cannot load bank transaction with null amount, skipping..."); return Optional.empty(); } return Optional.of(new SBankTransaction( resultSet.getUUID("player").orElse(null), bankAction.get(), resultSet.getInt("position").orElse(1), resultSet.getLong("time").orElse(System.currentTimeMillis()), resultSet.getString("failure_reason").orElse(""), amount.get() )); } @Override public UUID getPlayer() { return player; } @Override public BankAction getAction() { return bankAction; } @Override public int getPosition() { return position; } @Override public long getTime() { return time; } @Override public String getDate() { return date; } @Override public String getFailureReason() { return failureReason; } @Override public BigDecimal getAmount() { return amount; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java ================================================ package com.bgsoftware.superiorskyblock.island.bank; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BankAction; import com.bgsoftware.superiorskyblock.api.hooks.EconomyProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.bank.logs.CacheBankLogs; import com.bgsoftware.superiorskyblock.island.bank.logs.DatabaseBankLogs; import com.bgsoftware.superiorskyblock.island.bank.logs.IBankLogs; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; public class SIslandBank implements IslandBank { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final BigDecimal MONEY_FAILURE = BigDecimal.valueOf(-1); private static final UUID CONSOLE_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000"); private final AtomicReference balance = new AtomicReference<>(BigDecimal.ZERO); private final Island island; private final Supplier isGiveInterestFailed; private final IBankLogs bankLogs; public SIslandBank(Island island, Supplier isGiveInterestFailed) { this.island = island; this.isGiveInterestFailed = isGiveInterestFailed; this.bankLogs = BuiltinModules.BANK.getConfiguration().isCacheAllLogs() ? new CacheBankLogs() : new DatabaseBankLogs(island); } @Override public BigDecimal getBalance() { return balance.get(); } @Override public void setBalance(BigDecimal balance) { this.balance.set(balance.setScale(2, RoundingMode.HALF_DOWN)); // Trying to give interest again if the last one failed. if (isGiveInterestFailed.get()) island.giveInterest(false); } @Override public BankTransaction depositMoney(SuperiorPlayer superiorPlayer, BigDecimal amount) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(amount, "amount parameter cannot be null."); Log.debug(Debug.DEPOSIT_MONEY, island.getOwner().getName(), superiorPlayer.getName(), amount); BankTransaction bankTransaction; String failureReason; if (!island.hasPermission(superiorPlayer, IslandPrivileges.DEPOSIT_MONEY)) { failureReason = "No permission"; } else if (amount.compareTo(BigDecimal.ZERO) <= 0) { failureReason = "Invalid amount"; } else { BigDecimal playerBalance = plugin.getProviders().getBankEconomyProvider().getBalance(superiorPlayer); PluginEvent event = PluginEventsFactory.callIslandBankDepositEvent(island, superiorPlayer, amount); if (event.isCancelled()) { failureReason = event.getArgs().failureReason; } else if (playerBalance.compareTo(amount) < 0) { failureReason = "Not enough money"; } else if (!canDepositMoney(amount)) { failureReason = "Exceed bank limit"; } else { EconomyProvider.EconomyResult result = plugin.getProviders() .withdrawMoneyForBanks(superiorPlayer, amount); failureReason = result.getErrorMessage(); amount = BigDecimal.valueOf(result.getTransactionMoney()); } } int position = this.bankLogs.getLastTransactionPosition() + 1; if (Text.isBlank(failureReason)) { Log.debugResult(Debug.DEPOSIT_MONEY, "Return Success", amount); bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.DEPOSIT_COMPLETED, position, System.currentTimeMillis(), "", amount); increaseBalance(amount); addTransaction(bankTransaction, true); IslandUtils.sendMessage(island, Message.DEPOSIT_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName(), Formatters.NUMBER_FORMATTER.format(amount)); plugin.getMenus().refreshBankLogs(island); plugin.getMenus().refreshIslandBank(island); } else { Log.debugResult(Debug.DEPOSIT_MONEY, "Return Failure", failureReason); bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.DEPOSIT_FAILED, position, System.currentTimeMillis(), failureReason, MONEY_FAILURE); } return bankTransaction; } @Override public BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal amount) { Preconditions.checkNotNull(commandSender, "commandSender parameter cannot be null."); Preconditions.checkNotNull(amount, "amount parameter cannot be null."); Log.debug(Debug.DEPOSIT_MONEY, island.getOwner().getName(), commandSender.getName(), amount); PluginEvent event = PluginEventsFactory.callIslandBankDepositEvent(island, commandSender, amount); UUID senderUUID = commandSender instanceof Player ? ((Player) commandSender).getUniqueId() : null; int position = this.bankLogs.getLastTransactionPosition() + 1; BankAction bankAction; if (event.isCancelled()) { bankAction = BankAction.DEPOSIT_FAILED; Log.debugResult(Debug.DEPOSIT_MONEY, "Return Failure", "Event Cancelled"); } else { bankAction = BankAction.DEPOSIT_COMPLETED; Log.debugResult(Debug.DEPOSIT_MONEY, "Return Success", amount); } BankTransaction bankTransaction = new SBankTransaction(senderUUID, bankAction, position, System.currentTimeMillis(), event.getArgs().failureReason, amount); addTransaction(bankTransaction, true); if (!event.isCancelled()) increaseBalance(amount); plugin.getMenus().refreshBankLogs(island); plugin.getMenus().refreshIslandBank(island); return bankTransaction; } @Override public boolean canDepositMoney(BigDecimal amount) { Preconditions.checkNotNull(amount, "amount parameter cannot be null."); BigDecimal bankLimit = this.island.getBankLimit(); return bankLimit.compareTo(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE) <= 0 || this.balance.get().add(amount).compareTo(bankLimit) <= 0; } @Override public BankTransaction withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal amount, @Nullable List commandsToExecute) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(amount, "amount parameter cannot be null."); Log.debug(Debug.WITHDRAW_MONEY, island.getOwner().getName(), superiorPlayer.getName(), amount, commandsToExecute); BigDecimal withdrawAmount = balance.get().min(amount); BankTransaction bankTransaction; String failureReason; if (!island.hasPermission(superiorPlayer, IslandPrivileges.WITHDRAW_MONEY)) { failureReason = "No permission"; } else if (this.balance.get().compareTo(BigDecimal.ZERO) <= 0) { failureReason = "Bank is empty"; } else if (amount.compareTo(BigDecimal.ZERO) <= 0) { failureReason = "Invalid amount"; } else { PluginEvent event = PluginEventsFactory.callIslandBankWithdrawEvent(island, superiorPlayer, withdrawAmount); if (event.isCancelled()) { failureReason = event.getArgs().failureReason; } else if (commandsToExecute == null || commandsToExecute.isEmpty()) { EconomyProvider.EconomyResult result = plugin.getProviders().depositMoneyForBanks(superiorPlayer, withdrawAmount); failureReason = result.getErrorMessage(); withdrawAmount = BigDecimal.valueOf(result.getTransactionMoney()); } else { String currentBalance = balance.get().toString(); failureReason = ""; commandsToExecute.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command .replace("{0}", superiorPlayer.getName()) .replace("{1}", currentBalance) )); } } int position = this.bankLogs.getLastTransactionPosition() + 1; if (Text.isBlank(failureReason)) { Log.debugResult(Debug.WITHDRAW_MONEY, "Return Success", amount); bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.WITHDRAW_COMPLETED, position, System.currentTimeMillis(), "", withdrawAmount); decreaseBalance(withdrawAmount); addTransaction(bankTransaction, true); IslandUtils.sendMessage(island, Message.WITHDRAW_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName(), Formatters.NUMBER_FORMATTER.format(withdrawAmount)); plugin.getMenus().refreshBankLogs(island); plugin.getMenus().refreshIslandBank(island); } else { Log.debugResult(Debug.DEPOSIT_MONEY, "Return Failure", failureReason); bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.WITHDRAW_FAILED, position, System.currentTimeMillis(), failureReason, MONEY_FAILURE); } return bankTransaction; } @Override public BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecimal amount) { Preconditions.checkNotNull(commandSender, "commandSender parameter cannot be null."); Preconditions.checkNotNull(amount, "amount parameter cannot be null."); Log.debug(Debug.WITHDRAW_MONEY, island.getOwner().getName(), commandSender.getName(), amount); UUID senderUUID = commandSender instanceof Player ? ((Player) commandSender).getUniqueId() : null; int position = this.bankLogs.getLastTransactionPosition() + 1; PluginEvent event = PluginEventsFactory.callIslandBankWithdrawEvent( island, commandSender, amount); BankAction bankAction; if (event.isCancelled()) { bankAction = BankAction.DEPOSIT_FAILED; Log.debugResult(Debug.WITHDRAW_MONEY, "Return Failure", "Event Cancelled"); } else { bankAction = BankAction.DEPOSIT_COMPLETED; Log.debugResult(Debug.WITHDRAW_MONEY, "Return Success", amount); } BankTransaction bankTransaction = new SBankTransaction(senderUUID, bankAction, position, System.currentTimeMillis(), event.getArgs().failureReason, amount); if (!event.isCancelled()) decreaseBalance(amount); addTransaction(bankTransaction, true); plugin.getMenus().refreshBankLogs(island); plugin.getMenus().refreshIslandBank(island); return bankTransaction; } @Override public List getAllTransactions() { return this.bankLogs.getTransactions(); } @Override public List getTransactions(SuperiorPlayer superiorPlayer) { return this.bankLogs.getTransactions(superiorPlayer.getUniqueId()); } @Override public List getConsoleTransactions() { return this.bankLogs.getTransactions(CONSOLE_UUID); } @Override public void loadTransaction(BankTransaction bankTransaction) { addTransaction(bankTransaction, false); } private void addTransaction(BankTransaction bankTransaction, boolean save) { if (!BuiltinModules.BANK.getConfiguration().isBankLogs()) return; UUID senderUUID = bankTransaction.getPlayer(); this.bankLogs.addTransaction(bankTransaction, senderUUID == null ? CONSOLE_UUID : senderUUID, !save); if (save) { IslandsDatabaseBridge.saveBankTransaction(island, bankTransaction); } } private void decreaseBalance(BigDecimal amount) { increaseBalance(amount.negate()); } private void increaseBalance(BigDecimal amount) { this.balance.updateAndGet(bigDecimal -> bigDecimal.add(amount).setScale(3, RoundingMode.HALF_DOWN)); IslandsDatabaseBridge.saveBankBalance(island); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/CacheBankLogs.java ================================================ package com.bgsoftware.superiorskyblock.island.bank.logs; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class CacheBankLogs implements IBankLogs { private final Synchronized> transactions = Synchronized.of(new TreeSet<>(SortingComparators.BANK_TRANSACTIONS_COMPARATOR)); private final Map>> transactionsByPlayers = new ConcurrentHashMap<>(); @Override public int getLastTransactionPosition() { return this.transactions.readAndGet(set -> set.isEmpty() ? 0 : set.last().getPosition()); } @Override public List getTransactions() { return transactions.readAndGet(bankTransactions -> new SequentialListBuilder().build(bankTransactions)); } @Override public List getTransactions(UUID playerUUID) { Synchronized> transactions = this.transactionsByPlayers.get(playerUUID); return transactions == null ? Collections.emptyList() : transactions.readAndGet(Collections::unmodifiableList); } @Override public void addTransaction(BankTransaction bankTransaction, UUID senderUUID, boolean loadFromDatabase) { transactions.write(transactions -> transactions.add(bankTransaction)); transactionsByPlayers.computeIfAbsent(senderUUID, p -> Synchronized.of(new LinkedList<>())) .write(transactions -> transactions.add(bankTransaction)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java ================================================ package com.bgsoftware.superiorskyblock.island.bank.logs; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.island.bank.SBankTransaction; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; @SuppressWarnings("UnstableApiUsage") public class DatabaseBankLogs implements IBankLogs { private final LoadingCache> cachedBankTransactions = CacheBuilder.newBuilder() .maximumSize(1) .expireAfterAccess(10, TimeUnit.MINUTES) .build(new CacheLoader>() { @Override public List load(@NotNull Integer ignored) { sessionBankTransactions.invalidateAll(); return loadTransactionsFromDatabase(); } }); private final LoadingCache> sessionBankTransactions = CacheBuilder.newBuilder() .maximumSize(1) .expireAfterAccess(10, TimeUnit.MINUTES) .build(new CacheLoader>() { @Override public List load(@NotNull Integer ignored) { return new LinkedList<>(); } }); private final Island island; private int lastTransactionPosition = -1; public DatabaseBankLogs(Island island) { this.island = island; } @Override public int getLastTransactionPosition() { if (lastTransactionPosition == -1) { lastTransactionPosition = 0; for (BankTransaction transaction : getTransactions()) { int position = transaction.getPosition(); if (position > lastTransactionPosition) { lastTransactionPosition = position; } } } return lastTransactionPosition++; } @Override public List getTransactions() { return collectBankTransactions(); } @Override public List getTransactions(UUID playerUUID) { return new SequentialListBuilder() .filter(bankTransaction -> playerUUID.equals(bankTransaction.getPlayer())) .build(collectBankTransactions()); } @Override public void addTransaction(BankTransaction bankTransaction, UUID senderUUID, boolean loadFromDatabase) { sessionBankTransactions.getUnchecked(0).add(bankTransaction); } private List collectBankTransactions() { List bankTransactionList = new LinkedList<>(); bankTransactionList.addAll(cachedBankTransactions.getUnchecked(0)); bankTransactionList.addAll(sessionBankTransactions.getUnchecked(0)); return bankTransactionList; } private List loadTransactionsFromDatabase() { List bankTransactionsList = new LinkedList<>(); island.getDatabaseBridge().loadObject("bank_transactions", DatabaseFilter.fromFilter("island", island.getUniqueId().toString()), bankTransactionRow -> SBankTransaction.fromDatabase(new DatabaseResult(bankTransactionRow)) .ifPresent(bankTransactionsList::add)); return bankTransactionsList; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/IBankLogs.java ================================================ package com.bgsoftware.superiorskyblock.island.bank.logs; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import java.util.List; import java.util.UUID; public interface IBankLogs { int getLastTransactionPosition(); List getTransactions(); List getTransactions(UUID playerUUID); void addTransaction(BankTransaction bankTransaction, UUID senderUUID, boolean loadFromDatabase); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java ================================================ package com.bgsoftware.superiorskyblock.island.builder; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.enums.SyncStatus; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PermissionNode; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.DirtyChunk; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.mission.MissionReference; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; public class IslandBuilderImpl implements Island.Builder { private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); private static final int SYNCED_VALUE = -2; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Nullable public SuperiorPlayer owner; public UUID uuid = null; public BlockPosition center = null; public String islandName = ""; @Nullable public String islandType; public long creationTime = System.currentTimeMillis() / 1000; public String discord = "None"; public String paypal = "None"; public BigDecimal bonusWorth = BigDecimal.ZERO; public BigDecimal bonusLevel = BigDecimal.ZERO; public boolean isLocked = plugin.getSettings().isLockedIslands(); public boolean isIgnored = false; public String description = ""; public EnumerateSet generatedSchematics = new EnumerateSet<>(Dimension.values()); public EnumerateSet unlockedWorlds = new EnumerateSet<>(Dimension.values()); public long lastTimeUpdated = System.currentTimeMillis() / 1000; public final Set dirtyChunks = new LinkedHashSet<>(); public final KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); public final KeyMap entityCounts = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); public final EnumerateMap islandHomes = new EnumerateMap<>(Dimension.values()); public final List members = new LinkedList<>(); public final List bannedPlayers = new LinkedList<>(); public final Map playerPermissions = new LinkedHashMap<>(); public final Map rolePermissions = new LinkedHashMap<>(); public final Map upgrades = new LinkedHashMap<>(); public final KeyMap blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); public final Map ratings = new LinkedHashMap<>(); public final Map completedMissions = new LinkedHashMap<>(); public final Map islandFlags = new LinkedHashMap<>(); public final EnumerateMap> cobbleGeneratorValues = new EnumerateMap<>(Dimension.values()); public final List uniqueVisitors = new LinkedList<>(); public final KeyMap entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); public final Map islandEffects = new LinkedHashMap<>(); public final List islandChests = new ArrayList<>(plugin.getSettings().getIslandChests().getDefaultPages()); public final Int2ObjectMapView roleLimits = CollectionsFactory.createInt2ObjectArrayMap(); public final EnumerateMap visitorHomes = new EnumerateMap<>(Dimension.values()); public IntValue islandSize = IntValue.syncedFixed(SYNCED_VALUE); public IntValue warpsLimit = IntValue.syncedFixed(SYNCED_VALUE); public IntValue teamLimit = IntValue.syncedFixed(SYNCED_VALUE); public IntValue coopLimit = IntValue.syncedFixed(SYNCED_VALUE); public DoubleValue cropGrowth = DoubleValue.syncedFixed(SYNCED_VALUE); public DoubleValue spawnerRates = DoubleValue.syncedFixed(SYNCED_VALUE); public DoubleValue mobDrops = DoubleValue.syncedFixed(SYNCED_VALUE); public Value bankLimit = Value.syncedFixed(SYNCED_BANK_LIMIT_VALUE); public BigDecimal balance = BigDecimal.ZERO; public long lastInterestTime = System.currentTimeMillis() / 1000; public List warps = new LinkedList<>(); public List warpCategories = new LinkedList<>(); public List bankTransactions = new LinkedList<>(); public byte[] persistentData = new byte[0]; public IslandBuilderImpl() { } @Override public Island.Builder setOwner(@Nullable SuperiorPlayer owner) { this.owner = owner; return this; } @Override @Nullable public SuperiorPlayer getOwner() { return this.owner; } @Override public Island.Builder setUniqueId(UUID uuid) { Preconditions.checkNotNull(uuid, "uuid parameter cannot be null."); Preconditions.checkState(plugin.getGrid().getIslandByUUID(uuid) == null, "The provided uuid is not unique."); this.uuid = uuid; return this; } @Override public UUID getUniqueId() { return this.uuid; } @Override public Island.Builder setCenter(Location center) { Preconditions.checkNotNull(center, "center parameter cannot be null."); Preconditions.checkState(isValidCenter(center), "The provided center is not centered. center: " + center + ", maxIslandSize: " + plugin.getSettings().getMaxIslandSize()); this.center = SBlockPosition.of(center); return this; } @Override public Location getCenter() { return this.center.toLocation((World) null); } @Override public Island.Builder setName(String islandName) { Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); this.islandName = islandName; return this; } @Override public String getName() { return this.islandName; } @Override public Island.Builder setSchematicName(String islandType) { Preconditions.checkNotNull(islandType, "islandType parameter cannot be null."); this.islandType = islandType; return this; } @Override public String getScehmaticName() { return this.islandType; } @Override public Island.Builder setCreationTime(long creationTime) { this.creationTime = creationTime; return this; } @Override public long getCreationTime() { return this.creationTime; } @Override public Island.Builder setDiscord(String discord) { Preconditions.checkNotNull(discord, "discord parameter cannot be null."); this.discord = discord; return this; } @Override public String getDiscord() { return this.discord; } @Override public Island.Builder setPaypal(String paypal) { Preconditions.checkNotNull(paypal, "paypal parameter cannot be null."); this.paypal = paypal; return this; } @Override public String getPaypal() { return this.paypal; } @Override public Island.Builder setBonusWorth(BigDecimal bonusWorth) { Preconditions.checkNotNull(bonusWorth, "bonusWorth parameter cannot be null."); this.bonusWorth = bonusWorth; return this; } @Override public BigDecimal getBonusWorth() { return this.bonusWorth; } @Override public Island.Builder setBonusLevel(BigDecimal bonusLevel) { Preconditions.checkNotNull(bonusLevel, "bonusLevel parameter cannot be null."); this.bonusLevel = bonusLevel; return this; } @Override public BigDecimal getBonusLevel() { return this.bonusLevel; } @Override public Island.Builder setLocked(boolean isLocked) { this.isLocked = isLocked; return this; } @Override public boolean isLocked() { return this.isLocked; } @Override public Island.Builder setIgnored(boolean isIgnored) { this.isIgnored = isIgnored; return this; } @Override public boolean isIgnored() { return this.isIgnored; } @Override public Island.Builder setDescription(String description) { Preconditions.checkNotNull(description, "description parameter cannot be null."); this.description = description; return this; } @Override public String getDescription() { return this.description; } @Override public Island.Builder setGeneratedSchematic(Dimension dimension) { this.generatedSchematics.add(dimension); return this; } @Override public Set getGeneratedSchematics() { return Collections.unmodifiableSet(this.generatedSchematics.collect(Dimension.values())); } @Override public Island.Builder setUnlockedWorld(Dimension dimension) { this.unlockedWorlds.add(dimension); return this; } @Override public Set getUnlockedWorlds() { return Collections.unmodifiableSet(this.unlockedWorlds.collect(Dimension.values())); } @Override public Island.Builder setLastTimeUpdated(long lastTimeUpdated) { this.lastTimeUpdated = lastTimeUpdated; return this; } @Override public long getLastTimeUpdated() { return this.lastTimeUpdated; } @Override public Island.Builder setDirtyChunk(String worldName, int chunkX, int chunkZ) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null."); this.dirtyChunks.add(new DirtyChunk(worldName, chunkX, chunkZ)); return this; } @Override public boolean isDirtyChunk(String worldName, int chunkX, int chunkZ) { return this.dirtyChunks.contains(new DirtyChunk(worldName, chunkX, chunkZ)); } @Override public Island.Builder setBlockCount(Key block, BigInteger count) { Preconditions.checkNotNull(block, "block parameter cannot be null."); Preconditions.checkNotNull(count, "count parameter cannot be null."); this.blockCounts.put(block, count); return this; } @Override public KeyMap getBlockCounts() { return KeyMaps.unmodifiableKeyMap(this.blockCounts); } @Override public Island.Builder setEntityCount(Key entity, BigInteger count) { Preconditions.checkNotNull(entity, "entity parameter cannot be null."); Preconditions.checkNotNull(count, "count parameter cannot be null."); this.entityCounts.put(entity, count); return this; } @Override public KeyMap getEntityCounts() { return KeyMaps.unmodifiableKeyMap(this.entityCounts); } @Override public Island.Builder setIslandHome(Location location, Dimension dimension) { Preconditions.checkNotNull(location, "location parameter cannot be null."); return setIslandHome(dimension, SWorldPosition.of(location)); } @Override public Island.Builder setIslandHome(Dimension dimension, WorldPosition worldPosition) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); this.islandHomes.put(dimension, worldPosition); return this; } @Override public Map getIslandHomesAsDimensions() { Map islandHomes = new LinkedHashMap<>(); for (Dimension dimension : Dimension.values()) { WorldPosition islandHome = this.islandHomes.get(dimension); if (islandHome != null) { islandHomes.put(dimension, islandHome.toLocation((World) null)); } } return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes); } @Override public Island.Builder addIslandMember(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); this.members.add(superiorPlayer); return this; } @Override public List getIslandMembers() { return Collections.unmodifiableList(this.members); } @Override public Island.Builder addBannedPlayer(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); this.bannedPlayers.add(superiorPlayer); return this; } @Override public List getBannedPlayers() { return Collections.unmodifiableList(this.bannedPlayers); } @Override public Island.Builder setPlayerPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege, boolean value) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); this.playerPermissions.computeIfAbsent(superiorPlayer, p -> new PlayerPrivilegeNode(superiorPlayer, null)) .loadPrivilege(islandPrivilege, (byte) (value ? 1 : 0)); return this; } @Override public Map getPlayerPermissions() { return Collections.unmodifiableMap(this.playerPermissions); } @Override public Island.Builder setRolePermission(IslandPrivilege islandPrivilege, PlayerRole requiredRole) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); Preconditions.checkNotNull(requiredRole, "requiredRole parameter cannot be null."); this.rolePermissions.put(islandPrivilege, requiredRole.getId()); return this; } @Override public Map getRolePermissions() { return Collections.unmodifiableMap(this.rolePermissions.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> plugin.getRoles().getPlayerRoleFromId(entry.getValue()) ))); } @Override public Island.Builder setUpgrade(Upgrade upgrade, int level) { Preconditions.checkNotNull(upgrade, "upgrade parameter cannot be null."); this.upgrades.put(upgrade.getName(), level); return this; } @Override public Map getUpgrades() { return Collections.unmodifiableMap(this.upgrades.entrySet().stream().collect(Collectors.toMap( entry -> plugin.getUpgrades().getUpgrade(entry.getKey()), Map.Entry::getValue ))); } @Override public Island.Builder setBlockLimit(Key block, int limit) { Preconditions.checkNotNull(block, "block parameter cannot be null."); this.blockLimits.put(block, limit < 0 ? IntValue.syncedFixed(limit) : IntValue.fixed(limit)); return this; } @Override public KeyMap getBlockLimits() { return KeyMap.createKeyMap(IntValue.unboxMap(this.blockLimits)); } @Override public Island.Builder setRating(SuperiorPlayer superiorPlayer, Rating rating) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(rating, "rating parameter cannot be null."); this.ratings.put(superiorPlayer.getUniqueId(), rating); return this; } @Override public Map getRatings() { return Collections.unmodifiableMap(this.ratings.entrySet().stream().collect(Collectors.toMap( entry -> plugin.getPlayers().getSuperiorPlayer(entry.getKey()), Map.Entry::getValue ))); } @Override public Island.Builder setCompletedMission(Mission mission, int finishCount) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); this.completedMissions.put(new MissionReference(mission), new Counter(finishCount)); return this; } @Override public Map, Integer> getCompletedMissions() { Map, Integer> completedMissions = new LinkedHashMap<>(); this.completedMissions.forEach((mission, finishCount) -> { if (mission.isValid()) completedMissions.put(mission.getMission(), finishCount.get()); }); return completedMissions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(completedMissions); } @Override public Island.Builder setIslandFlag(IslandFlag islandFlag, boolean value) { Preconditions.checkNotNull(islandFlag, "islandFlag parameter cannot be null."); this.islandFlags.put(islandFlag, (byte) (value ? 1 : 0)); return this; } @Override public Map getIslandFlags() { return Collections.unmodifiableMap(this.islandFlags.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> entry.getValue() == 1 ? SyncStatus.ENABLED : SyncStatus.DISABLED ))); } @Override public Island.Builder setGeneratorRate(Key block, int rate, Dimension dimension) { Preconditions.checkNotNull(block, "block parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension dimension cannot be null."); this.cobbleGeneratorValues.computeIfAbsent(dimension, e -> KeyMaps.createArrayMap(KeyIndicator.MATERIAL)) .put(block, rate < 0 ? IntValue.syncedFixed(rate) : IntValue.fixed(rate)); return this; } @Override public Map> getGeneratorRatesAsDimensions() { Map> result = new IdentityHashMap<>(); for (Dimension dimension : Dimension.values()) { KeyMap generatorRates = this.cobbleGeneratorValues.get(dimension); if (generatorRates != null) { if (generatorRates.isEmpty()) { result.put(dimension, KeyMaps.createEmptyMap()); } else { result.put(dimension, KeyMap.createKeyMap(IntValue.unboxMap(generatorRates))); } } } return Collections.unmodifiableMap(result); } @Override public Island.Builder addUniqueVisitor(SuperiorPlayer superiorPlayer, long visitTime) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); this.uniqueVisitors.add(new SIsland.UniqueVisitor(superiorPlayer, visitTime)); return this; } @Override public Map getUniqueVisitors() { LinkedHashMap result = new LinkedHashMap<>(); this.uniqueVisitors.forEach(uniqueVisitor -> result.put(uniqueVisitor.getSuperiorPlayer(), uniqueVisitor.getLastVisitTime())); return Collections.unmodifiableMap(result); } @Override public Island.Builder setEntityLimit(Key entity, int limit) { Preconditions.checkNotNull(entity, "entity parameter cannot be null."); this.entityLimits.put(entity, limit < 0 ? IntValue.syncedFixed(limit) : IntValue.fixed(limit)); return this; } @Override public KeyMap getEntityLimits() { return KeyMap.createKeyMap(IntValue.unboxMap(this.entityLimits)); } @Override public Island.Builder setIslandEffect(PotionEffectType potionEffectType, int level) { Preconditions.checkNotNull(potionEffectType, "potionEffectType parameter cannot be null."); this.islandEffects.put(potionEffectType, level < 0 ? IntValue.syncedFixed(level) : IntValue.fixed(level)); return this; } @Override public Map getIslandEffects() { return Collections.unmodifiableMap(IntValue.unboxMap(this.islandEffects)); } @Override public Island.Builder setIslandChest(int index, ItemStack[] contents) { Preconditions.checkNotNull(contents, "contents parameter cannot be null."); if (index >= this.islandChests.size()) { while (index > this.islandChests.size()) { this.islandChests.add(new ItemStack[plugin.getSettings().getIslandChests().getDefaultSize() * 9]); } this.islandChests.add(contents); } else { this.islandChests.set(index, contents); } return this; } @Override public List getIslandChests() { return Collections.unmodifiableList(this.islandChests); } @Override public Island.Builder setRoleLimit(PlayerRole playerRole, int limit) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); this.roleLimits.put(playerRole.getId(), limit < 0 ? IntValue.syncedFixed(limit) : IntValue.fixed(limit)); return this; } @Override public Map getRoleLimits() { if (this.roleLimits.isEmpty()) return Collections.emptyMap(); Map roleLimits = new HashMap<>(); Iterator> iterator = this.roleLimits.entryIterator(); while (iterator.hasNext()) { Int2ObjectMapView.Entry entry = iterator.next(); roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get()); } return Collections.unmodifiableMap(roleLimits); } @Override public Island.Builder setVisitorHome(Location location, Dimension dimension) { Preconditions.checkNotNull(location, "location parameter cannot be null."); return setVisitorHome(dimension, SWorldPosition.of(location)); } @Override public Island.Builder setVisitorHome(Dimension dimension, WorldPosition worldPosition) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); this.visitorHomes.put(dimension, worldPosition); return this; } @Override public Map getVisitorHomesAsDimensions() { Map visitorHomes = new LinkedHashMap<>(); for (Dimension dimension : Dimension.values()) { WorldPosition visitorHome = this.visitorHomes.get(dimension); if (visitorHome != null) { visitorHomes.put(dimension, visitorHome.toLocation((World) null)); } } return visitorHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(visitorHomes); } @Override public Island.Builder setIslandSize(int islandSize) { this.islandSize = islandSize < 0 ? IntValue.syncedFixed(islandSize) : IntValue.fixed(islandSize); return this; } @Override public int getIslandSize() { return this.islandSize.get(); } @Override public Island.Builder setTeamLimit(int teamLimit) { this.teamLimit = teamLimit < 0 ? IntValue.syncedFixed(teamLimit) : IntValue.fixed(teamLimit); return this; } @Override public int getTeamLimit() { return this.teamLimit.get(); } @Override public Island.Builder setWarpsLimit(int warpsLimit) { this.warpsLimit = warpsLimit < 0 ? IntValue.syncedFixed(warpsLimit) : IntValue.fixed(warpsLimit); return this; } @Override public int getWarpsLimit() { return this.warpsLimit.get(); } @Override public Island.Builder setCropGrowth(double cropGrowth) { this.cropGrowth = cropGrowth < 0 ? DoubleValue.syncedFixed(cropGrowth) : DoubleValue.fixed(cropGrowth); return this; } @Override public double getCropGrowth() { return this.cropGrowth.get(); } @Override public Island.Builder setSpawnerRates(double spawnerRates) { this.spawnerRates = spawnerRates < 0 ? DoubleValue.syncedFixed(spawnerRates) : DoubleValue.fixed(spawnerRates); return this; } @Override public double getSpawnerRates() { return this.spawnerRates.get(); } @Override public Island.Builder setMobDrops(double mobDrops) { this.mobDrops = mobDrops < 0 ? DoubleValue.syncedFixed(mobDrops) : DoubleValue.fixed(mobDrops); return this; } @Override public double getMobDrops() { return this.mobDrops.get(); } @Override public Island.Builder setCoopLimit(int coopLimit) { this.coopLimit = coopLimit < 0 ? IntValue.syncedFixed(coopLimit) : IntValue.fixed(coopLimit); return this; } @Override public int getCoopLimit() { return this.coopLimit.get(); } @Override public Island.Builder setBankLimit(BigDecimal bankLimit) { Preconditions.checkNotNull(bankLimit, "bankLimit parameter cannot be null."); this.bankLimit = bankLimit.compareTo(SYNCED_BANK_LIMIT_VALUE) <= 0 ? Value.syncedFixed(bankLimit) : Value.fixed(bankLimit); return this; } @Override public BigDecimal getBankLimit() { return this.bankLimit.get(); } @Override public Island.Builder setBalance(BigDecimal balance) { Preconditions.checkNotNull(balance, "balance parameter cannot be null."); this.balance = balance; return this; } @Override public BigDecimal getBalance() { return this.balance; } @Override public Island.Builder setLastInterestTime(long lastInterestTime) { this.lastInterestTime = lastInterestTime; return this; } @Override public long getLastInterestTime() { return this.lastInterestTime; } @Override public Island.Builder addWarp(String name, String category, Location location, boolean isPrivate, @Nullable ItemStack icon) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkNotNull(category, "category parameter cannot be null."); Preconditions.checkNotNull(location, "location parameter cannot be null."); this.warps.add(new WarpRecord(name, category, SWorldPosition.of(location), LazyWorldLocation.getWorldName(location), isPrivate, icon)); return this; } @Override public Island.Builder addWarp(String name, String category, WorldInfo worldInfo, WorldPosition worldPosition, boolean isPrivate, @Nullable ItemStack icon) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkNotNull(category, "category parameter cannot be null."); Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); this.warps.add(new WarpRecord(name, category, worldPosition, worldInfo.getName(), isPrivate, icon)); return this; } @Override public boolean hasWarp(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null"); for (WarpRecord warpRecord : this.warps) { if (warpRecord.name.equals(name)) return true; } return false; } @Override public boolean hasWarp(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null"); WorldPosition worldPosition = SWorldPosition.of(location); String worldName = LazyWorldLocation.getWorldName(location); for (WarpRecord warpRecord : this.warps) { if (warpRecord.worldName.equals(worldName) && warpRecord.worldPosition.equals(worldPosition)) return true; } return false; } @Override public boolean hasWarp(WorldInfo worldInfo, WorldPosition worldPosition) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null"); Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null"); String worldName = worldInfo.getName(); for (WarpRecord warpRecord : this.warps) { if (warpRecord.worldName.equals(worldName) && warpRecord.worldPosition.equals(worldPosition)) return true; } return false; } @Override public Island.Builder addWarpCategory(String name, int slot, @Nullable ItemStack icon) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkArgument(slot >= 0, "slot must be positive."); this.warpCategories.add(new WarpCategoryRecord(name, slot, icon)); return this; } @Override public boolean hasWarpCategory(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null"); for (WarpCategoryRecord warpCategoryRecord : this.warpCategories) { if (warpCategoryRecord.name.equals(name)) return true; } return false; } @Override public Island.Builder addBankTransaction(BankTransaction bankTransaction) { Preconditions.checkNotNull(bankTransaction, "bankTransaction parameter cannot be null."); this.bankTransactions.add(bankTransaction); return this; } @Override public List getBankTransactions() { return Collections.unmodifiableList(this.bankTransactions); } @Override public Island.Builder setPersistentData(byte[] persistentData) { Preconditions.checkNotNull(persistentData, "persistentData parameter cannot be null."); this.persistentData = persistentData; return this; } @Override public byte[] getPersistentData() { return this.persistentData; } @Override public Island build() { if (this.uuid == null) throw new IllegalStateException("Cannot create an island with no valid uuid."); if (this.center == null) throw new IllegalStateException("Cannot create an island with no valid location."); return plugin.getFactory().createIsland(this); } private static boolean isValidCenter(Location center) { int maxIslandSize = plugin.getSettings().getMaxIslandSize() * 3; return center.getBlockX() % maxIslandSize == 0 && center.getBlockZ() % maxIslandSize == 0 && plugin.getGrid().getIslandAt(center) == null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/builder/WarpCategoryRecord.java ================================================ package com.bgsoftware.superiorskyblock.island.builder; import com.bgsoftware.common.annotations.Nullable; import org.bukkit.inventory.ItemStack; public class WarpCategoryRecord { public final String name; public final int slot; @Nullable public final ItemStack icon; public WarpCategoryRecord(String name, int slot, @Nullable ItemStack icon) { this.name = name; this.slot = slot; this.icon = icon; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/builder/WarpRecord.java ================================================ package com.bgsoftware.superiorskyblock.island.builder; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.inventory.ItemStack; public class WarpRecord { public final String name; public final String category; public final WorldPosition worldPosition; public final String worldName; public final boolean isPrivate; @Nullable public final ItemStack icon; public WarpRecord(String name, String category, WorldPosition worldPosition, String worldName, boolean isPrivate, @Nullable ItemStack icon) { this.name = name; this.category = category; this.worldPosition = worldPosition; this.worldName = worldName; this.isPrivate = isPrivate; this.icon = icon; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheImpl.java ================================================ package com.bgsoftware.superiorskyblock.island.cache; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; import com.bgsoftware.superiorskyblock.core.BaseCacheImpl; import java.util.function.Function; public class IslandCacheImpl implements IslandCache { private final BaseCacheImpl> cache = new BaseCacheImpl<>(IslandCacheKey.values()); private final Island island; public IslandCacheImpl(Island island) { this.island = island; } @Override public Island getIsland() { return this.island; } @Override public T store(IslandCacheKey key, T value) { return this.cache.store(key, value); } @Override public T remove(IslandCacheKey key) { return this.cache.remove(key); } @Override public T get(IslandCacheKey key) { return this.cache.get(key); } @Override public T getOrDefault(IslandCacheKey key, T def) { return this.cache.getOrDefault(key, def); } @Override public T computeIfAbsent(IslandCacheKey key, Function, T> mappingFunction) { return this.cache.computeIfAbsent(key, unused -> mappingFunction.apply(key)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheKeys.java ================================================ package com.bgsoftware.superiorskyblock.island.cache; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; import org.bukkit.Chunk; import java.util.Set; @SuppressWarnings({"rawtypes", "unchecked"}) public class IslandCacheKeys { public static final IslandCacheKey> PENDING_LOADED_CHUNKS = (IslandCacheKey>) (IslandCacheKey) register("PENDING_LOADED_CHUNKS", Set.class); private IslandCacheKeys() { } public static void registerCacheKeys() { // Do nothing, only trigger all the register calls } public static IslandCacheKey register(String name, Class valueType) { IslandCacheKey.register(name, valueType); return (IslandCacheKey) IslandCacheKey.getByName(name); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/chunk/DirtyChunksContainer.java ================================================ package com.bgsoftware.superiorskyblock.island.chunk; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.MutableChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import java.util.BitSet; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; public class DirtyChunksContainer { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final EnumerateMap dirtyChunks = new EnumerateMap<>(Dimension.values()); private final Island island; private final int minChunkX; private final int minChunkZ; private final int chunksInXAxis; private final int totalChunksCount; private final boolean shouldSave; public DirtyChunksContainer(Island island) { this.island = island; BlockPosition minimum = island.getMinimumPosition(); this.minChunkX = minimum.getX() >> 4; this.minChunkZ = minimum.getZ() >> 4; BlockPosition maximum = island.getMaximumPosition(); int maxChunkX = maximum.getX() >> 4; int maxChunkZ = maximum.getZ() >> 4; int chunksInZAxis = maxChunkZ - this.minChunkZ; this.chunksInXAxis = maxChunkX - this.minChunkX; this.totalChunksCount = this.chunksInXAxis * chunksInZAxis; this.shouldSave = !island.isSpawn(); } public Island getIsland() { return island; } public boolean isMarkedDirty(ChunkPosition chunkPosition) { int chunkIndex = getChunkIndex(chunkPosition); if (chunkIndex < 0) throw new IllegalStateException("Chunk is not inside island boundaries: " + chunkPosition); BitSet dirtyChunksBitset = this.dirtyChunks.get(chunkPosition.getWorldsInfo().getDimension()); return dirtyChunksBitset != null && !dirtyChunksBitset.isEmpty() && dirtyChunksBitset.get(chunkIndex); } public void markEmpty(ChunkPosition chunkPosition, boolean save) { int chunkIndex = getChunkIndex(chunkPosition); if (chunkIndex < 0) throw new IllegalStateException("Chunk is not inside island boundaries: " + chunkPosition); BitSet dirtyChunksBitset = this.dirtyChunks.get(chunkPosition.getWorldsInfo().getDimension()); boolean isMarkedDirty = dirtyChunksBitset != null && !dirtyChunksBitset.isEmpty() && dirtyChunksBitset.get(chunkIndex); if (isMarkedDirty) { dirtyChunksBitset.clear(chunkIndex); if (this.shouldSave && save) IslandsDatabaseBridge.saveDirtyChunks(this); } } public void markDirty(ChunkPosition chunkPosition, boolean save) { int chunkIndex = getChunkIndex(chunkPosition); if (chunkIndex < 0) throw new IllegalStateException("Chunk is not inside island boundaries: " + chunkPosition); BitSet dirtyChunksBitset = this.dirtyChunks.computeIfAbsent(chunkPosition.getWorldsInfo().getDimension(), e -> new BitSet(this.totalChunksCount)); boolean isMarkedDirty = !dirtyChunksBitset.isEmpty() && dirtyChunksBitset.get(chunkIndex); if (!isMarkedDirty) { dirtyChunksBitset.set(chunkIndex); if (this.shouldSave && save) IslandsDatabaseBridge.saveDirtyChunks(this); } } public void getDirtyChunks(Consumer consumer) { if (this.dirtyChunks.isEmpty()) return; MutableChunkPosition mutableChunkPosition = new MutableChunkPosition(); for (Dimension dimension : Dimension.values()) { BitSet dirtyChunks = this.dirtyChunks.get(dimension); if (dirtyChunks != null && !dirtyChunks.isEmpty()) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); if (worldInfo != null) { for (int j = dirtyChunks.nextSetBit(0); j >= 0; j = dirtyChunks.nextSetBit(j + 1)) { int deltaX = j / this.chunksInXAxis; int deltaZ = j % this.chunksInXAxis; consumer.accept(mutableChunkPosition.reset(worldInfo, deltaX + this.minChunkX, deltaZ + this.minChunkZ)); } } } } } private int getChunkIndex(ChunkPosition chunkPosition) { int deltaX = chunkPosition.getX() - this.minChunkX; int deltaZ = chunkPosition.getZ() - this.minChunkZ; return deltaX * this.chunksInXAxis + deltaZ; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java ================================================ package com.bgsoftware.superiorskyblock.island.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.IslandPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.container.grid.IslandsGrid; import com.bgsoftware.superiorskyblock.island.container.grid.MultiWorldIslandsGrid; import com.bgsoftware.superiorskyblock.island.container.grid.SingleWorldIslandsGrid; import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortMetadata; import com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortPlayerMetadata; import com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortRatingMetadata; import com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortValueMetadata; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class DefaultIslandsContainer implements IslandsContainer { private final Map islandsByUUID = new ConcurrentHashMap<>(); private final Map islandsByNames = new ConcurrentHashMap<>(); private IslandsGrid islandsGrid; private final Map>> sortedIslands = new ConcurrentHashMap<>(); private final EnumerateSet notifiedValues = new EnumerateSet<>(SortingType.values()); private final SuperiorSkyblockPlugin plugin; public DefaultIslandsContainer(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; this.islandsGrid = plugin.getProviders().hasCustomWorldsSupport() ? new MultiWorldIslandsGrid() : new SingleWorldIslandsGrid(); plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.WORLD_PROVIDER_UPDATE_EVENT, this::onWorldsProviderUpdate); } @Override public void addIsland(Island island) { addIslandToGrid(island); this.islandsByUUID.put(island.getUniqueId(), island); this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island); sortedIslands.values().forEach(sortedIslands -> { sortedIslands.write(_sortedIslands -> _sortedIslands.add(island)); }); } private void addIslandToGrid(Island island) { BlockPosition center = island.getCenterPosition(); long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); if (plugin.getProviders().hasCustomWorldsSupport()) { // We don't know the logic of the custom worlds support, therefore we add a position // for every possible world, so there won't be issues with detecting islands later. for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); if (worldInfo != null) islandsGrid.addIsland(worldInfo.getName(), packedPos, island); } } } else { islandsGrid.addIsland(null, packedPos, island); } } @Override public void removeIsland(Island island) { BlockPosition center = island.getCenterPosition(); long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); if (plugin.getProviders().hasCustomWorldsSupport()) { for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); if (worldInfo != null) islandsGrid.removeIslandAt(worldInfo.getName(), packedPos); } } } else { islandsGrid.removeIslandAt(null, packedPos); } this.islandsByUUID.remove(island.getUniqueId()); this.islandsByNames.remove(IslandNames.getNameForLookup(island.getStrippedName())); sortedIslands.values().forEach(sortedIslands -> { sortedIslands.write(_sortedIslands -> _sortedIslands.remove(island)); }); } @Nullable @Override public Island getIslandByUUID(UUID uuid) { return this.islandsByUUID.get(uuid); } @Override public Island getIslandByName(String name) { return this.islandsByNames.get(IslandNames.getNameForLookup(name)); } @Override public void updateIslandName(Island island, String oldName) { Island currentIsland = this.islandsByNames.remove(IslandNames.getNameForLookup(oldName)); if (currentIsland == island) this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island); } @Nullable @Override public Island getIslandAtPosition(int position, SortingType sortingType) { ensureSortingType(sortingType); return this.sortedIslands.get(sortingType).readAndGet(sortedIslands -> { return position < 0 || position >= sortedIslands.size() ? null : sortedIslands.get(position); }); } @Override public int getIslandPosition(Island island, SortingType sortingType) { ensureSortingType(sortingType); return this.sortedIslands.get(sortingType).readAndGet(sortedIslands -> { return sortedIslands.indexOf(island); }); } @Override public int getIslandsAmount() { return this.islandsByUUID.size(); } @Nullable @Override public Island getIslandAt(Location location) { Island island = plugin.getProviders().hasCustomWorldsSupport() ? customWorldsSupportIslandLookup(location) : nativeIslandLookup(location); return island == null || !island.isInside(SWorldPosition.of(location)) ? null : island; } private Island customWorldsSupportIslandLookup(Location location) { long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); String worldName = LazyWorldLocation.getWorldName(location); return this.islandsGrid.getIslandAt(worldName, packedPos); } private Island nativeIslandLookup(Location location) { // We first check that the world is an islands world. World world = location.getWorld(); if (world == null || !plugin.getGrid().isIslandsWorld(world)) return null; long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); return this.islandsGrid.getIslandAt(null, packedPos); } @Override public void sortIslands(SortingType sortingType, Runnable onFinish) { this.sortIslands(sortingType, false, onFinish); } @Override public void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Runnable onFinish) { ensureSortingType(sortingType); Synchronized> sortedIslands = this.sortedIslands.get(sortingType); if (!forceSort && (sortedIslands.readAndGet(List::size) <= 1 || !notifiedValues.remove(sortingType))) { if (onFinish != null) onFinish.run(); return; } BukkitExecutor.ensureAsync(() -> sortIslandsInternal(sortingType, onFinish)); } @Override public void notifyChange(SortingType sortingType, Island island) { notifiedValues.add(sortingType); } @Override public List getSortedIslands(SortingType sortingType) { ensureSortingType(sortingType); return this.sortedIslands.get(sortingType).readAndGet(sortedIslands -> new SequentialListBuilder().build(sortedIslands)); } @Override public List getIslandsUnsorted() { return new SequentialListBuilder().build(this.islandsByUUID.values()); } @Override public void addSortingType(SortingType sortingType, boolean sort) { Preconditions.checkArgument(!sortedIslands.containsKey(sortingType), "You cannot register an existing sorting type to the database."); sortIslandsInternal(sortingType, null); } private void ensureSortingType(SortingType sortingType) { Preconditions.checkState(sortedIslands.containsKey(sortingType), "The sorting-type " + sortingType + " doesn't exist in the database. Please contact author!"); } private void sortIslandsInternal(SortingType sortingType, @Nullable Runnable onFinish) { List existingIslands = new LinkedList<>(islandsByUUID.values()); existingIslands.removeIf(Island::isIgnored); List sortedIslands; if (existingIslands.size() <= 1) { sortedIslands = existingIslands; } else try { if (sortingType == SortingTypes.BY_LEVEL || sortingType == SortingTypes.BY_WORTH || sortingType == SortingTypes.BY_PLAYERS || sortingType == SortingTypes.BY_RATING) { sortedIslands = sortIslandsBuiltinSortingType(existingIslands, sortingType); } else { sortedIslands = existingIslands; sortedIslands.sort(sortingType); } } catch (Throwable error) { Log.warn("An error occurred while sorting islands for sorting-type ", sortingType.getName(), ":"); throw error; } this.sortedIslands.put(sortingType, Synchronized.of(sortedIslands)); if (onFinish != null) onFinish.run(); } private List sortIslandsBuiltinSortingType(List existingIslands, SortingType sortingType) { List> islandMetadatas = new LinkedList<>(); if (sortingType == SortingTypes.BY_WORTH) existingIslands.forEach(island -> islandMetadatas.add(new IslandSortValueMetadata(island, island.getWorth()))); else if (sortingType == SortingTypes.BY_LEVEL) existingIslands.forEach(island -> islandMetadatas.add(new IslandSortValueMetadata(island, island.getIslandLevel()))); else if (sortingType == SortingTypes.BY_RATING) existingIslands.forEach(island -> islandMetadatas.add(new IslandSortRatingMetadata(island))); else /* BY_PLAYERS */ existingIslands.forEach(island -> islandMetadatas.add(new IslandSortPlayerMetadata(island))); if (islandMetadatas.size() > 1) { islandMetadatas.sort(SortingComparators.ISLAND_METADATA_COMPARATOR); } existingIslands.clear(); islandMetadatas.forEach(islandMetadata -> existingIslands.add(islandMetadata.getIsland())); return existingIslands; } private void onWorldsProviderUpdate() { if (plugin.getProviders().hasCustomWorldsSupport() && islandsGrid instanceof SingleWorldIslandsGrid) { // We need to upgrade the grid to a MultiWorldIslandsGrid this.islandsGrid = new MultiWorldIslandsGrid(); // Re-add all registered islands for (Island island : this.islandsByUUID.values()) { addIslandToGrid(island); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java ================================================ package com.bgsoftware.superiorskyblock.island.container.grid; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; public interface IslandsGrid { void addIsland(String worldName, long packedPos, Island island); @Nullable Island removeIslandAt(String worldName, long packedPos); @Nullable Island getIslandAt(String worldName, long packedPos); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java ================================================ package com.bgsoftware.superiorskyblock.island.container.grid; import com.bgsoftware.superiorskyblock.api.island.Island; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class MultiWorldIslandsGrid implements IslandsGrid { private final Map store = new ConcurrentHashMap<>(); @Override public void addIsland(String worldName, long packedPos, Island island) { this.store.computeIfAbsent(worldName, d -> new SingleWorldIslandsGrid()) .addIsland(null, packedPos, island); } @Override public Island removeIslandAt(String worldName, long packedPos) { SingleWorldIslandsGrid worldGrid = this.store.get(worldName); return worldGrid == null ? null : worldGrid.removeIslandAt(null, packedPos); } @Override public Island getIslandAt(String worldName, long packedPos) { SingleWorldIslandsGrid worldGrid = this.store.get(worldName); return worldGrid == null ? null : worldGrid.getIslandAt(null, packedPos); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java ================================================ package com.bgsoftware.superiorskyblock.island.container.grid; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import java.util.concurrent.locks.StampedLock; public class SingleWorldIslandsGrid implements IslandsGrid { private final Long2ObjectMapView store = CollectionsFactory.createLong2ObjectLinkedHashMap(); private final StampedLock lock = new StampedLock(); @Override public void addIsland(String unused, long packedPos, Island island) { long stamp = this.lock.writeLock(); try { this.store.put(packedPos, island); } finally { this.lock.unlockWrite(stamp); } } @Override public Island removeIslandAt(String unused, long packedPos) { long stamp = this.lock.writeLock(); Island oldValue; try { oldValue = this.store.remove(packedPos); } finally { this.lock.unlockWrite(stamp); } return oldValue; } @Override public Island getIslandAt(String unused, long packedPos) { long stamp = this.lock.tryOptimisticRead(); Island island = this.store.get(packedPos); // Validate that no write occurred while reading if (!lock.validate(stamp)) { // Fallback to a proper read lock stamp = this.lock.readLock(); try { island = this.store.get(packedPos); } finally { this.lock.unlockRead(stamp); } } return island; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java ================================================ package com.bgsoftware.superiorskyblock.island.flag; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import java.util.Comparator; import java.util.Locale; public class IslandFlags { public static final IslandFlag ALWAYS_DAY = register("ALWAYS_DAY"); public static final IslandFlag ALWAYS_MIDDLE_DAY = register("ALWAYS_MIDDLE_DAY"); public static final IslandFlag ALWAYS_NIGHT = register("ALWAYS_NIGHT"); public static final IslandFlag ALWAYS_MIDDLE_NIGHT = register("ALWAYS_MIDDLE_NIGHT"); public static final IslandFlag ALWAYS_RAIN = register("ALWAYS_RAIN"); public static final IslandFlag ALWAYS_SHINY = register("ALWAYS_SHINY"); public static final IslandFlag CREEPER_EXPLOSION = register("CREEPER_EXPLOSION"); public static final IslandFlag CROPS_GROWTH = register("CROPS_GROWTH"); public static final IslandFlag EGG_LAY = register("EGG_LAY"); public static final IslandFlag ENDERMAN_GRIEF = register("ENDERMAN_GRIEF"); public static final IslandFlag FIRE_SPREAD = register("FIRE_SPREAD"); public static final IslandFlag GHAST_FIREBALL = register("GHAST_FIREBALL"); public static final IslandFlag LAVA_FLOW = register("LAVA_FLOW"); public static final IslandFlag PVP = register("PVP"); public static final IslandFlag TNT_EXPLOSION = register("TNT_EXPLOSION"); public static final IslandFlag TREE_GROWTH = register("TREE_GROWTH"); public static final IslandFlag WATER_FLOW = register("WATER_FLOW"); public static final IslandFlag WITHER_EXPLOSION = register("WITHER_EXPLOSION"); private static String ALL_FLAG_NAMES; private static int KNOWN_FLAGS_COUNT; private IslandFlags() { } public static void registerFlags() { // Do nothing, only trigger all the register calls } public static String getFlagsNames() { if (ALL_FLAG_NAMES == null || KNOWN_FLAGS_COUNT != IslandFlag.values().size()) { ALL_FLAG_NAMES = Formatters.COMMA_FORMATTER.format(IslandFlag.values().stream() .sorted(Comparator.comparing(IslandFlag::getName)) .map(islandFlag -> islandFlag.getName().toLowerCase(Locale.ENGLISH))); KNOWN_FLAGS_COUNT = IslandFlag.values().size(); } return ALL_FLAG_NAMES; } private static IslandFlag register(String name) { IslandFlag.register(name); return IslandFlag.getByName(name); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/notifications/IslandNotifications.java ================================================ package com.bgsoftware.superiorskyblock.island.notifications; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import java.util.Collections; public class IslandNotifications { private IslandNotifications() { } public static void notifyPlayerQuit(SuperiorPlayer superiorPlayer) { superiorPlayer.updateLastTimeStatus(); Island island = superiorPlayer.getIsland(); if (island == null) return; IslandUtils.sendMessage(island, Message.PLAYER_QUIT_ANNOUNCEMENT, Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName()); boolean anyOnline = island.getIslandMembers(true).stream().anyMatch(islandMember -> islandMember != superiorPlayer && islandMember.isOnline()); if (!anyOnline) { island.setLastTimeUpdate(System.currentTimeMillis() / 1000); island.setCurrentlyActive(false); } } public static void notifyPlayerJoin(SuperiorPlayer superiorPlayer) { superiorPlayer.updateLastTimeStatus(); Island island = superiorPlayer.getIsland(); if (island == null) return; IslandUtils.sendMessage(island, Message.PLAYER_JOIN_ANNOUNCEMENT, Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName()); island.updateLastTime(); island.setCurrentlyActive(true); // Give interest as soon as the owner joins the server if (BuiltinModules.BANK.getConfiguration().isBankInterestEnabled() && superiorPlayer == island.getOwner()) { int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval(); long currentTime = System.currentTimeMillis() / 1000; long ticksToNextInterest = (bankInterestInterval - (currentTime - island.getLastInterestTime())) * 20; if (ticksToNextInterest <= 0) { island.giveInterest(false); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/preview/DefaultIslandPreviews.java ================================================ package com.bgsoftware.superiorskyblock.island.preview; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class DefaultIslandPreviews implements IslandPreviews { private final Map islandPreviews = new ConcurrentHashMap<>(); @Override public void startIslandPreview(IslandPreview islandPreview) { this.islandPreviews.put(islandPreview.getPlayer().getUniqueId(), islandPreview); } @Override public IslandPreview endIslandPreview(SuperiorPlayer superiorPlayer) { return this.islandPreviews.remove(superiorPlayer.getUniqueId()); } @Override public IslandPreview getIslandPreview(SuperiorPlayer superiorPlayer) { return this.islandPreviews.get(superiorPlayer.getUniqueId()); } @Override public List getActivePreviews() { return new SequentialListBuilder().build(this.islandPreviews.values()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/preview/IslandPreviews.java ================================================ package com.bgsoftware.superiorskyblock.island.preview; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.util.List; public interface IslandPreviews { void startIslandPreview(IslandPreview islandPreview); IslandPreview endIslandPreview(SuperiorPlayer superiorPlayer); IslandPreview getIslandPreview(SuperiorPlayer superiorPlayer); List getActivePreviews(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java ================================================ package com.bgsoftware.superiorskyblock.island.preview; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import com.google.common.base.Preconditions; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.entity.Player; public class SIslandPreview implements IslandPreview { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final SuperiorPlayer superiorPlayer; private final Location previewLocation; private final Schematic schematic; private final String islandName; private final GameMode previousGameMode; public SIslandPreview(SuperiorPlayer superiorPlayer, Location previewLocation, Schematic schematic, String islandName, GameMode previousGameMode) { this.superiorPlayer = superiorPlayer; this.previewLocation = previewLocation; this.schematic = schematic; this.islandName = islandName; this.previousGameMode = previousGameMode; Player player = superiorPlayer.asPlayer(); Preconditions.checkNotNull(player, "Cannot start island preview to an offline player."); PlayerChat.listen(player, message -> { if (message.equalsIgnoreCase(Message.ISLAND_PREVIEW_CONFIRM_TEXT.getMessage(superiorPlayer.getUserLocale()))) { handleConfirm(); return true; } else if (message.equalsIgnoreCase(Message.ISLAND_PREVIEW_CANCEL_TEXT.getMessage(superiorPlayer.getUserLocale()))) { handleCancel(); return true; } return false; }); } @Override public SuperiorPlayer getPlayer() { return superiorPlayer; } @Override public Location getLocation() { return previewLocation.clone(); } @Override public Location getLocation(Location location) { if (location != null) { location.setWorld(this.previewLocation.getWorld()); location.setX(this.previewLocation.getX()); location.setY(this.previewLocation.getY()); location.setZ(this.previewLocation.getZ()); location.setYaw(this.previewLocation.getYaw()); location.setPitch(this.previewLocation.getPitch()); } return location; } @Override public String getSchematic() { return this.schematic.getName(); } @Override public String getIslandName() { return this.islandName; } @Override public GameMode getPreviousGameMode() { return this.previousGameMode; } @Override public void handleConfirm() { MenuIslandCreationConfig creationConfig = plugin.getProviders().getMenusProvider().getIslandCreationConfig(this.schematic); MenuActions.simulateIslandCreationClick(superiorPlayer, islandName, creationConfig, false, superiorPlayer.getOpenedView()); superiorPlayer.runIfOnline(PlayerChat::remove); } @Override public void handleCancel() { plugin.getGrid().cancelIslandPreview(superiorPlayer); Message.ISLAND_PREVIEW_CANCEL.send(superiorPlayer); } @Override public void handleEscape() { plugin.getGrid().cancelIslandPreview(superiorPlayer); Message.ISLAND_PREVIEW_CANCEL_DISTANCE.send(superiorPlayer); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java ================================================ package com.bgsoftware.superiorskyblock.island.privilege; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import java.util.Comparator; import java.util.Locale; import java.util.Objects; public class IslandPrivileges { // Builtin privileges public static final IslandPrivilege ALL = register("ALL"); public static final IslandPrivilege ANIMAL_BREED = register("ANIMAL_BREED"); public static final IslandPrivilege ANIMAL_SHEAR = register("ANIMAL_SHEAR"); public static final IslandPrivilege BAN_MEMBER = register("BAN_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege BREAK = register("BREAK"); public static final IslandPrivilege BRUSH = register("BRUSH", ServerVersion.isAtLeast(ServerVersion.v1_20)); public static final IslandPrivilege BUILD = register("BUILD"); public static final IslandPrivilege CHANGE_NAME = register("CHANGE_NAME", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege CHORUS_FRUIT = register("CHORUS_FRUIT", ServerVersion.isAtLeast(ServerVersion.v1_9)); public static final IslandPrivilege CLOSE_BYPASS = register("CLOSE_BYPASS"); public static final IslandPrivilege CLOSE_ISLAND = register("CLOSE_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege COOP_MEMBER = register("COOP_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DELETE_WARP = register("DELETE_WARP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DEMOTE_MEMBERS = register("DEMOTE_MEMBERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DEPOSIT_MONEY = register("DEPOSIT_MONEY", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DISBAND_ISLAND = register("DISBAND_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DISCORD_SHOW = register("DISCORD_SHOW"); public static final IslandPrivilege DROP_ITEMS = register("DROP_ITEMS"); public static final IslandPrivilege DYE_SHEEP = register("DYE_SHEEP"); public static final IslandPrivilege ENDER_PEARL = register("ENDER_PEARL"); public static final IslandPrivilege ENTITY_RIDE = register("ENTITY_RIDE"); public static final IslandPrivilege EXPEL_BYPASS = register("EXPEL_BYPASS"); public static final IslandPrivilege EXPEL_PLAYERS = register("EXPEL_PLAYERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege FERTILIZE = register("FERTILIZE"); public static final IslandPrivilege FISH = register("FISH"); public static final IslandPrivilege FLY = register("FLY"); public static final IslandPrivilege IGNITE_CREEPER = register("IGNITE_CREEPER"); public static final IslandPrivilege INVITE_MEMBER = register("INVITE_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege ISLAND_CHEST = register("ISLAND_CHEST", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege KICK_MEMBER = register("KICK_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege LEASH = register("LEASH"); public static final IslandPrivilege MINECART_ENTER = register("MINECART_ENTER"); public static final IslandPrivilege MINECART_OPEN = register("MINECART_OPEN"); public static final IslandPrivilege NAME_ENTITY = register("NAME_ENTITY"); public static final IslandPrivilege OPEN_ISLAND = register("OPEN_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege PAYPAL_SHOW = register("PAYPAL_SHOW"); public static final IslandPrivilege PICKUP_DROPS = register("PICKUP_DROPS"); @Nullable public static final IslandPrivilege PROMOTE_MEMBERS = register("PROMOTE_MEMBERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege RANKUP = register("RANKUP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege RATINGS_SHOW = register("RATINGS_SHOW", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SADDLE_ENTITY = register("SADDLE_ENTITY"); @Nullable public static final IslandPrivilege SCULK_SENSOR = register("SCULK_SENSOR", ServerVersion.isAtLeast(ServerVersion.v1_17)); public static final IslandPrivilege SET_BIOME = register("SET_BIOME", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_DISCORD = register("SET_DISCORD", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_HOME = register("SET_HOME", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_PAYPAL = register("SET_PAYPAL", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_PERMISSION = register("SET_PERMISSION", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_ROLE = register("SET_ROLE", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_SETTINGS = register("SET_SETTINGS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_WARP = register("SET_WARP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SPAWNER_BREAK = register("SPAWNER_BREAK"); @Nullable public static final IslandPrivilege UNCOOP_MEMBER = register("UNCOOP_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege VALUABLE_BREAK = register("VALUABLE_BREAK"); public static final IslandPrivilege VILLAGER_TRADING = register("VILLAGER_TRADING"); public static final IslandPrivilege WIND_CHARGE = register("WIND_CHARGE", ServerVersion.isAtLeast(ServerVersion.v1_21)); public static final IslandPrivilege WITHDRAW_MONEY = register("WITHDRAW_MONEY", IslandPrivilege.Type.COMMAND); // Privileges from configurations @Nullable public static IslandPrivilege CONFIG_VAULT_INTERACT; private static String ALL_PRIVILEGE_NAMES; private static int KNOWN_PRIVILEGES_COUNT; private IslandPrivileges() { } public static void registerPrivileges() { // Do nothing, only trigger all the register calls } public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, IslandPrivileges::onSettingsUpdate); } private static void onSettingsUpdate() { CONFIG_VAULT_INTERACT = null; SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); Key vaultKey = Keys.ofMaterialAndData("VAULT"); CONFIG_VAULT_INTERACT = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(vaultKey); } public static String getPrivilegesNames() { if (ALL_PRIVILEGE_NAMES == null || KNOWN_PRIVILEGES_COUNT != IslandPrivilege.values().size()) { ALL_PRIVILEGE_NAMES = Formatters.COMMA_FORMATTER.format(IslandPrivilege.values().stream() .sorted(Comparator.comparing(IslandPrivilege::getName)) .map(islandPrivilege -> islandPrivilege.getName().toLowerCase(Locale.ENGLISH))); KNOWN_PRIVILEGES_COUNT = IslandPrivilege.values().size(); } return ALL_PRIVILEGE_NAMES; } @NotNull private static IslandPrivilege register(String name) { return Objects.requireNonNull(register(name, true)); } @NotNull private static IslandPrivilege register(String name, IslandPrivilege.Type type) { return Objects.requireNonNull(register(name, type, true)); } @Nullable private static IslandPrivilege register(String name, boolean registerCheck) { return register(name, IslandPrivilege.Type.ACTION, registerCheck); } @Nullable private static IslandPrivilege register(String name, IslandPrivilege.Type type, boolean registerCheck) { if (!registerCheck) return null; IslandPrivilege.register(name, type); return IslandPrivilege.getByName(name); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/privilege/PlayerPrivilegeNode.java ================================================ package com.bgsoftware.superiorskyblock.island.privilege; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.google.common.base.Preconditions; public class PlayerPrivilegeNode extends PrivilegeNodeAbstract { protected final SuperiorPlayer superiorPlayer; protected Island island; public PlayerPrivilegeNode(SuperiorPlayer superiorPlayer, Island island) { this.superiorPlayer = superiorPlayer; this.island = island; } public PlayerPrivilegeNode(SuperiorPlayer superiorPlayer, Island island, String permissions) { this.superiorPlayer = superiorPlayer; this.island = island; setPermissions(permissions, false); } private PlayerPrivilegeNode(@Nullable EnumerateMap privileges, SuperiorPlayer superiorPlayer, Island island) { super(privileges); this.superiorPlayer = superiorPlayer; this.island = island; } public void setIsland(Island island) { this.island = island; } @Override public boolean hasPermission(IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); return getStatus(IslandPrivileges.ALL) == PrivilegeStatus.ENABLED || getStatus(islandPrivilege) == PrivilegeStatus.ENABLED; } @Override public PrivilegeNodeAbstract clone() { return new PlayerPrivilegeNode(privileges, superiorPlayer, island); } public void loadPrivilege(IslandPrivilege islandPrivilege, byte status) { privileges.put(islandPrivilege, PrivilegeStatus.of(status)); } protected PrivilegeStatus getStatus(IslandPrivilege islandPrivilege) { PrivilegeStatus cachedStatus = privileges.getOrDefault(islandPrivilege, PrivilegeStatus.DEFAULT); if (cachedStatus != PrivilegeStatus.DEFAULT) return cachedStatus; PlayerRole playerRole = island.isMember(superiorPlayer) ? superiorPlayer.getPlayerRole() : island.isCoop(superiorPlayer) ? SPlayerRole.coopRole() : SPlayerRole.guestRole(); return island.hasPermission(playerRole, islandPrivilege) ? PrivilegeStatus.ENABLED : PrivilegeStatus.DISABLED; } public static class EmptyPlayerPermissionNode extends PlayerPrivilegeNode { public static final EmptyPlayerPermissionNode INSTANCE; static { INSTANCE = new EmptyPlayerPermissionNode(); } EmptyPlayerPermissionNode() { this(null, null); } EmptyPlayerPermissionNode(SuperiorPlayer superiorPlayer, Island island) { super(null, superiorPlayer, island); } @Override public boolean hasPermission(IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); return superiorPlayer != null && island != null && super.hasPermission(islandPrivilege); } @Override protected PrivilegeStatus getStatus(IslandPrivilege islandPrivilege) { PlayerRole playerRole = island.isMember(superiorPlayer) ? superiorPlayer.getPlayerRole() : island.isCoop(superiorPlayer) ? SPlayerRole.coopRole() : SPlayerRole.guestRole(); if (island.hasPermission(playerRole, islandPrivilege)) return PrivilegeStatus.ENABLED; return PrivilegeStatus.DISABLED; } @Override public void setPermission(IslandPrivilege permission, boolean value) { // Do nothing. } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/privilege/PrivilegeNodeAbstract.java ================================================ package com.bgsoftware.superiorskyblock.island.privilege; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PermissionNode; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.util.Map; public abstract class PrivilegeNodeAbstract implements PermissionNode { protected final EnumerateMap privileges; protected PrivilegeNodeAbstract() { this.privileges = new EnumerateMap<>(IslandPrivilege.values()); } protected PrivilegeNodeAbstract(EnumerateMap privileges) { this.privileges = new EnumerateMap<>(privileges); } protected void setPermissions(@Nullable String permissions, boolean checkDefaults) { if (Text.isBlank(permissions)) return; String[] permission = permissions.split(";"); for (String perm : permission) { String[] permissionSections = perm.split(":"); try { IslandPrivilege islandPrivilege = IslandPrivilege.getByName(permissionSections[0]); if (permissionSections.length == 2) { privileges.put(islandPrivilege, PrivilegeStatus.of(permissionSections[1])); } else { if (!checkDefaults || !isDefault(islandPrivilege)) privileges.put(islandPrivilege, PrivilegeStatus.ENABLED); } } catch (NullPointerException ignored) { // Ignored - invalid privilege. } catch (Exception error) { Log.error(error, "An unexpected error while loading permissions for '", perm, "':"); } } } @Override public abstract boolean hasPermission(IslandPrivilege permission); @Override public void setPermission(IslandPrivilege islandPrivilege, boolean value) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); this.privileges.put(islandPrivilege, value ? PrivilegeStatus.ENABLED : PrivilegeStatus.DISABLED); } @Override public Map getCustomPermissions() { return this.privileges.collect(IslandPrivilege.values(), privilegeStatus -> privilegeStatus == PrivilegeStatus.ENABLED); } @Override public abstract PrivilegeNodeAbstract clone(); protected boolean isDefault(IslandPrivilege islandPrivilege) { return false; } protected enum PrivilegeStatus { ENABLED, DISABLED, DEFAULT; static PrivilegeStatus of(String value) throws IllegalArgumentException { switch (value) { case "0": return DISABLED; case "1": return ENABLED; default: return valueOf(value); } } static PrivilegeStatus of(byte value) throws IllegalArgumentException { switch (value) { case 0: return DISABLED; case 1: return ENABLED; default: throw new IllegalArgumentException("Invalid privilege status: " + value); } } @Override public String toString() { switch (this) { case ENABLED: return "1"; case DISABLED: return "0"; default: return name(); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/privilege/RolePrivilegeNode.java ================================================ package com.bgsoftware.superiorskyblock.island.privilege; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.google.common.base.Preconditions; import java.util.LinkedList; import java.util.List; public class RolePrivilegeNode extends PrivilegeNodeAbstract { @Nullable private final SPlayerRole playerRole; private final List linkedNodes = new LinkedList<>(); public RolePrivilegeNode(@Nullable SPlayerRole playerRole, @Nullable RolePrivilegeNode linkedNode) { this(playerRole, linkedNode, null); } public RolePrivilegeNode(@Nullable SPlayerRole playerRole, @Nullable RolePrivilegeNode linkedNode, @Nullable String permissions) { this.playerRole = playerRole; if (linkedNode != null) this.linkedNodes.add(linkedNode); if (!Text.isBlank(permissions)) BukkitExecutor.sync(() -> setPermissions(permissions, playerRole != null), 1L); } private RolePrivilegeNode(EnumerateMap privileges, @Nullable SPlayerRole playerRole, List linkedNodes) { super(privileges); this.playerRole = playerRole; for (RolePrivilegeNode linkedNode : linkedNodes) this.linkedNodes.add(linkedNode.clone()); } public void linkNode(RolePrivilegeNode otherNode) { this.linkedNodes.add(otherNode); } @Override public boolean hasPermission(IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); PrivilegeStatus status = getStatus(islandPrivilege); if (status != PrivilegeStatus.DEFAULT) { return status == PrivilegeStatus.ENABLED; } for (RolePrivilegeNode linkedNode : this.linkedNodes) { status = linkedNode.getStatus(islandPrivilege); if (status != PrivilegeStatus.DEFAULT) { return status == PrivilegeStatus.ENABLED; } } return playerRole != null && playerRole.getDefaultPermissions().hasPermission(islandPrivilege); } @Override public void setPermission(IslandPrivilege islandPrivilege, boolean value) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); setPermission(islandPrivilege, value, true); } @Override public RolePrivilegeNode clone() { return new RolePrivilegeNode(privileges, playerRole, linkedNodes); } @Override protected boolean isDefault(IslandPrivilege islandPrivilege) { if (playerRole != null) { return playerRole.getDefaultPermissions().isDefault(islandPrivilege); } for (RolePrivilegeNode linkedNode : this.linkedNodes) { if (linkedNode.isDefault(islandPrivilege)) return true; } return privileges.containsKey(islandPrivilege); } public PrivilegeStatus getStatus(IslandPrivilege permission) { return privileges.getOrDefault(permission, PrivilegeStatus.DEFAULT); } public void setPermission(IslandPrivilege permission, boolean value, boolean keepDisable) { if (!value && !keepDisable) { privileges.remove(permission); } else { super.setPermission(permission, value); } for (RolePrivilegeNode linkedNode : this.linkedNodes) linkedNode.setPermission(permission, false, false); } @Override public String toString() { return "RolePermissionNode" + privileges; } public static class EmptyRolePermissionNode extends RolePrivilegeNode { public static final EmptyRolePermissionNode INSTANCE; static { INSTANCE = new EmptyRolePermissionNode(); } EmptyRolePermissionNode() { super(null, null); } @Override public boolean hasPermission(IslandPrivilege permission) { return false; } @Override public void setPermission(IslandPrivilege permission, boolean value) { // Do nothing. } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/purge/DefaultIslandsPurger.java ================================================ package com.bgsoftware.superiorskyblock.island.purge; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; public class DefaultIslandsPurger implements IslandsPurger { private final Set scheduledIslands = new HashSet<>(); @Override public void scheduleIslandPurge(Island island) { this.scheduledIslands.add(island); } @Override public void unscheduleIslandPurge(Island island) { this.scheduledIslands.remove(island); } @Override public boolean isIslandPurgeScheduled(Island island) { return this.scheduledIslands.contains(island); } @Override public List getScheduledPurgedIslands() { return new SequentialListBuilder().build(this.scheduledIslands); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/purge/IslandsPurger.java ================================================ package com.bgsoftware.superiorskyblock.island.purge; import com.bgsoftware.superiorskyblock.api.island.Island; import java.util.List; public interface IslandsPurger { void scheduleIslandPurge(Island island); void unscheduleIslandPurge(Island island); boolean isIslandPurgeScheduled(Island island); List getScheduledPurgedIslands(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.island.role; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.RolesManager; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.island.role.container.RolesContainer; import com.google.common.base.Preconditions; import org.bukkit.configuration.ConfigurationSection; import java.util.Comparator; import java.util.LinkedList; import java.util.List; public class RolesManagerImpl extends Manager implements RolesManager { private static final int GUEST_ROLE_INDEX = -2; private static final int COOP_ROLE_INDEX = -1; private final RolesContainer rolesContainer; private int lastRole = Integer.MIN_VALUE; public RolesManagerImpl(SuperiorSkyblockPlugin plugin, RolesContainer rolesContainer) { super(plugin); this.rolesContainer = rolesContainer; } @Override public void loadData() throws ManagerLoadException { this.rolesContainer.clearRoles(); ConfigurationSection rolesSection = plugin.getSettings().getIslandRoles().getSection(); ConfigurationSection guestSection = rolesSection.getConfigurationSection("guest"); if (guestSection == null) throw new ManagerLoadException("Missing \"guest\" section for island roles", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); ConfigurationSection coopSection = rolesSection.getConfigurationSection("coop"); if (coopSection == null) throw new ManagerLoadException("Missing \"coop\" section for island roles", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); SPlayerRole guestsRole = loadRole(guestSection, GUEST_ROLE_INDEX, null); SPlayerRole coopRole = loadRole(coopSection, COOP_ROLE_INDEX, guestsRole); ConfigurationSection laddersSection = rolesSection.getConfigurationSection("ladder"); if (laddersSection == null) throw new ManagerLoadException("Missing \"ladder\" section for island roles", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); List rolesByWeight = new LinkedList<>(); for (String roleSectionName : laddersSection.getKeys(false)) rolesByWeight.add(laddersSection.getConfigurationSection(roleSectionName)); rolesByWeight.sort(Comparator.comparingInt(o -> o.getInt("weight", -1))); SPlayerRole previousRole = coopRole; for (ConfigurationSection roleSection : rolesByWeight) previousRole = loadRole(roleSection, previousRole.getWeight() + 1, previousRole); SPlayerRole.refreshRoles(); } @Override @Nullable public PlayerRole getPlayerRole(int index) { return this.rolesContainer.getPlayerRole(index); } @Override @Nullable public PlayerRole getPlayerRoleFromId(int id) { return this.rolesContainer.getPlayerRoleFromId(id); } @Override public PlayerRole getPlayerRole(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); return this.rolesContainer.getPlayerRole(name); } @Override public PlayerRole getDefaultRole() { return getPlayerRole(0); } @Override public PlayerRole getLastRole() { return getPlayerRole(lastRole); } @Override public PlayerRole getGuestRole() { return getPlayerRole(GUEST_ROLE_INDEX); } @Override public PlayerRole getCoopRole() { return getPlayerRole(COOP_ROLE_INDEX); } @Override public List getRoles() { return this.rolesContainer.getRoles(); } private SPlayerRole loadRole(ConfigurationSection section, int expectedWeight, SPlayerRole previousRole) throws ManagerLoadException { int weight = section.getInt("weight", expectedWeight); if (weight != expectedWeight) throw new ManagerLoadException("The role \"" + section.getName() + "\" has an unexpected weight: " + weight + ", expected: " + expectedWeight, ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); int id = section.getInt("id", weight); String name = section.getString("name"); String displayName = section.getString("display-name"); SPlayerRole playerRole = new SPlayerRole(name, displayName, id, weight, section.getStringList("permissions"), previousRole); this.rolesContainer.addPlayerRole(playerRole); if (weight > lastRole) lastRole = weight; return playerRole; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java ================================================ package com.bgsoftware.superiorskyblock.island.role; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.RolePrivilegeNode; import com.google.common.base.Preconditions; import java.util.List; import java.util.Locale; import java.util.Objects; public class SPlayerRole implements PlayerRole { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static String ALL_ROLE_NAMES; private static String LIMIT_ROLE_NAMES; private static String LADDER_ROLE_NAMES; private final String name; private final String displayName; private final int id; private final int weight; private final RolePrivilegeNode defaultPermissions; public SPlayerRole(String name, @Nullable String displayName, int id, int weight, List defaultPermissions, @Nullable SPlayerRole previousRole) { this.name = name; this.displayName = displayName == null ? name : displayName; this.id = id; this.weight = weight; String permissions = defaultPermissions.isEmpty() ? null : String.join(";", defaultPermissions); this.defaultPermissions = new RolePrivilegeNode(null, previousRole == null ? RolePrivilegeNode.EmptyRolePermissionNode.INSTANCE : previousRole.defaultPermissions, permissions); } public static PlayerRole defaultRole() { return plugin.getRoles().getDefaultRole(); } public static PlayerRole lastRole() { return plugin.getRoles().getLastRole(); } public static PlayerRole guestRole() { return plugin.getRoles().getGuestRole(); } public static PlayerRole coopRole() { return plugin.getRoles().getCoopRole(); } public static PlayerRole of(int weight) { return plugin.getRoles().getPlayerRole(weight); } public static PlayerRole fromId(int id) { return plugin.getRoles().getPlayerRoleFromId(id); } public static PlayerRole of(String name) { return plugin.getRoles().getPlayerRole(name); } public static String getAllRoleNames() { if (ALL_ROLE_NAMES == null) { ALL_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH))); } return ALL_ROLE_NAMES; } public static String getRoleLimitsNames() { if (LIMIT_ROLE_NAMES == null) { LIMIT_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() .filter(IslandUtils::isValidRoleForLimit) .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH))); } return LIMIT_ROLE_NAMES; } public static String getRolesLadderNames() { if (LADDER_ROLE_NAMES == null) { LADDER_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() .filter(PlayerRole::isRoleLadder) .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH))); } return LADDER_ROLE_NAMES; } public static void refreshRoles() { LIMIT_ROLE_NAMES = null; LADDER_ROLE_NAMES = null; } @Override public int getId() { return id; } @Override public String getName() { return name; } @Override public String getDisplayName() { return displayName; } @Override public int getWeight() { return weight; } @Override public boolean isHigherThan(PlayerRole role) { Preconditions.checkNotNull(role, "playerRole parameter cannot be null."); return getWeight() > role.getWeight(); } @Override public boolean isLessThan(PlayerRole role) { Preconditions.checkNotNull(role, "playerRole parameter cannot be null."); return getWeight() < role.getWeight(); } @Override public boolean isFirstRole() { return getWeight() == 0; } @Override public boolean isLastRole() { return getWeight() == lastRole().getWeight(); } @Override public boolean isRoleLadder() { return getWeight() >= 0 && (getPreviousRole() != null || getNextRole() != null); } @Override public PlayerRole getNextRole() { return getWeight() < 0 ? null : plugin.getRoles().getPlayerRole(getWeight() + 1); } @Override public PlayerRole getPreviousRole() { return getWeight() <= 0 ? null : plugin.getRoles().getPlayerRole(getWeight() - 1); } @Override public int hashCode() { return Objects.hash(id); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SPlayerRole that = (SPlayerRole) o; return id == that.id; } @Override public String toString() { return name; } public RolePrivilegeNode getDefaultPermissions() { return defaultPermissions; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/role/container/DefaultRolesContainer.java ================================================ package com.bgsoftware.superiorskyblock.island.role.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.google.common.base.Preconditions; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; public class DefaultRolesContainer implements RolesContainer { private final Int2ObjectMapView rolesByWeight = CollectionsFactory.createInt2ObjectArrayMap(); private final Int2ObjectMapView rolesById = CollectionsFactory.createInt2ObjectArrayMap(); private final Map rolesByName = new HashMap<>(); @Nullable @Override public PlayerRole getPlayerRole(int index) { return rolesByWeight.get(index); } @Nullable @Override public PlayerRole getPlayerRoleFromId(int id) { return rolesById.get(id); } @Override public PlayerRole getPlayerRole(String name) { PlayerRole playerRole = rolesByName.get(name.toUpperCase(Locale.ENGLISH)); Preconditions.checkArgument(playerRole != null, "Invalid role name: " + name); return playerRole; } @Override public List getRoles() { return new SequentialListBuilder() .sorted(Comparator.comparingInt(PlayerRole::getId)) .build(rolesById.valueIterator()); } @Override public void addPlayerRole(PlayerRole playerRole) { this.rolesByWeight.put(playerRole.getWeight(), playerRole); this.rolesById.put(playerRole.getId(), playerRole); this.rolesByName.put(playerRole.getName().toUpperCase(Locale.ENGLISH), playerRole); } @Override public void clearRoles() { this.rolesByWeight.clear(); this.rolesById.clear(); this.rolesByName.clear(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/role/container/RolesContainer.java ================================================ package com.bgsoftware.superiorskyblock.island.role.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import java.util.List; public interface RolesContainer { @Nullable PlayerRole getPlayerRole(int index); @Nullable PlayerRole getPlayerRoleFromId(int id); PlayerRole getPlayerRole(String name); List getRoles(); void addPlayerRole(PlayerRole playerRole); void clearRoles(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java ================================================ package com.bgsoftware.superiorskyblock.island.signs; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.Sign; import java.util.List; public class IslandSigns { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private IslandSigns() { } public static Result handleSignPlace(SuperiorPlayer superiorPlayer, Location warpLocation, String[] warpLines, boolean sendMessage) { // Adjust to the middle of the block warpLocation.add(0.5, 0, 0.5); Island island = plugin.getGrid().getIslandAt(warpLocation); if (island == null) return new Result(Reason.NOT_IN_ISLAND, false); superiorPlayer.runIfOnline(player -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { warpLocation.setYaw(player.getLocation(wrapper.getHandle()).getYaw()); } }); if (isWarpSign(warpLines[0])) { Reason reason = handleWarpSignPlace(superiorPlayer, island, warpLocation, warpLines, sendMessage); return new Result(reason, true); } else if (isVisitorsSign(warpLines[0])) { return handleVisitorsSignPlace(superiorPlayer, island, warpLocation, warpLines, sendMessage); } return new Result(Reason.SUCCESS, false); } public static Result handleSignBreak(@Nullable Island island, @Nullable SuperiorPlayer superiorPlayer, Sign sign) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location signLocation = sign.getLocation(wrapper.getHandle()); if (island == null) { island = plugin.getGrid().getIslandAt(signLocation); if (island == null) return new Result(Reason.NOT_IN_ISLAND, false); } IslandWarp islandWarp = island.getWarp(signLocation); if (islandWarp != null) { if (!PluginEventsFactory.callIslandDeleteWarpEvent(island, superiorPlayer, islandWarp)) return new Result(Reason.EVENT_CANCELLED, true); island.deleteWarp(superiorPlayer, signLocation); } else { if (sign.getLine(0).equalsIgnoreCase(plugin.getSettings().getVisitorsSign().getActive())) { if (!PluginEventsFactory.callIslandRemoveVisitorHomeEvent(island, superiorPlayer)) return new Result(Reason.EVENT_CANCELLED, true); island.setVisitorsLocation(null); } } } return new Result(Reason.SUCCESS, false); } private static Reason handleWarpSignPlace(SuperiorPlayer superiorPlayer, Island island, Location warpLocation, String[] signLines, boolean sendMessage) { int warpsLimit = island.getWarpsLimit(); if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) { if (sendMessage) Message.NO_MORE_WARPS.send(superiorPlayer); return Reason.LIMIT_REACHED; } String warpName = Formatters.STRIP_COLOR_FORMATTER.format(signLines[1].trim()); boolean privateFlag = signLines[2].equalsIgnoreCase("private"); Reason result = Reason.SUCCESS; if (warpName.isEmpty()) { if (sendMessage) Message.WARP_ILLEGAL_NAME.send(superiorPlayer); result = Reason.ILLEGAL_NAME; } else if (island.getWarp(warpName) != null) { if (sendMessage) Message.WARP_ALREADY_EXIST.send(superiorPlayer); result = Reason.ALREADY_EXIST; } else if (!IslandUtils.isWarpNameLengthValid(warpName)) { if (sendMessage) Message.WARP_NAME_TOO_LONG.send(superiorPlayer); result = Reason.NAME_TOO_LONG; } if (!PluginEventsFactory.callIslandCreateWarpEvent(island, superiorPlayer, warpName, warpLocation, !privateFlag, null)) result = Reason.EVENT_CANCELLED; if (result != Reason.SUCCESS) return result; List signWarp = plugin.getSettings().getSignWarp(); for (int i = 0; i < signWarp.size(); i++) signLines[i] = signWarp.get(i).replace("{0}", warpName); IslandWarp islandWarp = island.createWarp(warpName, warpLocation, null); islandWarp.setPrivateFlag(privateFlag); if (sendMessage) Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(warpLocation)); return Reason.SUCCESS; } private static Result handleVisitorsSignPlace(SuperiorPlayer superiorPlayer, Island island, Location visitorsLocation, String[] warpLines, boolean sendMessage) { int warpsLimit = island.getWarpsLimit(); if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) { if (sendMessage) Message.NO_MORE_WARPS.send(superiorPlayer); return new Result(Reason.LIMIT_REACHED, true); } PluginEvent setVisitorHomeEvent = PluginEventsFactory.callIslandSetVisitorHomeEvent(island, superiorPlayer, visitorsLocation); if (setVisitorHomeEvent.isCancelled()) return new Result(Reason.EVENT_CANCELLED, false); StringBuilder descriptionBuilder = new StringBuilder(); for (int i = 1; i < 4; i++) { String line = warpLines[i]; if (!line.isEmpty()) { String formattedLine = plugin.getSettings().getVisitorsSign().getDescriptionLineFormat().replace("{0}", line); descriptionBuilder.append("\n").append(ChatColor.RESET).append(formattedLine); } } String description = descriptionBuilder.length() < 1 ? "" : descriptionBuilder.substring(1); warpLines[0] = plugin.getSettings().getVisitorsSign().getActive(); for (int i = 1; i <= 3; i++) warpLines[i] = Formatters.COLOR_FORMATTER.format(warpLines[i]); Location islandVisitorsLocation = island.getVisitorsLocation((Dimension) null /* unused */); Block oldWelcomeSignBlock = islandVisitorsLocation == null ? null : islandVisitorsLocation.getBlock(); if (oldWelcomeSignBlock != null && Materials.isSign(oldWelcomeSignBlock.getType())) { Sign oldWelcomeSign = (Sign) oldWelcomeSignBlock.getState(); oldWelcomeSign.setLine(0, plugin.getSettings().getVisitorsSign().getInactive()); oldWelcomeSign.update(); } island.setVisitorsLocation(setVisitorHomeEvent.getArgs().islandVisitorHome); PluginEvent changeDescriptionEvent = PluginEventsFactory.callIslandChangeDescriptionEvent(island, superiorPlayer, description); if (!changeDescriptionEvent.isCancelled()) island.setDescription(changeDescriptionEvent.getArgs().description); if (sendMessage) Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(visitorsLocation)); return new Result(Reason.SUCCESS, true); } private static boolean isWarpSign(String firstSignLine) { return firstSignLine.equalsIgnoreCase(plugin.getSettings().getSignWarpLine()); } private static boolean isVisitorsSign(String firstSignLine) { return firstSignLine.equalsIgnoreCase(plugin.getSettings().getVisitorsSign().getLine()); } public enum Reason { NOT_IN_ISLAND, ILLEGAL_NAME, ALREADY_EXIST, NAME_TOO_LONG, LIMIT_REACHED, EVENT_CANCELLED, SUCCESS } public static class Result { private final Reason reason; private final boolean cancelEvent; public Result(Reason reason, boolean cancelEvent) { this.reason = reason; this.cancelEvent = cancelEvent; } public Reason getReason() { return reason; } public boolean isCancelEvent() { return cancelEvent; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingComparators.java ================================================ package com.bgsoftware.superiorskyblock.island.top; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortMetadata; import java.util.Comparator; public class SortingComparators { public final static Comparator PLAYER_NAMES_COMPARATOR = Comparator.comparing(SuperiorPlayer::getName); public final static Comparator PAIRED_PLAYERS_NAMES_COMPARATOR = Comparator.comparing(o -> o.getSuperiorPlayer().getName()); public final static Comparator BANK_TRANSACTIONS_COMPARATOR = Comparator.comparingInt(BankTransaction::getPosition); private final static Comparator ISLAND_NAMES_COMPARATOR = (o1, o2) -> { String firstName = o1.getStrippedName().isEmpty() ? o1.getOwner().getName() : o1.getStrippedName(); String secondName = o2.getStrippedName().isEmpty() ? o2.getOwner().getName() : o2.getStrippedName(); return firstName.compareTo(secondName); }; public final static Comparator WORTH_COMPARATOR = (o1, o2) -> { int compare = o2.getWorth().compareTo(o1.getWorth()); return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare; }; public final static Comparator LEVEL_COMPARATOR = (o1, o2) -> { int compare = o2.getIslandLevel().compareTo(o1.getIslandLevel()); return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare; }; public final static Comparator RATING_COMPARATOR = (o1, o2) -> { int totalRatingsCompare = Double.compare(o2.getTotalRating() * o2.getRatingAmount(), o1.getTotalRating() * o1.getRatingAmount()); if (totalRatingsCompare == 0) { int ratingsAmountCompare = Integer.compare(o2.getRatingAmount(), o1.getRatingAmount()); return ratingsAmountCompare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : ratingsAmountCompare; } return totalRatingsCompare; }; public final static Comparator PLAYERS_COMPARATOR = (o1, o2) -> { int compare = Integer.compare(o2.getAllPlayersInside().size(), o1.getAllPlayersInside().size()); return compare == 0 ? ISLAND_NAMES_COMPARATOR.compare(o1, o2) : compare; }; public final static Comparator ISLAND_ROLES_COMPARATOR = (o1, o2) -> { // Comparison is between o2 and o1 as the lower the weight is, the higher the player is. int compare = Integer.compare(o2.getPlayerRole().getWeight(), o1.getPlayerRole().getWeight()); return compare == 0 ? PLAYER_NAMES_COMPARATOR.compare(o1, o2) : compare; }; public static final Comparator ISLAND_METADATA_COMPARATOR = (Comparator) (o1, o2) -> o1.compareTo(o2); private SortingComparators() { } public static void initializeTopIslandMembersSorting() throws IllegalArgumentException { TopIslandMembersSorting.NAMES.setComparator(PLAYER_NAMES_COMPARATOR); TopIslandMembersSorting.ROLES.setComparator(ISLAND_ROLES_COMPARATOR); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java ================================================ package com.bgsoftware.superiorskyblock.island.top; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import java.util.Comparator; public class SortingTypes { public static final SortingType BY_WORTH = register("WORTH", SortingComparators.WORTH_COMPARATOR, false); public static final SortingType BY_LEVEL = register("LEVEL", SortingComparators.LEVEL_COMPARATOR, false); public static final SortingType BY_RATING = register("RATING", SortingComparators.RATING_COMPARATOR, false); public static final SortingType BY_PLAYERS = register("PLAYERS", SortingComparators.PLAYERS_COMPARATOR, false); private static volatile SortingType ISLAND_TOP_SORTING; private static volatile SortingType GLOBAL_WARPS_SORTING; private SortingTypes() { } public static void registerSortingTypes(SuperiorSkyblockPlugin plugin) { // We actually register the settings update listener in here, as otherwise it causes errors // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2752 registerListeners(plugin.getPluginEventsDispatcher()); } private static SortingType register(String name, Comparator comparator, boolean handleEqualsIslands) { SortingType.register(name, comparator, handleEqualsIslands); return SortingType.getByName(name); } public static SortingType getIslandTopSorting() { return ISLAND_TOP_SORTING; } public static SortingType getGlobalWarpsSorting() { return GLOBAL_WARPS_SORTING; } private static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SortingTypes::onSettingsUpdate); } private static void onSettingsUpdate() { String topOrder = SuperiorSkyblockPlugin.getPlugin().getSettings().getIslandTopOrder(); String warpsOrder = SuperiorSkyblockPlugin.getPlugin().getSettings().getGlobalWarpsOrder(); ISLAND_TOP_SORTING = resolveByName(topOrder); GLOBAL_WARPS_SORTING = resolveByName(warpsOrder); } private static SortingType resolveByName(String name) { return SortingType.getByName(name); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortMetadata.java ================================================ package com.bgsoftware.superiorskyblock.island.top.metadata; import com.bgsoftware.superiorskyblock.api.island.Island; import org.jetbrains.annotations.NotNull; public abstract class IslandSortMetadata> implements Comparable { private final Island island; protected final String islandName; protected IslandSortMetadata(Island island) { this.island = island; this.islandName = island.getStrippedName().isEmpty() ? island.getOwner().getName() : island.getStrippedName(); } public Island getIsland() { return island; } @Override public int compareTo(@NotNull T o) { return this.islandName.compareTo(o.islandName); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortPlayerMetadata.java ================================================ package com.bgsoftware.superiorskyblock.island.top.metadata; import com.bgsoftware.superiorskyblock.api.island.Island; public class IslandSortPlayerMetadata extends IslandSortMetadata { private final int allPlayersCount; public IslandSortPlayerMetadata(Island island) { super(island); this.allPlayersCount = island.getAllPlayersInside().size(); } @Override public int compareTo(IslandSortPlayerMetadata o) { int compare = Integer.compare(o.allPlayersCount, this.allPlayersCount); return compare == 0 ? super.compareTo(o) : compare; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortRatingMetadata.java ================================================ package com.bgsoftware.superiorskyblock.island.top.metadata; import com.bgsoftware.superiorskyblock.api.island.Island; public class IslandSortRatingMetadata extends IslandSortMetadata { private final int ratingAmount; private final double compareValue; public IslandSortRatingMetadata(Island island) { super(island); this.ratingAmount = island.getRatingAmount(); this.compareValue = island.getTotalRating() * ratingAmount; } @Override public int compareTo(IslandSortRatingMetadata o) { int compare = Double.compare(o.compareValue, this.compareValue); if (compare == 0) { compare = Integer.compare(o.ratingAmount, this.ratingAmount); if (compare == 0) compare = super.compareTo(o); } return compare; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortValueMetadata.java ================================================ package com.bgsoftware.superiorskyblock.island.top.metadata; import com.bgsoftware.superiorskyblock.api.island.Island; import java.math.BigDecimal; public class IslandSortValueMetadata extends IslandSortMetadata { private final BigDecimal value; public IslandSortValueMetadata(Island island, BigDecimal value) { super(island); this.value = value; } @Override public int compareTo(IslandSortValueMetadata o) { int compare = o.value.compareTo(this.value); return compare == 0 ? super.compareTo(o) : compare; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgrade.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade; public class DefaultUpgrade extends SUpgrade { private static final DefaultUpgrade INSTANCE = new DefaultUpgrade(); private DefaultUpgrade() { super("DEFAULT"); } public static DefaultUpgrade getInstance() { return INSTANCE; } @Override public SUpgradeLevel getUpgradeLevel(int level) { return DefaultUpgradeLevel.getInstance(); } @Override public int getMaxUpgradeLevel() { return 1; } @Override public void addUpgradeLevel(int level, SUpgradeLevel upgradeLevel) { // Not supported for the default upgrade. } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.upgrade.cost.EmptyUpgradeCost; import java.util.Collections; import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; public class DefaultUpgradeLevel extends SUpgradeLevel { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final DefaultUpgradeLevel INSTANCE = new DefaultUpgradeLevel(); private DefaultUpgradeLevel() { super(-1, EmptyUpgradeCost.getInstance(), Collections.emptyList(), "", Collections.emptySet(), Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getCropGrowth())), Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getSpawnerRates())), Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getMobDrops())), Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getTeamLimit())), Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getWarpsLimit())), Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getCoopLimit())), Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getIslandSize())), Value.syncedSupplied(() -> (KeyMap) plugin.getSettings().getDefaultValues().getBlockLimits()), Value.syncedSupplied(() -> (KeyMap) plugin.getSettings().getDefaultValues().getEntityLimits()), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRealGeneratorsMap()), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getIslandEffects()), Value.syncedSupplied(() -> Optional.of(plugin.getSettings().getDefaultValues().getBankLimit())), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRoleLimitsAsView()) ); } public static DefaultUpgradeLevel getInstance() { return INSTANCE; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/IslandUpgradeConstants.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade; import java.math.BigDecimal; public class IslandUpgradeConstants { public static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); public static final BigDecimal NO_BANK_LIMIT_VALUE = BigDecimal.valueOf(-1); public static final int SYNCED_VALUE = -2; public static final int NO_LIMIT_VALUE = -1; private IslandUpgradeConstants() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.EmptyInt2IntMapView; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.upgrade.cost.EmptyUpgradeCost; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.Set; public class SUpgrade implements Upgrade { private static final SUpgradeLevel NULL_LEVEL = new SUpgradeLevel(0, EmptyUpgradeCost.getInstance(), Collections.emptyList(), "", Collections.emptySet(), Value.syncedFixed(OptionalDouble.empty()), Value.syncedFixed(OptionalDouble.empty()), Value.syncedFixed(OptionalDouble.empty()), Value.syncedFixed(OptionalInt.empty()), Value.syncedFixed(OptionalInt.empty()), Value.syncedFixed(OptionalInt.empty()), Value.syncedFixed(OptionalInt.empty()), Value.syncedFixed(KeyMaps.createEmptyMap()), Value.syncedFixed(KeyMaps.createEmptyMap()), Value.syncedFixed(new EnumerateMap<>(Collections.emptyList())), Value.syncedFixed(Collections.emptyMap()), Value.syncedFixed(Optional.empty()), Value.syncedFixed(EmptyInt2IntMapView.INSTANCE)); private final String name; private SUpgradeLevel[] upgradeLevels = new SUpgradeLevel[0]; private final Set slots = new LinkedHashSet<>(); public SUpgrade(String name) { this.name = name; } @Override public String getName() { return name; } @Override public SUpgradeLevel getUpgradeLevel(int level) { return level <= 0 || level > upgradeLevels.length ? NULL_LEVEL : upgradeLevels[level - 1]; } @Override public int getMaxUpgradeLevel() { return upgradeLevels.length; } @Override public int getSlot() { return getSlots().get(0); } @Override public List getSlots() { return Collections.unmodifiableList(new LinkedList<>(this.slots)); } @Override public boolean isSlot(int slot) { return this.slots.contains(slot); } @Override public void setSlot(int slot) { this.slots.add(slot); } @Override public void setSlots(@Nullable List slots) { if (slots == null) { this.slots.clear(); } else { this.slots.addAll(slots); } } public void addUpgradeLevel(int level, SUpgradeLevel upgradeLevel) { if (level > upgradeLevels.length) upgradeLevels = Arrays.copyOf(upgradeLevels, level); upgradeLevels[level - 1] = upgradeLevel; } @Override public int hashCode() { return Objects.hash(name); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SUpgrade upgrade = (SUpgrade) o; return name.equals(upgrade.name); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.google.common.base.Preconditions; import org.bukkit.OfflinePlayer; import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffectType; import javax.script.ScriptException; import java.math.BigDecimal; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.Set; import java.util.stream.Collectors; public class SUpgradeLevel implements UpgradeLevel { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; private final int level; private final UpgradeCost cost; private final List commands; private final String permission; private final Set requirements; private final Value cropGrowth; private final Value spawnerRates; private final Value mobDrops; private final Value teamLimit; private final Value warpsLimit; private final Value coopLimit; private final Value borderSize; private final Value> blockLimits; private final Value> entityLimits; private final Value>> generatorRates; private final Value> islandEffects; private final Value> bankLimit; private final Value roleLimits; @Nullable private ItemData itemData; public SUpgradeLevel(int level, UpgradeCost cost, List commands, String permission, Set requirements, Value cropGrowth, Value spawnerRates, Value mobDrops, Value teamLimit, Value warpsLimit, Value coopLimit, Value borderSize, Value> blockLimits, Value> entityLimits, Value>> generatorRates, Value> islandEffects, Value> bankLimit, Value roleLimits) { this.level = level; this.cost = cost; this.commands = commands; this.permission = permission; this.requirements = requirements; this.cropGrowth = cropGrowth; this.spawnerRates = spawnerRates; this.mobDrops = mobDrops; this.teamLimit = teamLimit; this.warpsLimit = warpsLimit; this.coopLimit = coopLimit; this.borderSize = borderSize; this.blockLimits = blockLimits; this.entityLimits = entityLimits; this.generatorRates = generatorRates; this.islandEffects = islandEffects; this.bankLimit = bankLimit; this.roleLimits = roleLimits; } @Override public int getLevel() { return level; } @Override public double getPrice() { return cost.getCost().doubleValue(); } public UpgradeCost getCost() { return cost; } @Override public List getCommands() { return Collections.unmodifiableList(commands); } @Override public String getPermission() { return permission; } @Override public String checkRequirements(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer(); if (offlinePlayer != null) { for (UpgradeRequirement requirement : requirements) { String check = placeholdersService.get().parsePlaceholders(offlinePlayer, requirement.getPlaceholder()); try { if (!Boolean.parseBoolean(plugin.getScriptEngine().eval(check) + "")) return requirement.getErrorMessage(); } catch (ScriptException error) { Log.entering("ENTER", level, superiorPlayer.getName(), requirement.getPlaceholder()); Log.error(error, "An unexpected error occurred while checking for upgrade requirement:"); } } } return ""; } @Override public boolean hasCropGrowth() { return cropGrowth.get().isPresent(); } @Override public double getCropGrowth() { return cropGrowth.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public boolean hasSpawnerRates() { return spawnerRates.get().isPresent(); } @Override public double getSpawnerRates() { return spawnerRates.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public boolean hasMobDrops() { return mobDrops.get().isPresent(); } @Override public double getMobDrops() { return mobDrops.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public int getBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return blockLimits.get().getOrDefault(key, IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public int getExactBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return blockLimits.get().getRaw(key, IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public Map getBlockLimits() { return Collections.unmodifiableMap(blockLimits.get()); } @Override public int getEntityLimit(EntityType entityType) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null."); return getEntityLimit(Keys.of(entityType)); } @Override public int getEntityLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); return entityLimits.get().getOrDefault(key, IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public Map getEntityLimitsAsKeys() { return Collections.unmodifiableMap(entityLimits.get()); } @Override public boolean hasTeamLimit() { return teamLimit.get().isPresent(); } @Override public int getTeamLimit() { return teamLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public boolean hasWarpsLimit() { return warpsLimit.get().isPresent(); } @Override public int getWarpsLimit() { return warpsLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public boolean hasCoopLimit() { return coopLimit.get().isPresent(); } @Override public int getCoopLimit() { return coopLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public boolean hasBorderSize() { return borderSize.get().isPresent(); } @Override public int getBorderSize() { return borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public int getGeneratorAmount(Key key, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Map generatorRates = this.generatorRates.get().get(dimension); return (generatorRates == null ? 0 : generatorRates.getOrDefault(key, 0)); } @Override public Map getGeneratorAmounts(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Map generatorRates = this.generatorRates.get().get(dimension); return generatorRates == null ? Collections.emptyMap() : generatorRates.entrySet().stream().collect(Collectors.toMap( entry -> entry.getKey().toString(), Map.Entry::getValue)); } @Override public int getPotionEffect(PotionEffectType potionEffectType) { Preconditions.checkNotNull(potionEffectType, "potionEffectType parameter cannot be null."); return islandEffects.get().getOrDefault(potionEffectType, 0); } @Override public Map getPotionEffects() { return Collections.unmodifiableMap(islandEffects.get()); } @Override public boolean hasBankLimit() { return bankLimit.get().isPresent(); } @Override public BigDecimal getBankLimit() { return bankLimit.get().orElse(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE); } @Override public int getRoleLimit(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); return roleLimits.get().getOrDefault(playerRole.getId(), IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public Map getRoleLimits() { Int2IntMapView roleLimits = this.roleLimits.get(); if (roleLimits.isEmpty()) return Collections.emptyMap(); Map roleLimitsConverted = new LinkedHashMap<>(); Iterator iterator = roleLimits.entryIterator(); while (iterator.hasNext()) { Int2IntMapView.Entry entry = iterator.next(); PlayerRole playerRole = SPlayerRole.fromId(entry.getKey()); if (playerRole != null) roleLimitsConverted.put(playerRole, entry.getValue()); } return roleLimitsConverted.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(roleLimitsConverted); } public DoubleValue getCropGrowthUpgradeValue() { return DoubleValue.syncedSupplied(() -> cropGrowth.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public DoubleValue getSpawnerRatesUpgradeValue() { return DoubleValue.syncedSupplied(() -> spawnerRates.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public DoubleValue getMobDropsUpgradeValue() { return DoubleValue.syncedSupplied(() -> mobDrops.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public Map getBlockLimitsUpgradeValue() { return blockLimits.get().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> IntValue.syncedFixed(entry.getValue())) ); } public Map getEntityLimitsUpgradeValue() { return entityLimits.get().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> IntValue.syncedFixed(entry.getValue())) ); } public IntValue getTeamLimitUpgradeValue() { return IntValue.syncedSupplied(() -> teamLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public IntValue getWarpsLimitUpgradeValue() { return IntValue.syncedSupplied(() -> warpsLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public IntValue getCoopLimitUpgradeValue() { return IntValue.syncedSupplied(() -> coopLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public IntValue getBorderSizeUpgradeValue() { return IntValue.syncedSupplied(() -> borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public EnumerateMap> getGeneratorUpgradeValue() { EnumerateMap> generatorRates = this.generatorRates.get(); EnumerateMap> generatorRatesConverted = new EnumerateMap<>(Dimension.values()); for (Dimension dimension : Dimension.values()) { Map worldGeneratorRates = generatorRates.get(dimension); if (worldGeneratorRates != null) { Map result = worldGeneratorRates.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> IntValue.syncedFixed(entry.getValue()))); generatorRatesConverted.put(dimension, result); } } return generatorRatesConverted; } public Map getPotionEffectsUpgradeValue() { return islandEffects.get().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> IntValue.syncedFixed(entry.getValue())) ); } public Value getBankLimitUpgradeValue() { return Value.syncedSupplied(() -> bankLimit.get().orElseGet(() -> IslandUpgradeConstants.NO_BANK_LIMIT_VALUE)); } public Map getRoleLimitsUpgradeValue() { Int2IntMapView roleLimits = this.roleLimits.get(); if (roleLimits.isEmpty()) return Collections.emptyMap(); Map roleLimitsConverted = new LinkedHashMap<>(); Iterator iterator = roleLimits.entryIterator(); while (iterator.hasNext()) { Int2IntMapView.Entry entry = iterator.next(); PlayerRole playerRole = SPlayerRole.fromId(entry.getKey()); if (playerRole != null) roleLimitsConverted.put(playerRole, IntValue.syncedFixed(entry.getValue())); } return roleLimitsConverted.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(roleLimitsConverted); } public void setItemData(TemplateItem hasNextLevel, TemplateItem noNextLevel, GameSound hasNextLevelSound, GameSound noNextLevelSound, List hasNextLevelCommands, List noNextLevelCommands) { this.itemData = new ItemData(hasNextLevel, noNextLevel, hasNextLevelSound, noNextLevelSound, hasNextLevelCommands, noNextLevelCommands); } @Nullable public ItemData getItemData() { return itemData; } public static class ItemData { public TemplateItem hasNextLevel; public TemplateItem noNextLevel; public GameSound hasNextLevelSound; public GameSound noNextLevelSound; public List hasNextLevelCommands; public List noNextLevelCommands; public ItemData(TemplateItem hasNextLevel, TemplateItem noNextLevel, GameSound hasNextLevelSound, GameSound noNextLevelSound, List hasNextLevelCommands, List noNextLevelCommands) { this.hasNextLevel = hasNextLevel; this.noNextLevel = noNextLevel; this.hasNextLevelSound = hasNextLevelSound; this.noNextLevelSound = noNextLevelSound; this.hasNextLevelCommands = hasNextLevelCommands; this.noNextLevelCommands = noNextLevelCommands; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradeRequirement.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade; public class UpgradeRequirement { private final String placeholder; private final String errorMessage; public UpgradeRequirement(String placeholder, String errorMessage) { this.placeholder = placeholder; this.errorMessage = errorMessage; } public String getPlaceholder() { return placeholder; } public String getErrorMessage() { return errorMessage; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.UpgradesManager; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.island.upgrade.container.UpgradesContainer; import com.google.common.base.Preconditions; import java.util.Collection; import java.util.Locale; public class UpgradesManagerImpl extends Manager implements UpgradesManager { private final UpgradesContainer upgradesContainer; private String ALL_UPGRADE_NAMES; public UpgradesManagerImpl(SuperiorSkyblockPlugin plugin, UpgradesContainer upgradesContainer) { super(plugin); this.upgradesContainer = upgradesContainer; } @Override public void loadData() { // Data is loaded later. } @Override public Upgrade getUpgrade(String upgradeName) { Preconditions.checkNotNull(upgradeName, "upgradeName parameter cannot be null."); return this.upgradesContainer.getUpgrade(upgradeName); } @Override public Upgrade getUpgrade(int slot) { return this.upgradesContainer.getUpgrade(slot); } @Override public void addUpgrade(Upgrade upgrade) { this.upgradesContainer.addUpgrade(upgrade); ALL_UPGRADE_NAMES = null; } @Override public Upgrade getDefaultUpgrade() { return DefaultUpgrade.getInstance(); } @Override public boolean isUpgrade(String upgradeName) { Preconditions.checkNotNull(upgradeName, "upgradeName parameter cannot be null."); return getUpgrade(upgradeName) != null; } @Override public Collection getUpgrades() { return this.upgradesContainer.getUpgrades(); } @Override public void registerUpgradeCostLoader(String id, UpgradeCostLoader costLoader) { Preconditions.checkNotNull(id, "id parameter cannot be null."); Preconditions.checkNotNull(costLoader, "costLoader parameter cannot be null."); this.upgradesContainer.registerUpgradeCostLoader(id, costLoader); } @Override public Collection getUpgradesCostLoaders() { return this.upgradesContainer.getUpgradesCostLoaders(); } @Nullable @Override public UpgradeCostLoader getUpgradeCostLoader(String id) { Preconditions.checkNotNull(id, "id parameter cannot be null."); return this.upgradesContainer.getUpgradeCostLoader(id); } public void clearUpgrades() { this.upgradesContainer.clearUpgrades(); } public String getUpgradesNames() { if (ALL_UPGRADE_NAMES == null) { ALL_UPGRADE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getUpgrades().getUpgrades().stream() .map(upgrade -> upgrade.getName().toLowerCase(Locale.ENGLISH))); } return ALL_UPGRADE_NAMES; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/DefaultUpgradesContainer.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class DefaultUpgradesContainer implements UpgradesContainer { private final Map upgrades = new HashMap<>(); private final Map upgradeCostLoaders = new HashMap<>(); @Nullable @Override public Upgrade getUpgrade(String upgradeName) { return this.upgrades.get(upgradeName.toLowerCase(Locale.ENGLISH)); } @Nullable @Override public Upgrade getUpgrade(int slot) { return this.upgrades.values().stream() .filter(upgrade -> upgrade.isSlot(slot)) .findFirst() .orElse(null); } @Override public Collection getUpgrades() { return new SequentialListBuilder().build(this.upgrades.values()); } @Override public void registerUpgradeCostLoader(String id, UpgradeCostLoader costLoader) { this.upgradeCostLoaders.put(id.toLowerCase(Locale.ENGLISH), costLoader); } @Override public Collection getUpgradesCostLoaders() { return new SequentialListBuilder().build(this.upgradeCostLoaders.values()); } @Override public UpgradeCostLoader getUpgradeCostLoader(String id) { return this.upgradeCostLoaders.get(id.toLowerCase(Locale.ENGLISH)); } @Override public void addUpgrade(Upgrade upgrade) { this.upgrades.put(upgrade.getName().toLowerCase(Locale.ENGLISH), upgrade); } @Override public void clearUpgrades() { this.upgrades.clear(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/IslandUpgrades.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.container; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.google.common.collect.Sets; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; public class IslandUpgrades { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Set ALL_UPGRADE_CONTAINERS = Sets.newSetFromMap(new WeakHashMap<>()); static { } private final Map enabledUpgrades = new ConcurrentHashMap<>(); private final Map upgrades = new ConcurrentHashMap<>(); public IslandUpgrades() { ALL_UPGRADE_CONTAINERS.add(this); } public void setUpgradeLevel(Upgrade upgrade, int level) { setUpgradeLevelInternal(upgrade.getName(), Math.min(upgrade.getMaxUpgradeLevel(), level)); } public void setUpgradeLevels(Map upgrades) { upgrades.forEach(this::setUpgradeLevelInternal); } public UpgradeLevel getUpgradeLevel(Upgrade upgrade) { return upgrade.getUpgradeLevel(this.enabledUpgrades.getOrDefault(upgrade.getName(), 1)); } public Map getUpgrades() { return Collections.unmodifiableMap(this.enabledUpgrades); } private void setUpgradeLevelInternal(String upgradeName, int level) { this.enabledUpgrades.put(upgradeName, level); this.upgrades.put(upgradeName, level); } public static void onUpgradesUpdate() { for (IslandUpgrades islandUpgrades : ALL_UPGRADE_CONTAINERS) { islandUpgrades.enabledUpgrades.clear(); islandUpgrades.upgrades.forEach((upgradeName, level) -> { Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName); if (upgrade != null) islandUpgrades.setUpgradeLevel(upgrade, level); }); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/UpgradesContainer.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; import java.util.Collection; public interface UpgradesContainer { @Nullable Upgrade getUpgrade(String upgradeName); @Nullable Upgrade getUpgrade(int slot); Collection getUpgrades(); void registerUpgradeCostLoader(String id, UpgradeCostLoader costLoader); Collection getUpgradesCostLoaders(); UpgradeCostLoader getUpgradeCostLoader(String id); void addUpgrade(Upgrade upgrade); void clearUpgrades(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/cost/EmptyUpgradeCost.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.cost; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.math.BigDecimal; public class EmptyUpgradeCost extends UpgradeCostAbstract { private static final EmptyUpgradeCost INSTANCE = new EmptyUpgradeCost(); private EmptyUpgradeCost() { super(BigDecimal.ZERO, "Null"); } public static EmptyUpgradeCost getInstance() { return INSTANCE; } @Override public boolean hasEnoughBalance(SuperiorPlayer superiorPlayer) { return false; } @Override public void withdrawCost(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public UpgradeCost clone(BigDecimal cost) { return this; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/cost/PlaceholdersUpgradeCost.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.cost; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import org.bukkit.Bukkit; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class PlaceholdersUpgradeCost extends UpgradeCostAbstract { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; private final String placeholder; private final List withdrawCommands; public PlaceholdersUpgradeCost(BigDecimal cost, String placeholder, List withdrawCommands) { super(cost, "placeholders"); this.placeholder = placeholder; this.withdrawCommands = Collections.unmodifiableList(withdrawCommands); } @Override public boolean hasEnoughBalance(SuperiorPlayer superiorPlayer) { BigDecimal currentBalance = BigDecimal.ZERO; try { currentBalance = new BigDecimal(placeholdersService.get().parsePlaceholders(superiorPlayer.asOfflinePlayer(), placeholder)); } catch (Exception ignored) { } return currentBalance.compareTo(cost) >= 0; } @Override public void withdrawCost(SuperiorPlayer superiorPlayer) { String cost = super.cost.toPlainString(); String playerName = superiorPlayer.getName(); withdrawCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("%amount%", cost).replace("%player%", playerName))); } @Override public UpgradeCost clone(BigDecimal cost) { return new PlaceholdersUpgradeCost(cost, placeholder, withdrawCommands); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/cost/UpgradeCostAbstract.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.cost; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import java.math.BigDecimal; public abstract class UpgradeCostAbstract implements UpgradeCost { protected final BigDecimal cost; protected final String id; protected UpgradeCostAbstract(BigDecimal cost, String id) { this.cost = cost; this.id = id; } @Override public String getId() { return id; } @Override public BigDecimal getCost() { return cost; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/cost/VaultUpgradeCost.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.cost; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import java.math.BigDecimal; public class VaultUpgradeCost extends UpgradeCostAbstract { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public VaultUpgradeCost(BigDecimal value) { super(value, "money"); } @Override public boolean hasEnoughBalance(SuperiorPlayer superiorPlayer) { return plugin.getProviders().getEconomyProvider().getBalance(superiorPlayer).compareTo(cost) >= 0; } @Override public void withdrawCost(SuperiorPlayer superiorPlayer) { plugin.getProviders().withdrawMoney(superiorPlayer, cost); } @Override public UpgradeCost clone(BigDecimal cost) { return new VaultUpgradeCost(cost); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/loaders/PlaceholdersUpgradeCostLoader.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.loaders; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoadException; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; import com.bgsoftware.superiorskyblock.island.upgrade.cost.PlaceholdersUpgradeCost; import org.bukkit.configuration.ConfigurationSection; import java.math.BigDecimal; public class PlaceholdersUpgradeCostLoader implements UpgradeCostLoader { @Override public UpgradeCost loadCost(ConfigurationSection upgradeSection) throws UpgradeCostLoadException { if (!upgradeSection.contains("price")) throw new UpgradeCostLoadException("The field 'price' is missing from the section."); if (!upgradeSection.contains("placeholder")) throw new UpgradeCostLoadException("The field 'placeholder' is missing from the section."); if (!upgradeSection.contains("withdraw-commands")) throw new UpgradeCostLoadException("The field 'withdraw-commands' is missing from the section."); return new PlaceholdersUpgradeCost( BigDecimal.valueOf(upgradeSection.getDouble("price")), upgradeSection.getString("placeholder"), upgradeSection.getStringList("withdraw-commands") ); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/loaders/VaultUpgradeCostLoader.java ================================================ package com.bgsoftware.superiorskyblock.island.upgrade.loaders; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoadException; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; import com.bgsoftware.superiorskyblock.island.upgrade.cost.VaultUpgradeCost; import org.bukkit.configuration.ConfigurationSection; import java.math.BigDecimal; public class VaultUpgradeCostLoader implements UpgradeCostLoader { @Override public UpgradeCost loadCost(ConfigurationSection upgradeSection) throws UpgradeCostLoadException { if (!upgradeSection.contains("price")) throw new UpgradeCostLoadException("The field 'price' is missing from the section."); return new VaultUpgradeCost(BigDecimal.valueOf(upgradeSection.getDouble("price"))); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java ================================================ package com.bgsoftware.superiorskyblock.island.warp; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.inventory.ItemStack; import java.util.Objects; public class SIslandWarp implements IslandWarp { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final WarpCategory warpCategory; private String name; private WorldPosition worldPosition; private WorldInfo worldInfo; private boolean isPrivate; private ItemStack icon; public SIslandWarp(String name, WorldInfo worldInfo, WorldPosition worldPosition, WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) { this.name = name; this.worldPosition = worldPosition; this.worldInfo = worldInfo; this.warpCategory = warpCategory; this.isPrivate = isPrivate; this.icon = icon; } @Override public Island getIsland() { return warpCategory.getIsland(); } @Override public String getName() { return name; } @Override public void setName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Log.debug(Debug.SET_WARP_NAME, getOwnerName(), this.name, name); String oldName = this.name; this.name = name; IslandsDatabaseBridge.updateWarpName(getIsland(), this, oldName); } @Override public Location getLocation() { return IslandWorlds.setWorldToLocation(this.worldInfo, this.worldPosition); } @Override public Location getLocation(Location location) { if (location != null) { if (location instanceof LazyWorldLocation) { ((LazyWorldLocation) location).setWorldName(this.worldInfo.getName()); } else { IslandWorlds.ensureWorldLoaded(this.worldInfo); World world = Bukkit.getWorld(this.worldInfo.getName()); location.setWorld(world); } location.setX(this.worldPosition.getX()); location.setY(this.worldPosition.getY()); location.setZ(this.worldPosition.getZ()); location.setYaw(this.worldPosition.getYaw()); location.setPitch(this.worldPosition.getPitch()); } return location; } @Override public void setLocation(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); Log.debug(Debug.SET_WARP_LOCATION, getOwnerName(), this.name, location); this.worldInfo = plugin.getGrid().getIslandsWorldInfo(getIsland(), LazyWorldLocation.getWorldName(location)); this.worldPosition = SWorldPosition.of(location); IslandsDatabaseBridge.updateWarpLocation(getIsland(), this); } @Override public WorldPosition getPosition() { return this.worldPosition; } @Override public Dimension getPositionDimension() { return this.worldInfo.getDimension(); } @Override public void setPosition(Dimension dimension, WorldPosition worldPosition) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); Log.debug(Debug.SET_WARP_LOCATION, getOwnerName(), this.name, dimension, worldPosition); this.worldInfo = plugin.getGrid().getIslandsWorldInfo(getIsland(), dimension); this.worldPosition = worldPosition; IslandsDatabaseBridge.updateWarpLocation(getIsland(), this); } @Override public boolean hasPrivateFlag() { return isPrivate; } @Override public void setPrivateFlag(boolean privateFlag) { Log.debug(Debug.SET_WARP_PRIVATE, getOwnerName(), this.name, privateFlag); this.isPrivate = privateFlag; IslandsDatabaseBridge.updateWarpPrivateStatus(getIsland(), this); } @Override public ItemStack getRawIcon() { return icon == null ? null : icon.clone(); } @Override public ItemStack getIcon(SuperiorPlayer superiorPlayer) { if (icon == null) return null; try { ItemBuilder itemBuilder = new ItemBuilder(icon) .replaceAll("{0}", name); return superiorPlayer == null ? itemBuilder.build() : itemBuilder.build(superiorPlayer); } catch (Exception error) { setIcon(null); return null; } } @Override public void setIcon(ItemStack icon) { Log.debug(Debug.SET_WARP_ICON, getOwnerName(), this.name, icon); this.icon = icon == null ? null : icon.clone(); IslandsDatabaseBridge.updateWarpIcon(getIsland(), this); } @Override public WarpCategory getCategory() { return warpCategory; } @Override public int hashCode() { return Objects.hash(name); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SIslandWarp that = (SIslandWarp) o; return name.equals(that.name); } private String getOwnerName() { SuperiorPlayer superiorPlayer = getIsland().getOwner(); return superiorPlayer == null ? "None" : superiorPlayer.getName(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/warp/SWarpCategory.java ================================================ package com.bgsoftware.superiorskyblock.island.warp; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import org.bukkit.inventory.ItemStack; import java.util.LinkedList; import java.util.List; import java.util.UUID; public class SWarpCategory implements WarpCategory { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final List islandWarps = new LinkedList<>(); private final UUID islandUUID; private Island cachedIsland; private String name; private int slot; private ItemStack icon; public SWarpCategory(UUID islandUUID, String name, int slot, @Nullable ItemStack icon) { this.islandUUID = islandUUID; this.name = name; this.slot = slot; this.icon = icon == null ? WarpIcons.DEFAULT_WARP_CATEGORY_ICON.build() : icon; } @Override public Island getIsland() { return cachedIsland == null ? (cachedIsland = plugin.getGrid().getIslandByUUID(islandUUID)) : cachedIsland; } @Override public String getName() { return name; } @Override public void setName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); Log.debug(Debug.SET_WARP_CATEGORY_NAME, getOwnerName(), this.name, name); String oldName = this.name; this.name = name; for (IslandWarp islandWarp : islandWarps) IslandsDatabaseBridge.updateWarpCategory(getIsland(), islandWarp, oldName); IslandsDatabaseBridge.updateWarpCategoryName(getIsland(), this, oldName); } @Override public List getWarps() { return islandWarps; } @Override public int getSlot() { return slot; } @Override public void setSlot(int slot) { Log.debug(Debug.SET_WARP_CATEGORY_SLOT, getOwnerName(), this.name, slot); this.slot = slot; IslandsDatabaseBridge.updateWarpCategorySlot(getIsland(), this); } @Override public ItemStack getRawIcon() { return icon.clone(); } @Override public ItemStack getIcon(@Nullable SuperiorPlayer superiorPlayer) { ItemBuilder itemBuilder = new ItemBuilder(icon) .replaceAll("{0}", name); return superiorPlayer == null ? itemBuilder.build() : itemBuilder.build(superiorPlayer); } @Override public void setIcon(@Nullable ItemStack icon) { Log.debug(Debug.SET_WARP_CATEGORY_ICON, getOwnerName(), this.name, icon); this.icon = icon == null ? WarpIcons.DEFAULT_WARP_CATEGORY_ICON.build() : icon.clone(); IslandsDatabaseBridge.updateWarpCategoryIcon(getIsland(), this); } private String getOwnerName() { SuperiorPlayer superiorPlayer = getIsland().getOwner(); return superiorPlayer == null ? "None" : superiorPlayer.getName(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java ================================================ package com.bgsoftware.superiorskyblock.island.warp; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.List; public class SignWarp { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private SignWarp() { } public static void trySignWarpBreak(IslandWarp islandWarp, CommandSender commandSender) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { Location warpLocation = islandWarp.getLocation(wrapper.getHandle()); if (warpLocation.getWorld() == null) { IslandWorlds.accessIslandWorldAsync(islandWarp.getIsland(), warpLocation, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(unused -> { trySignWarpBreakWorldLoaded(islandWarp, commandSender); }); }); return; } } trySignWarpBreakWorldLoaded(islandWarp, commandSender); } private static void trySignWarpBreakWorldLoaded(IslandWarp islandWarp, CommandSender commandSender) { ChunksProvider.loadChunk(ChunkPosition.of(islandWarp), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { trySignWarpBreakChunkLoaded(islandWarp, commandSender); }); } private static void trySignWarpBreakChunkLoaded(IslandWarp islandWarp, CommandSender commandSender) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location warpLocation = islandWarp.getLocation(wrapper.getHandle()); Block signBlock = warpLocation.getBlock(); BlockState blockState = signBlock.getState(); // We check for a sign block at the warp's location. if (!(blockState instanceof Sign)) return; Sign sign = (Sign) blockState; List configSignWarp = new ArrayList<>(plugin.getSettings().getSignWarp()); configSignWarp.replaceAll(line -> line.replace("{0}", islandWarp.getName())); String[] signLines = sign.getLines(); for (int i = 0; i < signLines.length && i < configSignWarp.size(); ++i) { if (!signLines[i].equals(configSignWarp.get(i))) return; } // Detected warp sign signBlock.setType(Material.AIR); signBlock.getWorld().dropItemNaturally(warpLocation, new ItemStack(blockState.getType())); Message.DELETE_WARP_SIGN_BROKE.send(commandSender); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/island/warp/WarpIcons.java ================================================ package com.bgsoftware.superiorskyblock.island.warp; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import org.bukkit.Material; public class WarpIcons { public static final TemplateItem DEFAULT_WARP_CATEGORY_ICON = new TemplateItem(new ItemBuilder(Material.BOOK) .withName("&6{0}")); public static TemplateItem DEFAULT_WARP_ICON; private WarpIcons() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/AbstractGameEventListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEventCallback; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; public abstract class AbstractGameEventListener { protected final SuperiorSkyblockPlugin plugin; protected AbstractGameEventListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } protected void registerCallback(GameEventType type, GameEventPriority priority, GameEventCallback callback) { registerCallback(type, priority, true, callback); } protected void registerCallback(GameEventType type, GameEventPriority priority, boolean ignoreCancelled, GameEventCallback callback) { plugin.getGameEventsDispatcher().registerCallback(this, type, priority, ignoreCancelled, callback); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/AdminPlayersListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import java.util.UUID; public class AdminPlayersListener extends AbstractGameEventListener { private static final UUID DEVELOPER_UUID = UUID.fromString("45713654-41bf-45a1-aa6f-00fe6598703b"); private final String buildName; public AdminPlayersListener(SuperiorSkyblockPlugin plugin) { super(plugin); String fileName = plugin.getFileName().split("\\.")[0]; String buildName = fileName.contains("-") ? fileName.substring(fileName.indexOf('-') + 1) : ""; this.buildName = buildName.isEmpty() ? "" : " (Build: " + buildName + ")"; registerCallback(GameEventType.PLAYER_JOIN_EVENT, GameEventPriority.MONITOR, this::onPlayerJoin); } private void onPlayerJoin(GameEvent e) { Player player = e.getArgs().player; // Notifies me when a server uses one of my plugins. if (player.getUniqueId().equals(DEVELOPER_UUID)) { Bukkit.getScheduler().runTaskLater(plugin, () -> Message.CUSTOM.send(player, "&8[&fSuperiorSeries&8] &7This server is using SuperiorSkyblock2 v" + plugin.getDescription().getVersion() + buildName, true), 5L); } // Notifies operators about new updates if (player.isOp() && plugin.getUpdater().isOutdated()) { Bukkit.getScheduler().runTaskLater(plugin, () -> player.sendMessage(ChatColor.BLUE + "" + ChatColor.BOLD + "SuperiorSkyblock2" + ChatColor.GRAY + " A new version is available (v" + plugin.getUpdater().getLatestVersion() + ")!"), 20L); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Item; import org.bukkit.entity.Minecart; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.event.block.Action; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.ItemStack; import java.util.Collection; import java.util.Map; import java.util.concurrent.TimeUnit; public class BlockChangesListener extends AbstractGameEventListener { private static final Map BUCKET_TO_KEY_CACHE = new ArrayMap<>(); @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable private static final Material CLOSED_EYEBLOSSOM = EnumHelper.getEnum(Material.class, "CLOSED_EYEBLOSSOM"); @Nullable private static final Material OPEN_EYEBLOSSOM = EnumHelper.getEnum(Material.class, "OPEN_EYEBLOSSOM"); @Nullable private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BUILD_COPPERGOLEM"); @WorldRecordFlags private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; static { for (Material material : Material.values()) { if (material.name().contains("_BUCKET")) { BUCKET_TO_KEY_CACHE.put(material, getBlockKeyFromBucketMaterial(material)); } } } private final Collection alreadySpongeAbosrbCalled = AutoRemovalCollection.newArrayList(5L * 50, TimeUnit.MILLISECONDS); private final Collection alreadyChorusFlowerTracked = AutoRemovalCollection.newArrayList(1L * 50, TimeUnit.MILLISECONDS); private final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; public BlockChangesListener(SuperiorSkyblockPlugin plugin) { super(plugin); this.registerListeners(); } /* BLOCK PLACES */ private void onBlockPlace(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; BlockState replacedState = e.getArgs().replacedState; boolean shouldAvoidReplacedState = replacedState.equals(block.getState()); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(Keys.of(block), block.getLocation(wrapper.getHandle()), plugin.getNMSWorld().getDefaultAmount(block), shouldAvoidReplacedState ? null : replacedState, REGULAR_RECORD_FLAGS); } } private void onBucketEmpty(GameEvent e) { Material bucket = e.getArgs().bucket; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().clickedBlock.getWorld())) return; Key blockKey = BUCKET_TO_KEY_CACHE.computeIfAbsent(bucket, BlockChangesListener::getBlockKeyFromBucketMaterial); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Block clickedBlock = e.getArgs().clickedBlock; this.worldRecordService.get().recordBlockPlace(blockKey, clickedBlock.getLocation(wrapper.getHandle()), 1, null, REGULAR_RECORD_FLAGS); } } private void onStructureGrow(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().location.getWorld())) return; KeyMap placedBlockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); KeyMap brokenBlockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); e.getArgs().blocks.forEach(blockState -> { Key placedBlockKey = Keys.of(blockState); Key brokenBlockKey = Keys.of(blockState.getBlock()); if (!placedBlockKey.equals(brokenBlockKey)) { if (!placedBlockKey.equals(ConstantKeys.AIR)) placedBlockCounts.put(placedBlockKey, placedBlockCounts.getOrDefault(placedBlockKey, 0) + 1); if (!brokenBlockKey.equals(ConstantKeys.AIR)) brokenBlockCounts.put(brokenBlockKey, brokenBlockCounts.getOrDefault(brokenBlockKey, 0) + 1); } }); Location growLocation = e.getArgs().location; this.worldRecordService.get().recordMultiBlocksPlace(placedBlockCounts, growLocation, WorldRecordFlags.DIRTY_CHUNKS); this.worldRecordService.get().recordMultiBlocksBreak(brokenBlockCounts, growLocation, WorldRecordFlags.DIRTY_CHUNKS); } private void onBlockGrow(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; BlockState newState = e.getArgs().newState; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(Keys.of(newState), block.getLocation(wrapper.getHandle()), 1, block.getState(), REGULAR_RECORD_FLAGS); } } private void onBlockForm(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; BlockState newState = e.getArgs().newState; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = block.getLocation(wrapper.getHandle()); this.worldRecordService.get().recordBlockPlace(Keys.of(newState), location, 1, block.getState(), REGULAR_RECORD_FLAGS); } } private void onBlockSpread(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Block source = e.getArgs().source; BlockState newState = e.getArgs().newState; Material newStateType = newState.getType(); Material sourceType = source.getType(); Key spreadBlock = null; if (newStateType == CHORUS_FLOWER && sourceType == CHORUS_FLOWER) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location spreadBlockLocation = source.getLocation(wrapper.getHandle()); // When a chorus flower grows, it is replaced with a flower plant and multiple new flowers can grow. // Therefore, we want to track a plant one time instead of a new flower. if (!alreadyChorusFlowerTracked.contains(spreadBlockLocation)) { spreadBlock = ConstantKeys.CHORUS_PLANT; alreadyChorusFlowerTracked.add(spreadBlockLocation.clone()); } } } if (spreadBlock == null) { spreadBlock = Keys.of(newState); } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(spreadBlock, block.getLocation(wrapper.getHandle()), 1, block.getState(), REGULAR_RECORD_FLAGS); } } private void onBlockShapeUpdate(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Key newStateKey = Keys.of(block); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); if (newStateKey.equals(ConstantKeys.AIR)) { // New state is AIR, so this is a block break Key oldStateKey = Keys.of(e.getArgs().oldState); this.worldRecordService.get().recordBlockBreak(oldStateKey, blockLocation, 1, REGULAR_RECORD_FLAGS); } else { this.worldRecordService.get().recordBlockPlace(newStateKey, block.getLocation(wrapper.getHandle()), 1, e.getArgs().oldState, REGULAR_RECORD_FLAGS); } } } private void onMinecartPlace(GameEvent e) { Entity vehicle = e.getArgs().entity; if (!(vehicle instanceof Minecart)) return; Key minecartBlockKey = getMinecartBlockKey(vehicle.getType()); if (minecartBlockKey != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(minecartBlockKey, vehicle.getLocation(wrapper.getHandle()), 1, null, REGULAR_RECORD_FLAGS); } } } private void onSpawnerChange(GameEvent e) { Action action = e.getArgs().action; Block clickedBlock = e.getArgs().clickedBlock; if (action != Action.RIGHT_CLICK_BLOCK || clickedBlock.getType() != Materials.SPAWNER.toBukkitType()) return; ItemStack handItem = e.getArgs().usedItem; if (handItem == null) return; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld())) return; Material handItemType = handItem.getType(); if (!Materials.isSpawnEgg(handItemType)) return; Chunk chunk = clickedBlock.getChunk(); BlockState oldBlockState = clickedBlock.getState(); Key oldSpawnerKey = Keys.of(oldBlockState); BukkitExecutor.sync(() -> { if (!chunk.isLoaded()) return; Key newSpawnerKey = Keys.of(clickedBlock); if (!oldSpawnerKey.equals(newSpawnerKey)) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = clickedBlock.getLocation(wrapper.getHandle()); int spawnerCount = plugin.getProviders().getSpawnersProvider().getSpawner(location).getKey(); this.worldRecordService.get().recordBlockBreak(oldSpawnerKey, location, spawnerCount, REGULAR_RECORD_FLAGS); this.worldRecordService.get().recordBlockPlace(newSpawnerKey, location, spawnerCount, null, REGULAR_RECORD_FLAGS); } } }, 1L); } private void onEntityChangeBlock(GameEvent e) { if (e.getArgs().entity instanceof Player) return; Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Key newBlockKey = e.getArgs().newType; Key oldBlockKey = Keys.of(block); if (newBlockKey.equals(oldBlockKey)) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); if (!oldBlockKey.equals(ConstantKeys.AIR)) { this.worldRecordService.get().recordBlockBreak(oldBlockKey, blockLocation, plugin.getNMSWorld().getDefaultAmount(block), REGULAR_RECORD_FLAGS); } if (!newBlockKey.equals(ConstantKeys.AIR)) { this.worldRecordService.get().recordBlockPlace(newBlockKey, blockLocation, 1, null, REGULAR_RECORD_FLAGS); } } } /* BLOCK BREAKS */ private void onBlockBreak(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; this.worldRecordService.get().recordBlockBreak(block, REGULAR_RECORD_FLAGS); } private void onBucketFill(GameEvent e) { Block clickedBlock = e.getArgs().clickedBlock; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld())) return; boolean isWaterLogged = plugin.getNMSWorld().isWaterLogged(clickedBlock); if (isWaterLogged || clickedBlock.isLiquid()) { Key blockKey = isWaterLogged ? ConstantKeys.WATER : Keys.of(clickedBlock); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockBreak(blockKey, clickedBlock.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS); } } } private void onEntitySpawn(GameEvent e) { Entity entity = e.getArgs().entity; if (entity.isDead()) return; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; onMinecartPlace(e); onDragonEggDrop(e); onGolemStructure(e); } private void onDragonEggDrop(GameEvent e) { Entity entity = e.getArgs().entity; if (!(entity instanceof Item)) return; Item item = (Item) entity; if (item.getItemStack().getType() != Material.DRAGON_EGG) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { for (Entity nearby : item.getNearbyEntities(2, 2, 2)) { if (nearby instanceof FallingBlock) { Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) nearby); this.worldRecordService.get().recordBlockBreak(blockKey, nearby.getLocation(wrapper.getHandle()), 1, WorldRecordFlags.SAVE_BLOCK_COUNT); return; } } } } private void onGolemStructure(GameEvent e) { CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = e.getArgs().entity.getLocation(wrapper.getHandle()); if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM) { this.worldRecordService.get().recordBlockBreak(ConstantKeys.IRON_BLOCK, entityLocation, 4, 0); this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, REGULAR_RECORD_FLAGS); } else if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN) { this.worldRecordService.get().recordBlockBreak(ConstantKeys.SNOW_BLOCK, entityLocation, 2, 0); this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, REGULAR_RECORD_FLAGS); } else if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_WITHER) { this.worldRecordService.get().recordBlockBreak(ConstantKeys.SOUL_SAND, entityLocation, 4, 0); this.worldRecordService.get().recordBlockBreak(ConstantKeys.WITHER_SKELETON_SKULL, entityLocation, 3, REGULAR_RECORD_FLAGS); } else if (spawnReason == BUILD_COPPERGOLEM) { Block copperOrChestBlock = entityLocation.getBlock().getRelative(BlockFace.DOWN); Key copperBlock = Keys.of(copperOrChestBlock); this.worldRecordService.get().recordBlockBreak(copperBlock, entityLocation, 1, 0); this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, 0); BukkitExecutor.sync(() -> { Key chestBlock = Keys.of(copperOrChestBlock); this.worldRecordService.get().recordBlockPlace(chestBlock, entityLocation, 1, null, REGULAR_RECORD_FLAGS); }, 1L); } } } private void onPistonExtend(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) return; for (Block block : e.getArgs().blocks) { if (plugin.getNMSWorld().getPistonReaction(block) == PistonPushReaction.DESTROY) { this.worldRecordService.get().recordBlockBreak(block, 1, REGULAR_RECORD_FLAGS); } } } private void onLeavesDecay(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; this.worldRecordService.get().recordBlockBreak(block, 1, REGULAR_RECORD_FLAGS); } private void onBlockFromTo(GameEvent e) { Block block = e.getArgs().block; // Ignore dragon eggs, otherwise it will add +1 to the count of dragon eggs // when right-clicking them if (block.getType() == Material.DRAGON_EGG) return; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Block toBlock = e.getArgs().toBlock; if (toBlock.getType() != Material.AIR) { // Do not save block counts this.worldRecordService.get().recordBlockBreak(toBlock, 1, WorldRecordFlags.DIRTY_CHUNKS); } else { BukkitExecutor.sync(() -> { // Ignore cobblestone blocks, otherwise it will add +1 to the count of cobblestone when generated // from cobblestone generator if (toBlock.getType() != Material.COBBLESTONE) { // Do not save block counts this.worldRecordService.get().recordBlockPlace(toBlock, 1, null, WorldRecordFlags.DIRTY_CHUNKS); } }); } } private void onBlockFade(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; BlockState newState = e.getArgs().newState; if (newState.getType() == Material.AIR) { this.worldRecordService.get().recordBlockBreak(block, REGULAR_RECORD_FLAGS); } else { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(Keys.of(newState), newState.getLocation(wrapper.getHandle()), 1, block.getState(), REGULAR_RECORD_FLAGS); } } } private void onEntityExplode(GameEvent e) { if (e.getArgs().isSoftExplosion) return; Entity entity = e.getArgs().entity; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); e.getArgs().blocks.forEach(block -> { Key blockKey = Keys.of(block); blockCounts.put(blockKey, blockCounts.getOrDefault(blockKey, 0) + 1); }); if (entity instanceof TNTPrimed) blockCounts.put(ConstantKeys.TNT, blockCounts.getOrDefault(ConstantKeys.TNT, 0) + 1); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordMultiBlocksBreak(blockCounts, entity.getLocation(wrapper.getHandle()), REGULAR_RECORD_FLAGS); } } private void onSpongeAbsorb(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = block.getLocation(wrapper.getHandle()); if (alreadySpongeAbosrbCalled.contains(location)) return; worldRecordService.get().recordBlockPlace(ConstantKeys.WET_SPONGE, location, 1, block.getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); alreadySpongeAbosrbCalled.add(location.clone()); } } private void onGenericGame(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().world)) return; // We only care about block_change if (!e.getArgs().gameEvent.equals("block_change")) return; Location blockLocation = e.getArgs().location; Block block = blockLocation.getBlock(); Material blockType = block.getType(); Key newBlockKey; Key oldBlockKey; if (blockType == OPEN_EYEBLOSSOM) { // OPEN_EYEBLOSSOM was changed, we want to remove CLOSED_EYEBLOSSOM and replace it with OPEN_EYEBLOSSOM newBlockKey = ConstantKeys.OPEN_EYEBLOSSOM; oldBlockKey = ConstantKeys.CLOSED_EYEBLOSSOM; } else if (blockType == CLOSED_EYEBLOSSOM) { // CLOSED_EYEBLOSSOM was changed, we want to remove OPEN_EYEBLOSSOM and replace it with CLOSED_EYEBLOSSOM newBlockKey = ConstantKeys.CLOSED_EYEBLOSSOM; oldBlockKey = ConstantKeys.OPEN_EYEBLOSSOM; } else { return; } worldRecordService.get().recordBlockPlace(newBlockKey, blockLocation, 1, null, 0); worldRecordService.get().recordBlockBreak(oldBlockKey, blockLocation, 1, REGULAR_RECORD_FLAGS); } /* INTERNAL */ private void registerListeners() { registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onBlockPlace); registerCallback(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketEmpty); registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.MONITOR, this::onStructureGrow); registerCallback(GameEventType.BLOCK_GROW_EVENT, GameEventPriority.MONITOR, this::onBlockGrow); registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.MONITOR, this::onBlockForm); registerCallback(GameEventType.BLOCK_SPREAD_EVENT, GameEventPriority.MONITOR, this::onBlockSpread); registerCallback(GameEventType.BLOCK_UPDATE_SHAPE_EVENT, GameEventPriority.MONITOR, this::onBlockShapeUpdate); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSpawnerChange); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.MONITOR, this::onEntityChangeBlock); registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onBlockBreak); registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketFill); registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onEntitySpawn); registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.MONITOR, this::onPistonExtend); registerCallback(GameEventType.LEAVES_DECAY_EVENT, GameEventPriority.MONITOR, this::onLeavesDecay); registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.MONITOR, this::onBlockFromTo); registerCallback(GameEventType.BLOCK_FADE_EVENT, GameEventPriority.MONITOR, this::onBlockFade); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onEntityExplode); registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.MONITOR, this::onSpongeAbsorb); if (CLOSED_EYEBLOSSOM != null || OPEN_EYEBLOSSOM != null) registerCallback(GameEventType.GENERIC_GAME_EVENT, GameEventPriority.MONITOR, this::onGenericGame); } @Nullable private static Key getMinecartBlockKey(EntityType minecartType) { switch (minecartType) { case MINECART_HOPPER: return ConstantKeys.HOPPER; case MINECART_COMMAND: return ConstantKeys.COMMAND_BLOCK; case MINECART_TNT: return ConstantKeys.TNT; case MINECART_FURNACE: return ConstantKeys.FURNACE; case MINECART_CHEST: return ConstantKeys.CHEST; case MINECART_MOB_SPAWNER: return ConstantKeys.MOB_SPAWNER; } return null; } private static Key getBlockKeyFromBucketMaterial(Material material) { return Keys.ofMaterialAndData(material.name().replace("_BUCKET", "")); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.events.EventCallback; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; import com.bgsoftware.superiorskyblock.world.BukkitItems; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.block.BlockFadeEvent; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFromToEvent; import org.bukkit.event.block.BlockGrowEvent; import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockRedstoneEvent; import org.bukkit.event.block.BlockSpreadEvent; import org.bukkit.event.block.EntityBlockFormEvent; import org.bukkit.event.block.LeavesDecayEvent; import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityChangeBlockEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityInteractEvent; import org.bukkit.event.entity.EntityPortalEnterEvent; import org.bukkit.event.entity.EntityPortalEvent; import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.entity.EntityTeleportEvent; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.PlayerLeashEntityEvent; import org.bukkit.event.entity.ProjectileHitEvent; import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.hanging.HangingPlaceEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerBucketFillEvent; import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerInteractAtEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerShearEntityEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerUnleashEntityEvent; import org.bukkit.event.vehicle.VehicleCreateEvent; import org.bukkit.event.vehicle.VehicleDamageEvent; import org.bukkit.event.vehicle.VehicleEnterEvent; import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; import org.bukkit.event.vehicle.VehicleMoveEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.inventory.ItemStack; import java.util.List; import java.util.Map; import java.util.function.Supplier; public class BukkitEventsListener implements Listener { private static final ReflectMethod PROJECTILE_HIT_TARGET_ENTITY = new ReflectMethod<>( ProjectileHitEvent.class, "getHitEntity"); private static final ReflectMethod PROJECTILE_HIT_EVENT_TARGET_BLOCK = new ReflectMethod<>( ProjectileHitEvent.class, "getHitBlock"); @Nullable private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "WIND_CHARGE"); @Nullable private static final EntityType BREEZE_WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "BREEZE_WIND_CHARGE"); private final SuperiorSkyblockPlugin plugin; public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; // Block Events createEventListener(GameEventType.BLOCK_BREAK_EVENT, BlockBreakEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_BURN_EVENT, BlockBurnEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_DISPENSE_EVENT, BlockDispenseEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_FADE_EVENT, BlockFadeEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_FORM_EVENT, BlockFormEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_FROM_TO_EVENT, BlockFromToEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_GROW_EVENT, BlockGrowEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_IGNITE_EVENT, BlockIgniteEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_PHYSICS_EVENT, BlockPhysicsEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_PLACE_EVENT, BlockPlaceEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_REDSTONE_EVENT, BlockRedstoneEvent.class, this::createGameEvent, this::cancelBlockRedstoneEvent); createEventListener(GameEventType.BLOCK_SPREAD_EVENT, BlockSpreadEvent.class, this::createGameEvent); createEventListener(GameEventType.LEAVES_DECAY_EVENT, LeavesDecayEvent.class, this::createGameEvent); createEventListener(GameEventType.PISTON_EXTEND_EVENT, BlockPistonExtendEvent.class, this::createGameEvent); createEventListener(GameEventType.PISTON_RETRACT_EVENT, BlockPistonRetractEvent.class, this::createGameEvent); // World Events createEventListener(GameEventType.CHUNK_LOAD_EVENT, ChunkLoadEvent.class, this::createGameEvent); createEventListener(GameEventType.CHUNK_UNLOAD_EVENT, ChunkUnloadEvent.class, this::createGameEvent); createEventListener(GameEventType.SIGN_CHANGE_EVENT, SignChangeEvent.class, this::createGameEvent); createEventListener(GameEventType.STRUCTURE_GROW_EVENT, StructureGrowEvent.class, this::createGameEvent); createEventListener(GameEventType.WORLD_UNLOAD_EVENT, WorldUnloadEvent.class, this::createGameEvent); // Entity Events createEventListener(GameEventType.ENTITY_BLOCK_FORM_EVENT, EntityBlockFormEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, EntityChangeBlockEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_COLLISION_EVENT, VehicleEntityCollisionEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, EntityDamageByEntityEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, EntityDamageEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, VehicleDamageEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_ENTER_PORTAL_EVENT, EntityPortalEnterEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_EXPLODE_EVENT, EntityExplodeEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_INTERACT_EVENT, EntityInteractEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_MOVE_EVENT, PlayerMoveEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_MOVE_EVENT, VehicleMoveEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_PORTAL_EVENT, EntityPortalEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_PORTAL_EVENT, PlayerPortalEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_RIDE_EVENT, VehicleEnterEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_SPAWN_EVENT, CreatureSpawnEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_SPAWN_EVENT, HangingPlaceEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_SPAWN_EVENT, ItemSpawnEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_SPAWN_EVENT, VehicleCreateEvent.class, this::createGameEvent, this::cancelVehicleCreateEvent); createEventListener(GameEventType.ENTITY_TARGET_EVENT, EntityTargetEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_TELEPORT_EVENT, EntityTeleportEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_TELEPORT_EVENT, PlayerTeleportEvent.class, this::createGameEvent); createEventListener(GameEventType.HANGING_BREAK_EVENT, HangingBreakByEntityEvent.class, this::createGameEvent); createEventListener(GameEventType.HANGING_PLACE_EVENT, HangingPlaceEvent.class, this::createGameEvent2); createEventListener(GameEventType.PROJECTILE_HIT_EVENT, ProjectileHitEvent.class, this::createGameEvent); createEventListener(GameEventType.PROJECTILE_LAUNCH_EVENT, ProjectileLaunchEvent.class, this::createGameEvent); // Inventory Events createEventListener(GameEventType.INVENTORY_CLICK_EVENT, InventoryClickEvent.class, this::createGameEvent); createEventListener(GameEventType.INVENTORY_CLOSE_EVENT, InventoryCloseEvent.class, this::createGameEvent); createEventListener(GameEventType.INVENTORY_OPEN_EVENT, InventoryOpenEvent.class, this::createGameEvent); // Player Events createEventListener(GameEventType.PLAYER_CHANGED_WORLD_EVENT, PlayerChangedWorldEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_COMMAND_EVENT, PlayerCommandPreprocessEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_DROP_ITEM_EVENT, PlayerDropItemEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, PlayerBucketEmptyEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_FILL_BUCKET_EVENT, PlayerBucketFillEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_GAMEMODE_CHANGE, PlayerGameModeChangeEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractAtEntityEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEntityEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_ITEM_CONSUME_EVENT, PlayerItemConsumeEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_JOIN_EVENT, PlayerJoinEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_LEASH_ENTITY_EVENT, PlayerLeashEntityEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_LOGIN_EVENT, PlayerLoginEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_PICKUP_ITEM_EVENT, PlayerPickupItemEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_QUIT_EVENT, PlayerQuitEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_RESPAWN_EVENT, PlayerRespawnEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_SHEAR_ENTITY_EVENT, PlayerShearEntityEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_UNLEASH_ENTITY_EVENT, PlayerUnleashEntityEvent.class, this::createGameEvent); // Special Events (per version) try { Class.forName("org.bukkit.event.block.SpongeAbsorbEvent"); createEventListener(GameEventType.SPONGE_ABSORB_EVENT, org.bukkit.event.block.SpongeAbsorbEvent.class, new SpongeAbsorbEventFunction()); } catch (ClassNotFoundException ignored) { } try { Class.forName("com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent"); createEventListener(GameEventType.ENTITY_DEATH_EVENT, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent.class, new EntityRemoveFromWorldEventFunction()); } catch (ClassNotFoundException ignored) { createEventListener(GameEventType.ENTITY_DEATH_EVENT, EntityDeathEvent.class, this::createGameEvent); } boolean registeredChatListener = false; if (plugin.getSettings().getChatSigningSupport()) { try { Class.forName("io.papermc.paper.event.player.AsyncChatEvent"); createEventListener(GameEventType.PLAYER_CHAT_EVENT, io.papermc.paper.event.player.AsyncChatEvent.class, new AsyncChatEventFunctions(), new AsyncChatEventFunctions()); registeredChatListener = true; } catch (Exception ignored) { } } if (!registeredChatListener) createEventListener(GameEventType.PLAYER_CHAT_EVENT, AsyncPlayerChatEvent.class, this::createGameEvent); try { Class.forName("org.bukkit.event.player.PlayerPickupArrowEvent"); createEventListener(GameEventType.PLAYER_PICKUP_ARROW_EVENT, org.bukkit.event.player.PlayerPickupArrowEvent.class, new PlayerPickupArrowEventFunctions()); } catch (Exception ignored) { } try { Class.forName("org.bukkit.event.player.PlayerAttemptPickupItemEvent"); createEventListener(GameEventType.PLAYER_PICKUP_ITEM_EVENT, org.bukkit.event.player.PlayerAttemptPickupItemEvent.class, new PlayerPickupItemEventFunctions()); } catch (Exception ignored) { } try { Class.forName("org.bukkit.event.raid.RaidTriggerEvent"); createEventListener(GameEventType.RAID_TRIGGER_EVENT, org.bukkit.event.raid.RaidTriggerEvent.class, new RaidTriggerEventFunctions()); } catch (Exception ignored) { } try { Class genericGameEventClass = Class.forName("org.bukkit.event.world.GenericGameEvent"); createEventListener(GameEventType.GENERIC_GAME_EVENT, genericGameEventClass, plugin.getNMSAlgorithms().getGenericGameCreator()); } catch (Exception ignored) { } } /* * BLOCK EVENTS */ private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockBreakEvent e) { GameEventArgs.BlockBreakEvent blockBreakEvent = new GameEventArgs.BlockBreakEvent(); blockBreakEvent.block = e.getBlock(); blockBreakEvent.player = e.getPlayer(); return eventType.createEvent(blockBreakEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockBurnEvent e) { GameEventArgs.BlockBurnEvent blockBurnEvent = new GameEventArgs.BlockBurnEvent(); blockBurnEvent.block = e.getBlock(); return eventType.createEvent(blockBurnEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockDispenseEvent e) { GameEventArgs.BlockDispenseEvent blockDispenseEvent = new GameEventArgs.BlockDispenseEvent(); blockDispenseEvent.block = e.getBlock(); blockDispenseEvent.dispensedItem = e.getItem(); blockDispenseEvent.velocity = e.getVelocity(); return eventType.createEvent(blockDispenseEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFadeEvent e) { GameEventArgs.BlockFadeEvent blockFadeEvent = new GameEventArgs.BlockFadeEvent(); blockFadeEvent.block = e.getBlock(); blockFadeEvent.newState = e.getNewState(); return eventType.createEvent(blockFadeEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFormEvent e) { GameEventArgs.BlockFormEvent blockFormEvent = new GameEventArgs.BlockFormEvent(); blockFormEvent.block = e.getBlock(); blockFormEvent.newState = e.getNewState(); return eventType.createEvent(blockFormEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFromToEvent e) { GameEventArgs.BlockFromToEvent blockFromToEvent = new GameEventArgs.BlockFromToEvent(); blockFromToEvent.block = e.getBlock(); blockFromToEvent.toBlock = e.getToBlock(); return eventType.createEvent(blockFromToEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockGrowEvent e) { GameEventArgs.BlockGrowEvent blockGrowEvent = new GameEventArgs.BlockGrowEvent(); blockGrowEvent.block = e.getBlock(); blockGrowEvent.newState = e.getNewState(); return eventType.createEvent(blockGrowEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockIgniteEvent e) { GameEventArgs.BlockIgniteEvent blockIgniteEvent = new GameEventArgs.BlockIgniteEvent(); blockIgniteEvent.block = e.getBlock(); blockIgniteEvent.igniteCause = e.getCause(); return eventType.createEvent(blockIgniteEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPhysicsEvent e) { GameEventArgs.BlockPhysicsEvent blockPhysicsEvent = new GameEventArgs.BlockPhysicsEvent(); blockPhysicsEvent.block = e.getBlock(); return eventType.createEvent(blockPhysicsEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPlaceEvent e) { GameEventArgs.BlockPlaceEvent blockPlaceEvent = new GameEventArgs.BlockPlaceEvent(); blockPlaceEvent.block = e.getBlock(); blockPlaceEvent.player = e.getPlayer(); blockPlaceEvent.againstBlock = e.getBlockAgainst(); blockPlaceEvent.replacedState = e.getBlockReplacedState(); blockPlaceEvent.usedHand = BukkitItems.getHand(e); blockPlaceEvent.usedItem = getHandItem(e.getPlayer(), blockPlaceEvent.usedHand, true, () -> e.getItemInHand()); return eventType.createEvent(blockPlaceEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockRedstoneEvent e) { GameEventArgs.BlockRedstoneEvent blockRedstoneEvent = new GameEventArgs.BlockRedstoneEvent(); blockRedstoneEvent.block = e.getBlock(); return eventType.createEvent(blockRedstoneEvent); } private void cancelBlockRedstoneEvent(BlockRedstoneEvent bukkitEvent, GameEvent gameEvent) { if (gameEvent.isCancelled()) bukkitEvent.setNewCurrent(0); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockSpreadEvent e) { GameEventArgs.BlockSpreadEvent blockSpreadEvent = new GameEventArgs.BlockSpreadEvent(); blockSpreadEvent.block = e.getBlock(); blockSpreadEvent.newState = e.getNewState(); blockSpreadEvent.source = e.getSource(); return eventType.createEvent(blockSpreadEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, LeavesDecayEvent e) { GameEventArgs.LeavesDecayEvent leavesDecayEvent = new GameEventArgs.LeavesDecayEvent(); leavesDecayEvent.block = e.getBlock(); return eventType.createEvent(leavesDecayEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPistonExtendEvent e) { GameEventArgs.PistonExtendEvent pistonExtendEvent = new GameEventArgs.PistonExtendEvent(); pistonExtendEvent.block = e.getBlock(); pistonExtendEvent.blocks = e.getBlocks(); pistonExtendEvent.direction = e.getDirection(); return eventType.createEvent(pistonExtendEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPistonRetractEvent e) { GameEventArgs.PistonRetractEvent pistonRetractEvent = new GameEventArgs.PistonRetractEvent(); pistonRetractEvent.block = e.getBlock(); pistonRetractEvent.blocks = e.getBlocks(); pistonRetractEvent.direction = e.getDirection(); return eventType.createEvent(pistonRetractEvent); } /* * WORLD EVENTS */ private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ChunkLoadEvent e) { GameEventArgs.ChunkLoadEvent chunkLoadEvent = new GameEventArgs.ChunkLoadEvent(); chunkLoadEvent.chunk = e.getChunk(); chunkLoadEvent.isNewChunk = e.isNewChunk(); return eventType.createEvent(chunkLoadEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ChunkUnloadEvent e) { GameEventArgs.ChunkUnloadEvent chunkUnloadEvent = new GameEventArgs.ChunkUnloadEvent(); chunkUnloadEvent.chunk = e.getChunk(); return eventType.createEvent(chunkUnloadEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, SignChangeEvent e) { GameEventArgs.SignChangeEvent signChangeEvent = new GameEventArgs.SignChangeEvent(); signChangeEvent.block = e.getBlock(); signChangeEvent.player = e.getPlayer(); signChangeEvent.lines = e.getLines(); return eventType.createEvent(signChangeEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, StructureGrowEvent e) { GameEventArgs.StructureGrowEvent structureGrowEvent = new GameEventArgs.StructureGrowEvent(); structureGrowEvent.world = e.getWorld(); structureGrowEvent.location = e.getLocation(); structureGrowEvent.blocks = e.getBlocks(); return eventType.createEvent(structureGrowEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, WorldUnloadEvent e) { GameEventArgs.WorldUnloadEvent worldUnloadEvent = new GameEventArgs.WorldUnloadEvent(); worldUnloadEvent.world = e.getWorld(); return eventType.createEvent(worldUnloadEvent); } /* * ENTITY EVENTS */ private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityBlockFormEvent e) { GameEventArgs.EntityBlockFormEvent entityBlockFormEvent = new GameEventArgs.EntityBlockFormEvent(); entityBlockFormEvent.block = e.getBlock(); entityBlockFormEvent.newState = e.getNewState(); entityBlockFormEvent.entity = e.getEntity(); return eventType.createEvent(entityBlockFormEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityChangeBlockEvent e) { GameEventArgs.EntityChangeBlockEvent entityChangeBlockEvent = new GameEventArgs.EntityChangeBlockEvent(); entityChangeBlockEvent.entity = e.getEntity(); entityChangeBlockEvent.block = e.getBlock(); if (ServerVersion.isLegacy()) { // noinspection deprecated entityChangeBlockEvent.newType = Keys.of(e.getTo(), e.getData()); } else { entityChangeBlockEvent.newType = Keys.of(e.getTo(), (byte) 0); } return eventType.createEvent(entityChangeBlockEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleEntityCollisionEvent e) { GameEventArgs.EntityCollisionEvent entityCollisionEvent = new GameEventArgs.EntityCollisionEvent(); entityCollisionEvent.entity = e.getEntity(); entityCollisionEvent.target = e.getVehicle(); return eventType.createEvent(entityCollisionEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDamageByEntityEvent e) { GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); entityDamageEvent.entity = e.getEntity(); entityDamageEvent.damageCause = e.getCause(); entityDamageEvent.damager = e.getDamager(); return eventType.createEvent(entityDamageEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDamageEvent e) { GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); entityDamageEvent.entity = e.getEntity(); entityDamageEvent.damageCause = e.getCause(); entityDamageEvent.damager = null; return eventType.createEvent(entityDamageEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleDamageEvent e) { GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); entityDamageEvent.entity = e.getVehicle(); entityDamageEvent.damager = e.getAttacker(); entityDamageEvent.damageCause = EntityDamageEvent.DamageCause.ENTITY_ATTACK; return eventType.createEvent(entityDamageEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEnterEvent e) { GameEventArgs.EntityEnterPortalEvent entityEnterPortalEvent = new GameEventArgs.EntityEnterPortalEvent(); entityEnterPortalEvent.entity = e.getEntity(); entityEnterPortalEvent.portalLocation = e.getLocation(); return eventType.createEvent(entityEnterPortalEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityExplodeEvent e) { GameEventArgs.EntityExplodeEvent entityExplodeEvent = new GameEventArgs.EntityExplodeEvent(); entityExplodeEvent.entity = e.getEntity(); entityExplodeEvent.blocks = e.blockList(); entityExplodeEvent.isSoftExplosion = e.getEntityType() == WIND_CHARGE || e.getEntityType() == BREEZE_WIND_CHARGE; return eventType.createEvent(entityExplodeEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityInteractEvent e) { GameEventArgs.EntityInteractEvent entityExplodeEvent = new GameEventArgs.EntityInteractEvent(); entityExplodeEvent.entity = e.getEntity(); entityExplodeEvent.block = e.getBlock(); return eventType.createEvent(entityExplodeEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerMoveEvent e) { Location from = e.getFrom(); Location to = e.getTo(); if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ() && from.getBlockY() == to.getBlockY()) return null; GameEventArgs.EntityMoveEvent entityMoveEvent = new GameEventArgs.EntityMoveEvent(); entityMoveEvent.entity = e.getPlayer(); entityMoveEvent.from = e.getFrom(); entityMoveEvent.to = e.getTo(); return eventType.createEvent(entityMoveEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleMoveEvent e) { Location from = e.getFrom(); Location to = e.getTo(); if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ() && from.getBlockY() == to.getBlockY()) return null; GameEventArgs.EntityMoveEvent entityMoveEvent = new GameEventArgs.EntityMoveEvent(); entityMoveEvent.entity = e.getVehicle(); entityMoveEvent.from = e.getFrom(); entityMoveEvent.to = e.getTo(); return eventType.createEvent(entityMoveEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEvent e) { GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); entityPortalEvent.entity = e.getEntity(); entityPortalEvent.cause = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; entityPortalEvent.from = e.getFrom(); entityPortalEvent.to = e.getTo(); return eventType.createEvent(entityPortalEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerPortalEvent e) { GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); entityPortalEvent.entity = e.getPlayer(); entityPortalEvent.cause = e.getTo() == null ? e.getCause() : e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; entityPortalEvent.from = e.getFrom(); entityPortalEvent.to = e.getTo(); return eventType.createEvent(entityPortalEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleEnterEvent e) { GameEventArgs.EntityRideEvent entityRideEvent = new GameEventArgs.EntityRideEvent(); entityRideEvent.entity = e.getEntered(); entityRideEvent.vehicle = e.getVehicle(); return eventType.createEvent(entityRideEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, CreatureSpawnEvent e) { GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); entitySpawnEvent.entity = e.getEntity(); entitySpawnEvent.spawnReason = e.getSpawnReason(); return eventType.createEvent(entitySpawnEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, HangingPlaceEvent e) { GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); entitySpawnEvent.entity = e.getEntity(); entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; return eventType.createEvent(entitySpawnEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ItemSpawnEvent e) { GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); entitySpawnEvent.entity = e.getEntity(); entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; return eventType.createEvent(entitySpawnEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleCreateEvent e) { GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); entitySpawnEvent.entity = e.getVehicle(); entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; return eventType.createEvent(entitySpawnEvent); } private void cancelVehicleCreateEvent(VehicleCreateEvent bukkitEvent, GameEvent gameEvent) { if (gameEvent.isCancelled()) bukkitEvent.getVehicle().remove(); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityTargetEvent e) { GameEventArgs.EntityTargetEvent entityTargetEvent = new GameEventArgs.EntityTargetEvent(); entityTargetEvent.entity = e.getEntity(); entityTargetEvent.target = e.getTarget(); return eventType.createEvent(entityTargetEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityTeleportEvent e) { GameEventArgs.EntityTeleportEvent entityTeleportEvent = new GameEventArgs.EntityTeleportEvent(); entityTeleportEvent.entity = e.getEntity(); entityTeleportEvent.from = e.getFrom(); entityTeleportEvent.to = e.getTo(); entityTeleportEvent.cause = PlayerTeleportEvent.TeleportCause.UNKNOWN; return eventType.createEvent(entityTeleportEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerTeleportEvent e) { GameEventArgs.EntityTeleportEvent entityTeleportEvent = new GameEventArgs.EntityTeleportEvent(); entityTeleportEvent.entity = e.getPlayer(); entityTeleportEvent.from = e.getFrom(); entityTeleportEvent.to = e.getTo(); entityTeleportEvent.cause = e.getCause(); return eventType.createEvent(entityTeleportEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, HangingBreakByEntityEvent e) { GameEventArgs.HangingBreakEvent hangingBreakEvent = new GameEventArgs.HangingBreakEvent(); hangingBreakEvent.entity = e.getEntity(); hangingBreakEvent.remover = e.getRemover(); hangingBreakEvent.removeCause = e.getCause(); return eventType.createEvent(hangingBreakEvent); } private GameEvent createGameEvent2(GameEventType eventType, GameEventPriority priority, HangingPlaceEvent e) { GameEventArgs.HangingPlaceEvent hangingPlaceEvent = new GameEventArgs.HangingPlaceEvent(); hangingPlaceEvent.entity = e.getEntity(); hangingPlaceEvent.player = e.getPlayer(); return eventType.createEvent(hangingPlaceEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ProjectileHitEvent e) { GameEventArgs.ProjectileHitEvent projectileHitEvent = new GameEventArgs.ProjectileHitEvent(); projectileHitEvent.entity = e.getEntity(); if (PROJECTILE_HIT_TARGET_ENTITY.isValid()) projectileHitEvent.hitEntity = PROJECTILE_HIT_TARGET_ENTITY.invoke(e); if (PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid()) projectileHitEvent.hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e); return eventType.createEvent(projectileHitEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ProjectileLaunchEvent e) { GameEventArgs.ProjectileLaunchEvent projectileLaunchEvent = new GameEventArgs.ProjectileLaunchEvent(); projectileLaunchEvent.entity = e.getEntity(); return eventType.createEvent(projectileLaunchEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDeathEvent e) { GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent(); entityDeathEvent.entity = e.getEntity(); return eventType.createEvent(entityDeathEvent); } /* * INVENTORY EVENTS */ private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, InventoryClickEvent e) { GameEventArgs.InventoryClickEvent inventoryClickEvent = new GameEventArgs.InventoryClickEvent(); inventoryClickEvent.bukkitEvent = e; return eventType.createEvent(inventoryClickEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, InventoryCloseEvent e) { GameEventArgs.InventoryCloseEvent inventoryCloseEvent = new GameEventArgs.InventoryCloseEvent(); inventoryCloseEvent.bukkitEvent = e; return eventType.createEvent(inventoryCloseEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, InventoryOpenEvent e) { GameEventArgs.InventoryOpenEvent inventoryOpenEvent = new GameEventArgs.InventoryOpenEvent(); inventoryOpenEvent.bukkitEvent = e; return eventType.createEvent(inventoryOpenEvent); } /* * PLAYER EVENTS */ private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerChangedWorldEvent e) { GameEventArgs.PlayerChangedWorldEvent playerChangedWorldEvent = new GameEventArgs.PlayerChangedWorldEvent(); playerChangedWorldEvent.player = e.getPlayer(); playerChangedWorldEvent.from = e.getFrom(); return eventType.createEvent(playerChangedWorldEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerCommandPreprocessEvent e) { GameEventArgs.PlayerCommandEvent playerCommandEvent = new GameEventArgs.PlayerCommandEvent(); playerCommandEvent.player = e.getPlayer(); playerCommandEvent.command = e.getMessage(); return eventType.createEvent(playerCommandEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerDropItemEvent e) { GameEventArgs.PlayerDropItemEvent playerDropItemEvent = new GameEventArgs.PlayerDropItemEvent(); playerDropItemEvent.player = e.getPlayer(); playerDropItemEvent.droppedItem = e.getItemDrop(); return eventType.createEvent(playerDropItemEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerBucketEmptyEvent e) { GameEventArgs.PlayerEmptyBucketEvent playerEmptyBucketEvent = new GameEventArgs.PlayerEmptyBucketEvent(); playerEmptyBucketEvent.player = e.getPlayer(); playerEmptyBucketEvent.bucket = e.getBucket(); playerEmptyBucketEvent.clickedBlock = e.getBlockClicked(); return eventType.createEvent(playerEmptyBucketEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerBucketFillEvent e) { GameEventArgs.PlayerFillBucketEvent playerFillBucketEvent = new GameEventArgs.PlayerFillBucketEvent(); playerFillBucketEvent.player = e.getPlayer(); playerFillBucketEvent.bucket = e.getBucket(); playerFillBucketEvent.clickedBlock = e.getBlockClicked(); return eventType.createEvent(playerFillBucketEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerGameModeChangeEvent e) { GameEventArgs.PlayerGamemodeChangeEvent playerGamemodeChangeEvent = new GameEventArgs.PlayerGamemodeChangeEvent(); playerGamemodeChangeEvent.player = e.getPlayer(); playerGamemodeChangeEvent.newGamemode = e.getNewGameMode(); return eventType.createEvent(playerGamemodeChangeEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractAtEntityEvent e) { GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = Action.RIGHT_CLICK_AIR; playerInteractEvent.usedHand = BukkitItems.getHand(e); playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null); playerInteractEvent.clickedEntity = e.getRightClicked(); return eventType.createEvent(playerInteractEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractEntityEvent e) { GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = Action.RIGHT_CLICK_AIR; playerInteractEvent.usedHand = BukkitItems.getHand(e); playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null); playerInteractEvent.clickedEntity = e.getRightClicked(); return eventType.createEvent(playerInteractEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractEvent e) { GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = e.getAction(); playerInteractEvent.usedHand = BukkitItems.getHand(e); playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, () -> e.getItem()); playerInteractEvent.clickedBlock = e.getClickedBlock(); return eventType.createEvent(playerInteractEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerItemConsumeEvent e) { GameEventArgs.PlayerItemConsumeEvent playerItemConsumeEvent = new GameEventArgs.PlayerItemConsumeEvent(); playerItemConsumeEvent.player = e.getPlayer(); playerItemConsumeEvent.consumedItem = e.getItem(); return eventType.createEvent(playerItemConsumeEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerJoinEvent e) { GameEventArgs.PlayerJoinEvent playerJoinEvent = new GameEventArgs.PlayerJoinEvent(); playerJoinEvent.player = e.getPlayer(); return eventType.createEvent(playerJoinEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerLeashEntityEvent e) { GameEventArgs.PlayerLeashEntityEvent playerLeashEntityEvent = new GameEventArgs.PlayerLeashEntityEvent(); playerLeashEntityEvent.player = e.getPlayer(); playerLeashEntityEvent.entity = e.getEntity(); return eventType.createEvent(playerLeashEntityEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerLoginEvent e) { GameEventArgs.PlayerLoginEvent playerLoginEvent = new GameEventArgs.PlayerLoginEvent(); playerLoginEvent.player = e.getPlayer(); return eventType.createEvent(playerLoginEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerPickupItemEvent e) { GameEventArgs.PlayerPickupItemEvent playerPickupItemEvent = new GameEventArgs.PlayerPickupItemEvent(); playerPickupItemEvent.player = e.getPlayer(); playerPickupItemEvent.pickedUpItem = e.getItem(); return eventType.createEvent(playerPickupItemEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerQuitEvent e) { GameEventArgs.PlayerQuitEvent playerQuitEvent = new GameEventArgs.PlayerQuitEvent(); playerQuitEvent.player = e.getPlayer(); return eventType.createEvent(playerQuitEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerRespawnEvent e) { GameEventArgs.PlayerRespawnEvent playerRespawnEvent = new GameEventArgs.PlayerRespawnEvent(); playerRespawnEvent.player = e.getPlayer(); playerRespawnEvent.bukkitEvent = e; return eventType.createEvent(playerRespawnEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerShearEntityEvent e) { GameEventArgs.PlayerShearEntityEvent playerShearEntityEvent = new GameEventArgs.PlayerShearEntityEvent(); playerShearEntityEvent.player = e.getPlayer(); playerShearEntityEvent.entity = e.getEntity(); return eventType.createEvent(playerShearEntityEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerUnleashEntityEvent e) { GameEventArgs.PlayerUnleashEntityEvent playerUnleashEntityEvent = new GameEventArgs.PlayerUnleashEntityEvent(); playerUnleashEntityEvent.player = e.getPlayer(); playerUnleashEntityEvent.entity = e.getEntity(); return eventType.createEvent(playerUnleashEntityEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, AsyncPlayerChatEvent e) { GameEventArgs.PlayerChatEvent playerChatEvent = new GameEventArgs.PlayerChatEvent(); playerChatEvent.player = e.getPlayer(); playerChatEvent.message = e.getMessage(); playerChatEvent.format = e.getFormat(); return eventType.createEvent(playerChatEvent); } /* * INTERNALS */ private void createEventListener(GameEventType eventType, Class bukkitEventClass, GameEventCreator function) { createEventListener(eventType, bukkitEventClass, function, null); } private void createEventListener(GameEventType eventType, Class bukkitEventClass, GameEventCreator function, @Nullable ApplyBukkitEventFunction applyBukkitEventFunction) { Map> callbacks = plugin.getGameEventsDispatcher().getCallbacks(eventType); if (!callbacks.isEmpty()) { callbacks.keySet().forEach(priority -> createEventListenerForPriority(eventType, bukkitEventClass, priority, function, applyBukkitEventFunction)); } } private void createEventListenerForPriority(GameEventType eventType, Class bukkitEventClass, GameEventPriority gameEventPriority, GameEventCreator function, @Nullable ApplyBukkitEventFunction applyBukkitEventFunction) { EventPriority bukkitEventPriority = EventPriority.valueOf(gameEventPriority.name()); plugin.getServer().getPluginManager().registerEvent(bukkitEventClass, this, bukkitEventPriority, (listener, event) -> { if (!bukkitEventClass.isAssignableFrom(event.getClass())) return; IEventsDispatcher customEventsDispatcher = plugin.getEventsDispatcher(); if (customEventsDispatcher != null) { if (customEventsDispatcher.notifyEvent(event, bukkitEventPriority)) return; if (!customEventsDispatcher.shouldFallbackToDefaultExecutorOnFailure()) return; } GameEvent gameEvent = function.execute(eventType, gameEventPriority, (E) event); if (gameEvent == null) return; boolean cancelledBeforeDispatch = false; if (event instanceof Cancellable && ((Cancellable) event).isCancelled()) { gameEvent.setCancelled(); cancelledBeforeDispatch = true; } plugin.getGameEventsDispatcher().onGameEvent(gameEvent, gameEventPriority); if (!cancelledBeforeDispatch && gameEvent.isCancelled()) { if (event instanceof Cancellable) ((Cancellable) event).setCancelled(true); } if (applyBukkitEventFunction != null) applyBukkitEventFunction.apply((E) event, gameEvent); }, plugin, false); } private static ItemStack getHandItem(Player player, PlayerHand usedHand, boolean clone, @Nullable Supplier defItem) { ItemStack itemStack = BukkitItems.getHandItem(player, usedHand); if (clone && itemStack != null) { itemStack = itemStack.clone(); } if (defItem != null && (itemStack == null || itemStack.getType() == Material.AIR)) itemStack = defItem.get(); return itemStack; } public interface GameEventCreator { @Nullable GameEvent execute(GameEventType eventType, GameEventPriority priority, E e); } private interface ApplyBukkitEventFunction { void apply(E bukkitEvent, GameEvent event); } /* * SPECIAL EVENTS */ private static class SpongeAbsorbEventFunction implements GameEventCreator { @Override public GameEvent execute(GameEventType eventType, GameEventPriority priority, org.bukkit.event.block.SpongeAbsorbEvent e) { GameEventArgs.SpongeAbsorbEvent spongeAbsorbEvent = new GameEventArgs.SpongeAbsorbEvent(); spongeAbsorbEvent.block = e.getBlock(); spongeAbsorbEvent.blocks = e.getBlocks(); return eventType.createEvent(spongeAbsorbEvent); } } private class EntityRemoveFromWorldEventFunction implements GameEventCreator { @Override public GameEvent execute(GameEventType eventType, GameEventPriority priority, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent e) { Location entityLocation = e.getEntity().getLocation(); BukkitExecutor.sync(() -> { if (e.getEntity().isValid() && !e.getEntity().isDead()) return; World world = entityLocation.getWorld(); int chunkX = entityLocation.getBlockX() >> 4; int chunkZ = entityLocation.getBlockZ() >> 4; // We don't want call this event if if (world.isChunkLoaded(chunkX, chunkZ)) { GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent(); entityDeathEvent.entity = e.getEntity(); GameEvent gameEvent = eventType.createEvent(entityDeathEvent); plugin.getGameEventsDispatcher().onGameEvent(gameEvent, priority); } }, 1L); return null; } } private class AsyncChatEventFunctions implements GameEventCreator, ApplyBukkitEventFunction { @Override public GameEvent execute(GameEventType eventType, GameEventPriority priority, io.papermc.paper.event.player.AsyncChatEvent e) { GameEventArgs.PlayerChatEvent playerChatEvent = new GameEventArgs.PlayerChatEvent(); playerChatEvent.player = e.getPlayer(); playerChatEvent.message = LegacyComponentSerializer.legacyAmpersand().serialize(e.message()); return eventType.createEvent(playerChatEvent); } @Override public void apply(io.papermc.paper.event.player.AsyncChatEvent bukkitEvent, GameEvent event) { plugin.getNMSAlgorithms().handlePaperChatRenderer(bukkitEvent); } } private static class PlayerPickupArrowEventFunctions implements GameEventCreator { @Override public GameEvent execute(GameEventType eventType, GameEventPriority priority, org.bukkit.event.player.PlayerPickupArrowEvent e) { GameEventArgs.PlayerPickupArrowEvent playerPickupArrowEvent = new GameEventArgs.PlayerPickupArrowEvent(); playerPickupArrowEvent.player = e.getPlayer(); playerPickupArrowEvent.pickedUpItem = e.getItem(); return eventType.createEvent(playerPickupArrowEvent); } } private static class PlayerPickupItemEventFunctions implements GameEventCreator { @Override public GameEvent execute(GameEventType eventType, GameEventPriority priority, org.bukkit.event.player.PlayerAttemptPickupItemEvent e) { GameEventArgs.PlayerPickupItemEvent playerPickupItemEvent = new GameEventArgs.PlayerPickupItemEvent(); playerPickupItemEvent.player = e.getPlayer(); playerPickupItemEvent.pickedUpItem = e.getItem(); return eventType.createEvent(playerPickupItemEvent); } } private static class RaidTriggerEventFunctions implements GameEventCreator { @Override public GameEvent execute(GameEventType eventType, GameEventPriority priority, org.bukkit.event.raid.RaidTriggerEvent e) { GameEventArgs.RaidTriggerEvent raidTriggerEvent = new GameEventArgs.RaidTriggerEvent(); raidTriggerEvent.world = e.getWorld(); raidTriggerEvent.player = e.getPlayer(); raidTriggerEvent.raidLocation = e.getRaid().getLocation(); return eventType.createEvent(raidTriggerEvent); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import java.util.regex.Matcher; import java.util.regex.Pattern; public class BukkitListeners { private static final Pattern LISTENER_REGISTER_FAILURE = Pattern.compile("Plugin SuperiorSkyblock2 v(.*) has failed to register events for (.*) because (.*) does not exist\\."); private final SuperiorSkyblockPlugin plugin; private String listenerRegisterFailure = ""; public BukkitListeners(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } public void registerListeners() { new AdminPlayersListener(this.plugin); new ChunksListener(this.plugin); new EntityTrackingListener(this.plugin); new FeaturesListener(this.plugin); new IslandFlagsListener(this.plugin); new IslandWorldEventsListener(this.plugin); new MenusListener(this.plugin); new PlayersListener(this.plugin); new PortalsListener(this.plugin); new ProtectionListener(this.plugin); new SignsListener(this.plugin); new StackedBlocksListener(this.plugin); new WorldDestructionListener(this.plugin); if (plugin.getSettings().isStopLeaving()) new IslandOutsideListener(this.plugin); if (plugin.getSettings().isAutoBlocksTracking()) new BlockChangesListener(this.plugin); if (!plugin.getSettings().getIslandPreviews().getLocations().isEmpty()) new IslandPreviewListener(this.plugin); safeEventsRegister(new BukkitEventsListener(this.plugin)); } public void unregisterListeners() { plugin.getGameEventsDispatcher().clearCallbacks(); HandlerList.unregisterAll(this.plugin); } public void registerListenerFailureFilter() { plugin.getLogger().setFilter(record -> { Matcher matcher = LISTENER_REGISTER_FAILURE.matcher(record.getMessage()); if (matcher.find()) listenerRegisterFailure = matcher.group(3); return true; }); } private void safeEventsRegister(Listener listener) { listenerRegisterFailure = ""; plugin.getServer().getPluginManager().registerEvents(listener, plugin); if (!listenerRegisterFailure.isEmpty()) throw new RuntimeException(listenerRegisterFailure); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; public class ChunksListener extends AbstractGameEventListener { private final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; public ChunksListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerCallback(GameEventType.CHUNK_UNLOAD_EVENT, GameEventPriority.MONITOR, this::onChunkUnload); registerCallback(GameEventType.WORLD_UNLOAD_EVENT, GameEventPriority.MONITOR, this::onWorldUnload); registerCallback(GameEventType.CHUNK_LOAD_EVENT, GameEventPriority.MONITOR, this::onChunkLoad); } private void onChunkUnload(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().chunk.getWorld())) return; handleChunkUnload(e.getArgs().chunk); } private void onWorldUnload(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().world)) return; for (Chunk loadedChunk : e.getArgs().world.getLoadedChunks()) handleChunkUnload(loadedChunk); } private void onChunkLoad(GameEvent e) { handleChunkLoad(e.getArgs().chunk, e.getArgs().isNewChunk); } /* INTERNAL */ private void handleChunkUnload(Chunk chunk) { plugin.getStackedBlocks().removeStackedBlockHolograms(chunk); List chunkIslands = plugin.getGrid().getIslandsAt(chunk); chunkIslands.forEach(island -> { if (!island.isSpawn()) handleIslandChunkUnload(island, chunk); }); } private void handleIslandChunkUnload(Island island, Chunk chunk) { if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class)) plugin.getNMSChunks().startTickingChunk(island, chunk, true); if (!plugin.getNMSChunks().isChunkEmpty(chunk)) island.markChunkDirty(chunk.getWorld(), chunk.getX(), chunk.getZ(), true); Arrays.stream(chunk.getEntities()).forEach(this.worldRecordService.get()::recordEntityDespawn); } private void handleChunkLoad(Chunk chunk, boolean isNewChunk) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(chunk.getWorld())) return; List chunkIslands = plugin.getGrid().getIslandsAt(chunk); chunkIslands.forEach(island -> { if (!island.isSpawn()) { try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { handleIslandChunkLoad(island, chunk, chunkPosition, isNewChunk); } } }); } private void handleIslandChunkLoad(Island island, Chunk chunk, ChunkPosition chunkPosition, boolean isNewChunk) { World world = chunk.getWorld(); Dimension dimension = plugin.getGrid().getIslandsWorldDimension(world); if (isNewChunk && dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { Biome defaultWorldBiome = IslandUtils.getDefaultWorldBiome(dimension); // We want to update the biome for new island chunks. if (island.getBiome() != defaultWorldBiome) { List playersToUpdate; try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { playersToUpdate = strategy.getPlayers(WorldInfo.of(world)); } plugin.getNMSChunks().setBiome(Collections.singletonList(chunkPosition), island.getBiome(), playersToUpdate); } } plugin.getNMSChunks().injectChunkSections(chunk); IslandCache islandCache = island.getCache(); Set pendingLoadedChunksForIsland = islandCache.computeIfAbsent(IslandCacheKeys.PENDING_LOADED_CHUNKS, k -> new LinkedHashSet<>()); pendingLoadedChunksForIsland.add(chunk); boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class); if (cropGrowthEnabled && island.isInsideRange(chunk)) plugin.getNMSChunks().startTickingChunk(island, chunk, false); if (!plugin.getNMSChunks().isChunkEmpty(chunk)) island.markChunkDirty(world, chunk.getX(), chunk.getZ(), true); BlockPosition islandCenter = island.getCenterPosition(); boolean entityLimitsEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class); MutableBoolean recalculateEntities = new MutableBoolean(false); if (chunk.getX() == (islandCenter.getX() >> 4) && chunk.getZ() == (islandCenter.getZ() >> 4)) { if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { Block chunkBlock = chunk.getBlock(0, 100, 0); island.setBiome(world.getBiome(chunkBlock.getX(), chunkBlock.getZ()), false); } if (entityLimitsEnabled) recalculateEntities.set(true); } BukkitExecutor.sync(() -> { if (chunk.isLoaded()) // Update holograms of stacked blocks in delay so the chunk is entirely loaded. plugin.getStackedBlocks().updateStackedBlockHolograms(chunk); }, 10L); BukkitExecutor.sync(() -> { if (!pendingLoadedChunksForIsland.remove(chunk) || !chunk.isLoaded()) return; // If we cannot recalculate entities at this moment, we want to track entities normally. if (!island.getEntitiesTracker().canRecalculateEntityCounts()) recalculateEntities.set(false); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { for (Entity entity : chunk.getEntities()) { // We want to delete old holograms of stacked blocks + count entities for the chunk if (entity instanceof ArmorStand && isOldHologram((ArmorStand) entity) && plugin.getStackedBlocks().getStackedBlockAmount(entity.getLocation(wrapper.getHandle()).subtract(0, 1, 0)) > 1) { entity.remove(); } } } if (recalculateEntities.get()) { island.getEntitiesTracker().recalculateEntityCounts(); pendingLoadedChunksForIsland.clear(); islandCache.remove(IslandCacheKeys.PENDING_LOADED_CHUNKS); } }, 2L); DefaultIslandCalculationAlgorithm.CACHED_CALCULATED_CHUNKS.write(cache -> cache.remove(chunkPosition)); } private static boolean isOldHologram(ArmorStand armorStand) { return !armorStand.hasGravity() && armorStand.isSmall() && !armorStand.isVisible() && armorStand.isCustomNameVisible() && armorStand.isMarker() && armorStand.getCustomName() != null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.entity.Entity; public class EntityTrackingListener extends AbstractGameEventListener { private final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; public EntityTrackingListener(SuperiorSkyblockPlugin plugin) { super(plugin); this.registerListeners(); } private void onEntitySpawn(GameEvent e) { Entity entity = e.getArgs().entity; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; this.worldRecordService.get().recordEntitySpawn(entity); } private void onEntityDeath(GameEvent e) { Entity entity = e.getArgs().entity; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; worldRecordService.get().recordEntityDespawn(entity); } /* INTERNAL */ private void registerListeners() { registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onEntitySpawn); registerCallback(GameEventType.ENTITY_DEATH_EVENT, GameEventPriority.MONITOR, this::onEntityDeath); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.inventory.ItemStack; import java.lang.reflect.Field; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; public class FeaturesListener extends AbstractGameEventListener { private static final EnumerateMap, PlaceholdersPopulator> POPULATORS = new EnumerateMap<>(PluginEventType.values()); @Nullable private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); @Nullable private static final Material TRIAL_SPAWNER = EnumHelper.getEnum(Material.class, "TRIAL_SPAWNER"); @Nullable private static final Material SCULK_SENSOR = EnumHelper.getEnum(Material.class, "SCULK_SENSOR"); @Nullable private static final Material SCULK_SHRIEKER = EnumHelper.getEnum(Material.class, "SCULK_SHRIEKER"); private final LazyReference protectionManager = new LazyReference() { @Override protected RegionManagerService create() { return plugin.getServices().getService(RegionManagerService.class); } }; public FeaturesListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerListeners(); } /* EVENT COMMANDS */ private void onGeneralPluginEvent(PluginEvent event) { List commands = plugin.getSettings().getEventCommands().get(event.getType().getBukkitEventName()); if (commands == null) return; Map placeholdersReplaces = new HashMap<>(); PlaceholdersPopulator placeholdersPopulator = POPULATORS.computeIfAbsent(event.getType(), type -> createPlaceholdersPopulator(event.getArgs().getClass())); if (placeholdersPopulator != null) placeholdersPopulator.populate(event.getArgs(), placeholdersReplaces); BukkitExecutor.ensureMain(() -> { for (String command : commands) { for (Map.Entry replaceEntry : placeholdersReplaces.entrySet()) command = command.replace(replaceEntry.getKey(), replaceEntry.getValue()); Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command); } }); } /* OBSIDIAN TO LAVA */ private void onObsidianClick(GameEvent e) { Player player = e.getArgs().player; ItemStack handItem = e.getArgs().usedItem; Block clickedBlock = e.getArgs().clickedBlock; if (handItem == null || clickedBlock == null || handItem.getType() != Material.BUCKET || clickedBlock.getType() != Material.OBSIDIAN) return; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld())) return; if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) != 1) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.protectionManager.get().handleBlockBreak(superiorPlayer, clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(clickedBlock.getLocation(wrapper.getHandle())); } if (island == null) return; e.setCancelled(); ItemStack inHandItem = handItem.clone(); inHandItem.setAmount(inHandItem.getAmount() - 1); PlayerHand usedHand = e.getArgs().usedHand; BukkitItems.setHandItem(player, usedHand, inHandItem.getAmount() == 0 ? null : inHandItem); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { BukkitItems.addItem(new ItemStack(Material.LAVA_BUCKET), player.getInventory(), player.getLocation(wrapper.getHandle())); } island.handleBlockBreak(ConstantKeys.OBSIDIAN, 1); clickedBlock.setType(Material.AIR); } /* VISITORS BLOCKED COMMANDS */ private void onPlayerCommandAsVisitor(GameEvent e) { Player player = e.getArgs().player; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(player.getWorld())) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer.hasBypassModeEnabled()) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } if (island == null || island.isSpawn() || !island.isVisitor(superiorPlayer, true)) return; String[] message = e.getArgs().command.toLowerCase(Locale.ENGLISH).split(" "); String commandLabel = message[0].toCharArray()[0] == '/' ? message[0].substring(1) : message[0]; if (plugin.getSettings().getBlockedVisitorsCommands().stream().anyMatch(commandLabel::contains)) { e.setCancelled(); Message.VISITOR_BLOCK_COMMAND.send(superiorPlayer); } } /* PREVIEW BLOCKED COMMANDS */ private void onPlayerCommandWhilePreview(GameEvent e) { Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer.hasBypassModeEnabled()) return; IslandPreview islandPreview = plugin.getGrid().getIslandPreview(superiorPlayer); if (islandPreview == null) return; String[] message = e.getArgs().command.toLowerCase(Locale.ENGLISH).split(" "); String commandLabel = message[0].toCharArray()[0] == '/' ? message[0].substring(1) : message[0]; if (plugin.getSettings().getIslandPreviews().getBlockedCommands().stream().anyMatch(commandLabel::contains)) { e.setCancelled(); Message.ISLAND_PREVIEW_BLOCK_COMMAND.send(superiorPlayer); } } /* BLOCKS TRACKING */ private void onChunkLoad(GameEvent e) { Chunk chunk = e.getArgs().chunk; List chunkIslands = plugin.getGrid().getIslandsAt(chunk); chunkIslands.forEach(island -> handleIslandChunkLoad(island, chunk)); } private void handleIslandChunkLoad(Island island, Chunk chunk) { List blockEntities = plugin.getNMSChunks().getBlockEntities(chunk); if (blockEntities.isEmpty()) return; blockEntities.forEach(blockEntity -> { plugin.getNMSWorld().replaceSculkSensorListener(island, blockEntity); plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockEntity); }); } /* VAULTS & TRIAL SPAWNERS */ private void onTrialBlockPlace(GameEvent e) { Block block = e.getArgs().block; Material blockType = block.getType(); if (blockType != VAULT && blockType != TRIAL_SPAWNER) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(blockLocation); if (island == null) return; plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockLocation); } } /* SCULK SENSORS */ private void onSculkSensorPlace(GameEvent e) { Block block = e.getArgs().block; Material blockType = block.getType(); if (blockType != SCULK_SENSOR) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(blockLocation); if (island == null) return; plugin.getNMSWorld().replaceSculkSensorListener(island, blockLocation); } } private void onSculkShriekerInteract(GameEvent e) { Action action = e.getArgs().action; Block clickedBlock = e.getArgs().clickedBlock; if (action != Action.PHYSICAL || clickedBlock.getType() != SCULK_SHRIEKER) return; InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); Location blockLocation = clickedBlock.getLocation(wrapper.getHandle()); interactionResult = protectionManager.get().handleCustomInteraction(superiorPlayer, blockLocation, IslandPrivileges.SCULK_SENSOR); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) e.setCancelled(); } /* INTERNAL */ private void registerListeners() { for (PluginEventType eventType : PluginEventType.values()) { String bukkitEventName = eventType.getBukkitEventName(); if (bukkitEventName != null && plugin.getSettings().getEventCommands().containsKey(bukkitEventName)) plugin.getPluginEventsDispatcher().registerCallback(eventType, this::onGeneralPluginEvent); } if (plugin.getSettings().isObsidianToLava()) registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onObsidianClick); if (!plugin.getSettings().getBlockedVisitorsCommands().isEmpty()) registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommandAsVisitor); if (!plugin.getSettings().getIslandPreviews().getBlockedCommands().isEmpty()) registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommandWhilePreview); registerCallback(GameEventType.CHUNK_LOAD_EVENT, GameEventPriority.MONITOR, this::onChunkLoad); if (VAULT != null && TRIAL_SPAWNER != null) { registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onTrialBlockPlace); } if (SCULK_SENSOR != null && SCULK_SHRIEKER != null) { registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onSculkSensorPlace); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSculkShriekerInteract); } } private static PlaceholdersPopulator createPlaceholdersPopulator(Class argsClass) { List> fieldsData = new LinkedList<>(); collectAllFields(argsClass, field -> { ReflectField reflectField = new ReflectField<>(field.getDeclaringClass(), field.getType(), field.getName()); if (reflectField.isValid()) { String placeholder = "%" + field.getName() + "%"; FieldData fieldData = createFieldData(reflectField, field, placeholder); fieldsData.add(fieldData); if (field.getName().equals("superiorPlayer")) fieldsData.add(new FieldData(fieldData.reflectField, "%player%", fieldData.toStringMethod)); else if (field.getName().equals("targetPlayer")) fieldsData.add(new FieldData(fieldData.reflectField, "%target%", fieldData.toStringMethod)); } }); return (args, placeholders) -> { for (FieldData fieldData : fieldsData) { Optional.ofNullable(fieldData.reflectField.get(args)).ifPresent(value -> placeholders.put(fieldData.placeholder, (String) fieldData.toStringMethod.apply(value))); } }; } private static FieldData createFieldData(ReflectField reflectField, Field field, String placeholder) { if (field.getType() == SuperiorPlayer.class) return new FieldData<>((ReflectField) reflectField, placeholder, SuperiorPlayer::getName); else if (field.getType() == Island.class) return new FieldData<>((ReflectField) reflectField, placeholder, Island::getName); else if (field.getType() == Mission.class) return new FieldData<>((ReflectField) reflectField, placeholder, Mission::getName); else if (field.getType() == String.class) return new FieldData<>((ReflectField) reflectField, placeholder, s -> s); else return new FieldData<>(reflectField, placeholder, String::valueOf); } private static void collectAllFields(Class clazz, Consumer consumer) { while (clazz != null && clazz != Object.class) { for (Field field : clazz.getFields()) consumer.accept(field); clazz = clazz.getSuperclass(); } } private interface PlaceholdersPopulator { void populate(T args, Map placeholders); } private static class FieldData { private final ReflectField reflectField; private final Function toStringMethod; private final String placeholder; FieldData(ReflectField reflectField, String placeholder, Function toStringMethod) { this.reflectField = reflectField; this.toStringMethod = toStringMethod; this.placeholder = placeholder; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Chicken; import org.bukkit.entity.Enderman; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Fireball; import org.bukkit.entity.Ghast; import org.bukkit.entity.Item; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.potion.PotionEffectType; import org.bukkit.projectiles.ProjectileSource; import java.util.EnumSet; import java.util.List; import java.util.Optional; public class IslandFlagsListener extends AbstractGameEventListener { private static final EnumSet NATURAL_SPAWN_REASONS = initializeNaturalSpawnReasons(); private final Int2ObjectMapView originalFireballsDamager = CollectionsFactory.createInt2ObjectArrayMap(); private World spawnIslandWorld; public IslandFlagsListener(SuperiorSkyblockPlugin plugin) { super(plugin); this.registerListeners(); } /* INTERNAL EVENTS */ private void onSpawnUpdate() { // We want to optimize island checks only for island worlds // However, if the spawn world is not an islands world, we want to check it as well. Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter( plugin.getSettings().getWorlds().getDefaultWorldDimension()); this.spawnIslandWorld = spawnLocation.getWorld(); } /* ENTITY SPAWNING */ private void onEntitySpawn(GameEvent e) { // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(e.getArgs().entity.getWorld())) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = e.getArgs().entity.getLocation(wrapper.getHandle()); if (checkPreventEntitySpawn(e, location) || checkPreventEggLay(e, location)) e.setCancelled(); } } private boolean checkPreventEntitySpawn(GameEvent e, Location entityLocation) { CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason; if (spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER || spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER_EGG) { List entityCategories = BukkitEntities.getCategories(e.getArgs().entity); IslandFlag islandFlag; for (EntityCategory entityCategory : entityCategories) { islandFlag = entityCategory.getSpawnerSpawningIslandFlag(); if (islandFlag != null && preventAction(entityLocation, islandFlag)) { return true; } } } else if (NATURAL_SPAWN_REASONS.contains(spawnReason)) { List entityCategories = BukkitEntities.getCategories(e.getArgs().entity); IslandFlag islandFlag; for (EntityCategory entityCategory : entityCategories) { islandFlag = entityCategory.getNaturalSpawningIslandFlag(); if (islandFlag != null && preventAction(entityLocation, islandFlag)) { return true; } } } return false; } private boolean checkPreventEggLay(GameEvent e, Location entityLocation) { if (!(e.getArgs().entity instanceof Item)) return false; Item item = (Item) e.getArgs().entity; if (item.getItemStack().getType() != Material.EGG) return false; if (preventAction(entityLocation, IslandFlags.EGG_LAY)) { for (Entity entity : item.getNearbyEntities(1, 1, 1)) { if (entity instanceof Chicken) { return true; } } } return false; } /* ENTITY EXPLOSIONS */ private void onHangingBreakByEntity(GameEvent e) { Entity entity = e.getArgs().entity; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(entity.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); HangingBreakEvent.RemoveCause removeCause = e.getArgs().removeCause; Entity remover = e.getArgs().remover; if (removeCause == HangingBreakEvent.RemoveCause.EXPLOSION) { if (remover instanceof Player) { // Explosion was set by TNT. if (preventAction(entityLocation, IslandFlags.TNT_EXPLOSION)) { e.setCancelled(); return; } } else if (remover instanceof Ghast) { // Explosion was set by TNT. if (preventAction(entityLocation, IslandFlags.GHAST_FIREBALL)) { e.setCancelled(); return; } } } if (preventEntityExplosion(remover, entityLocation)) { e.setCancelled(); } } } private void onEntityExplode(GameEvent e) { Entity entity = e.getArgs().entity; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(entity.getWorld())) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventEntityExplosion(entity, entity.getLocation(wrapper.getHandle()))) e.getArgs().blocks.clear(); } } private void onEntityChangeBlock(GameEvent e) { Block block = e.getArgs().block; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(block.getWorld())) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventEntityExplosion(e.getArgs().entity, block.getLocation(wrapper.getHandle()))) e.setCancelled(); } } private void onFireballDamage(GameEvent e) { Entity entity = e.getArgs().entity; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(entity.getWorld())) { return; } if (entity instanceof Fireball) { originalFireballsDamager.put(entity.getEntityId(), ((Fireball) entity).getShooter()); BukkitExecutor.sync(() -> originalFireballsDamager.remove(entity.getEntityId()), 40L); } } public boolean preventEntityExplosion(Entity source, Location explodeLocation) { IslandFlag islandFlag; switch (source.getType()) { case CREEPER: islandFlag = IslandFlags.CREEPER_EXPLOSION; break; case PRIMED_TNT: case MINECART_TNT: islandFlag = IslandFlags.TNT_EXPLOSION; break; case WITHER: case WITHER_SKULL: islandFlag = IslandFlags.WITHER_EXPLOSION; break; case FIREBALL: { ProjectileSource projectileSource = originalFireballsDamager.remove(source.getEntityId()); if (projectileSource == null) projectileSource = ((Fireball) source).getShooter(); if (projectileSource instanceof Ghast) { islandFlag = IslandFlags.GHAST_FIREBALL; break; } } default: return false; } return preventAction(explodeLocation, islandFlag); } /* GENERAL EVENTS */ private void onBlockFlow(GameEvent e) { Block block = e.getArgs().block; Block toBlock = e.getArgs().toBlock; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(toBlock.getWorld())) { return; } IslandFlag islandFlag = plugin.getNMSWorld().isWaterLogged(block) ? IslandFlags.WATER_FLOW : IslandFlags.LAVA_FLOW; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventAction(toBlock.getLocation(wrapper.getHandle()), islandFlag)) e.setCancelled(); } } private void onCropsGrowth(GameEvent e) { Block block = e.getArgs().block; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(block.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.CROPS_GROWTH)) e.setCancelled(); } } private void onTreeGrowth(GameEvent e) { Location location = e.getArgs().location; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(location.getWorld())) { return; } if (preventAction(location, IslandFlags.TREE_GROWTH)) e.setCancelled(); } private void onFireSpread(GameEvent e) { Block block = e.getArgs().block; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(block.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) e.setCancelled(); } } private void onBlockIgnite(GameEvent e) { if (e.getArgs().igniteCause != BlockIgniteEvent.IgniteCause.SPREAD) return; Block block = e.getArgs().block; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(block.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) e.setCancelled(); } } private void onEndermanGrief(GameEvent e) { if (!(e.getArgs().entity instanceof Enderman)) return; Block block = e.getArgs().block; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(block.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.ENDERMAN_GRIEF)) e.setCancelled(); } } private void onPoisonAttack(GameEvent e) { Entity entity = e.getArgs().entity; EntityType entityType = entity.getType(); if (entityType != EntityType.SPLASH_POTION) return; // We only check island flags in relevant worlds if (shouldIgnoreWorldEvents(entity.getWorld())) { return; } BukkitEntities.getPlayerSource(entity).ifPresent(shooterPlayer -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (!preventAction(entity.getLocation(wrapper.getHandle()), IslandFlags.PVP)) return; } List nearbyEntities = entity.getNearbyEntities(2, 2, 2); BukkitExecutor.sync(() -> nearbyEntities.forEach(nearbyEntity -> { if (nearbyEntity instanceof LivingEntity && !nearbyEntity.getUniqueId().equals(shooterPlayer.getUniqueId())) ((LivingEntity) nearbyEntity).removePotionEffect(PotionEffectType.POISON); }), 1L); }); } /* INTERNAL */ private boolean preventAction(Location location, IslandFlag islandFlag) { Island island = plugin.getGrid().getIslandAt(location); if (island == null) return false; if (!plugin.getSettings().getSpawn().isProtected() && island.isSpawn()) return false; return !island.hasSettingsEnabled(islandFlag); } private void registerListeners() { registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.LOWEST, this::onEntityExplode); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEntityChangeBlock); registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEntitySpawn); registerCallback(GameEventType.HANGING_BREAK_EVENT, GameEventPriority.LOWEST, this::onHangingBreakByEntity); registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.MONITOR, this::onFireballDamage); registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.LOWEST, this::onBlockFlow); registerCallback(GameEventType.BLOCK_GROW_EVENT, GameEventPriority.LOWEST, this::onCropsGrowth); registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.LOWEST, this::onTreeGrowth); registerCallback(GameEventType.BLOCK_BURN_EVENT, GameEventPriority.LOWEST, this::onFireSpread); registerCallback(GameEventType.BLOCK_IGNITE_EVENT, GameEventPriority.LOWEST, this::onBlockIgnite); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEndermanGrief); registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.LOWEST, this::onPoisonAttack); plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SPAWN_UPDATE_EVENT, this::onSpawnUpdate); } private boolean shouldIgnoreWorldEvents(@Nullable World world) { return world == null || (world != this.spawnIslandWorld && !plugin.getGrid().isIslandsWorld(world)); } private static EnumSet initializeNaturalSpawnReasons() { EnumSet naturalSpawnReasons = EnumSet.noneOf(CreatureSpawnEvent.SpawnReason.class); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "JOCKEY")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "CHUNK_GEN")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "NATURAL")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "TRAP")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "MOUNT")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "VILLAGE_INVASION")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "VILLAGE_DEFENSE")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "PATROL")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BEEHIVE")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "LIGHTNING")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "DEFAULT")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "JOCKEY")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "JOCKEY")).ifPresent(naturalSpawnReasons::add); Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "JOCKEY")).ifPresent(naturalSpawnReasons::add); return naturalSpawnReasons; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; public class IslandOutsideListener extends AbstractGameEventListener { public IslandOutsideListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, this::onMinecartRightClick); registerCallback(GameEventType.ENTITY_RIDE_EVENT, GameEventPriority.NORMAL, this::onEntityRide); registerCallback(GameEventType.ENTITY_MOVE_EVENT, GameEventPriority.NORMAL, this::onEntityMove); } private void onMinecartRightClick(GameEvent e) { Entity rightClicked = e.getArgs().clickedEntity; if (rightClicked == null) return; if (!plugin.getGrid().isIslandsWorld(rightClicked.getWorld())) return; Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer.hasBypassModeEnabled()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = rightClicked.getLocation(wrapper.getHandle()); Island entityIsland = plugin.getGrid().getIslandAt(entityLocation); if (entityIsland != null && entityIsland.isInsideRange(entityLocation, 1D)) return; } e.setCancelled(); } private void onEntityRide(GameEvent e) { if (!plugin.getSettings().isStopLeaving()) return; Entity vehicle = e.getArgs().vehicle; if (!plugin.getGrid().isIslandsWorld(vehicle.getWorld())) return; Entity entity = e.getArgs().entity; if (entity instanceof Player && plugin.getPlayers().getSuperiorPlayer(entity).hasBypassModeEnabled()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location vehicleLocation = vehicle.getLocation(wrapper.getHandle()); Island entityIsland = plugin.getGrid().getIslandAt(vehicleLocation); if (entityIsland != null && entityIsland.isInsideRange(vehicleLocation, 1D)) return; } e.setCancelled(); } private void onEntityMove(GameEvent e) { if (!plugin.getSettings().isStopLeaving()) return; Location to = e.getArgs().to; World destinationWorld = to.getWorld(); if (!plugin.getGrid().isIslandsWorld(destinationWorld)) return; Entity entity = e.getArgs().entity; if (!entity.getWorld().equals(destinationWorld)) return; Location from = e.getArgs().from; if (entity instanceof Player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); if (handlePlayerMove(superiorPlayer, from, to, true, false)) e.setCancelled(); } else { Entity passenger = entity.getPassenger(); SuperiorPlayer superiorPlayer = passenger instanceof Player ? plugin.getPlayers().getSuperiorPlayer(passenger) : null; if (superiorPlayer == null) return; handlePlayerMove(superiorPlayer, from, to, false, true); } } private boolean handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Location to, boolean delayTeleport, boolean forceTeleport) { if (superiorPlayer.hasBypassModeEnabled()) return false; Island toIsland = plugin.getGrid().getIslandAt(to); if (toIsland != null && toIsland.isInsideRange(to, 1D)) return false; if (delayTeleport) { // If we don't delay the teleport, it will not occur due to the cancellation of PlayerMoveEvent BukkitExecutor.sync(() -> handlePlayerMoveOutsideIslandTeleport(superiorPlayer, from, forceTeleport), 1L); } else { handlePlayerMoveOutsideIslandTeleport(superiorPlayer, from, forceTeleport); } return true; } private void handlePlayerMoveOutsideIslandTeleport(SuperiorPlayer superiorPlayer, Location from, boolean forceTeleport) { Island fromIsland = plugin.getGrid().getIslandAt(from); Player player = superiorPlayer.asPlayer(); // We don't teleport in case we're inside the island, we just cancel the event. // However, if the player is in vehicle, we want to eject him and teleport. if (!forceTeleport && fromIsland != null && fromIsland.isInsideRange(from) && !player.isInsideVehicle()) return; player.eject(); if (fromIsland != null) { superiorPlayer.teleport(fromIsland, result -> { if (!result) { superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); } }); } else { superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import org.bukkit.GameMode; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; public class IslandPreviewListener extends AbstractGameEventListener { public IslandPreviewListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerCallback(GameEventType.PLAYER_QUIT_EVENT, GameEventPriority.MONITOR, this::onPlayerQuit); registerCallback(GameEventType.ENTITY_TELEPORT_EVENT, GameEventPriority.NORMAL, this::onPlayerTeleport); } private void onPlayerQuit(GameEvent e) { Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) superiorPlayer).release(); return; } // Cancelling island preview mode if (plugin.getGrid().getIslandPreview(superiorPlayer) != null) { GameMode gameMode = plugin.getGrid().getIslandPreview(superiorPlayer).getPreviousGameMode(); plugin.getGrid().cancelIslandPreview(superiorPlayer); /* cancelIslandPreview changes the GameMode and teleports the player later. In this case tho, we want the things to be instant - no async, no nothing. */ player.setGameMode(gameMode); player.teleport(plugin.getGrid().getSpawnIsland().getCenter( plugin.getSettings().getWorlds().getDefaultWorldDimension())); } } private void onPlayerTeleport(GameEvent e) { Entity entity = e.getArgs().entity; if (!(entity instanceof Player)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); if (superiorPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) superiorPlayer).release(); return; } if (((Player) entity).getGameMode() == plugin.getSettings().getIslandPreviews().getGameMode() && plugin.getGrid().getIslandPreview(superiorPlayer) != null) e.setCancelled(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.Entity; public class IslandWorldEventsListener extends AbstractGameEventListener { private final LazyReference hologramsService = new LazyReference() { @Override protected HologramsService create() { return plugin.getServices().getService(HologramsService.class); } }; public IslandWorldEventsListener(SuperiorSkyblockPlugin plugin) { super(plugin); if (plugin.getSettings().isDisableRedstoneOffline() || plugin.getSettings().getAFKIntegrations().isDisableRedstone()) registerCallback(GameEventType.BLOCK_REDSTONE_EVENT, GameEventPriority.HIGHEST, this::onBlockRedstone); if (plugin.getSettings().getAFKIntegrations().isDisableSpawning()) registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.HIGHEST, this::onEntitySpawn); } private void onBlockRedstone(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(block.getLocation(wrapper.getHandle())); } if (island == null || island.isSpawn()) return; if ((plugin.getSettings().isDisableRedstoneOffline() && !island.isCurrentlyActive()) || (plugin.getSettings().getAFKIntegrations().isDisableRedstone() && island.getAllPlayersInside().stream().allMatch(SuperiorPlayer::isAFK))) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Log.debug(Debug.DISABLE_REDSTONE, island.getOwner().getName(), block.getLocation(wrapper.getHandle())); } e.setCancelled(); } } private void onEntitySpawn(GameEvent e) { Entity entity = e.getArgs().entity; if (hologramsService.get().isHologram(entity)) return; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); } if (island == null || island.isSpawn() || !island.getAllPlayersInside().stream().allMatch(SuperiorPlayer::isAFK)) return; e.setCancelled(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; public class MenusListener extends AbstractGameEventListener { private final Int2ObjectMapView latestClickedItem = CollectionsFactory.createInt2ObjectArrayMap(); public MenusListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.MONITOR, false, this::onInventoryClickDupePatch); registerCallback(GameEventType.INVENTORY_CLOSE_EVENT, GameEventPriority.MONITOR, false, this::onInventoryCloseDupePatch); registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.NORMAL, this::onMenuClick); registerCallback(GameEventType.INVENTORY_CLOSE_EVENT, GameEventPriority.NORMAL, this::onMenuClose); } /* * The following two events are here for patching a dupe glitch caused * by shift clicking and closing the inventory at the same time. */ private void onInventoryClickDupePatch(GameEvent e) { if (!e.isCancelled()) return; ItemStack clickedItem = e.getArgs().bukkitEvent.getCurrentItem(); Inventory inventory = e.getArgs().bukkitEvent.getClickedInventory(); if (clickedItem != null && inventory != null && inventory.getHolder() instanceof MenuView) { int entityId = e.getArgs().bukkitEvent.getWhoClicked().getEntityId(); latestClickedItem.put(entityId, clickedItem); BukkitExecutor.sync(() -> latestClickedItem.remove(entityId), 20L); } } private void onInventoryCloseDupePatch(GameEvent e) { Player player = (Player) e.getArgs().bukkitEvent.getPlayer(); ItemStack clickedItem = latestClickedItem.remove(player.getEntityId()); if (clickedItem != null) { BukkitExecutor.sync(() -> { player.getInventory().removeItem(clickedItem); player.updateInventory(); }, 1L); } } /* MENU INTERACTIONS HANDLING */ private void onMenuClick(GameEvent e) { InventoryView inventoryView = e.getArgs().bukkitEvent.getView(); Inventory clickedInventory = e.getArgs().bukkitEvent.getClickedInventory(); Inventory topInventory = inventoryView.getTopInventory(); if (topInventory == null || clickedInventory == null) return; InventoryHolder inventoryHolder = topInventory.getHolder(); if (inventoryHolder instanceof MenuView) { e.setCancelled(); if (clickedInventory.equals(topInventory)) { MenuView menuView = (MenuView) inventoryHolder; menuView.getMenu().onClick(e.getArgs().bukkitEvent, menuView); } } else if (inventoryHolder instanceof StackedBlocksDepositMenu) { ((StackedBlocksDepositMenu) inventoryHolder).onInteract(e.getArgs().bukkitEvent); } } private void onMenuClose(GameEvent e) { Inventory topInventory = e.getArgs().bukkitEvent.getView().getTopInventory(); InventoryHolder inventoryHolder = topInventory == null ? null : topInventory.getHolder(); if (inventoryHolder instanceof MenuView) { MenuView menuView = (MenuView) inventoryHolder; menuView.getMenu().onClose(e.getArgs().bukkitEvent, menuView); } else if (inventoryHolder instanceof StackedBlocksDepositMenu) { ((StackedBlocksDepositMenu) inventoryHolder).onClose(e.getArgs().bukkitEvent); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.HitActionResult; import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.service.region.MoveResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.SIslandChest; import com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore; import com.bgsoftware.superiorskyblock.player.respawn.RespawnActions; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.List; import java.util.Locale; public class PlayersListener extends AbstractGameEventListener { private final LazyReference regionManagerService = new LazyReference() { @Override protected RegionManagerService create() { return plugin.getServices().getService(RegionManagerService.class); } }; public PlayersListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerListeners(); } /* PLAYER NOTIFIERS */ private void onPlayerLogin(GameEvent e) { Player player = e.getArgs().player; List duplicatedPlayers = plugin.getPlayers().matchAllPlayers(superiorPlayer -> superiorPlayer.getName().equalsIgnoreCase(player.getName()) && !superiorPlayer.getUniqueId().equals(player.getUniqueId())); if (!duplicatedPlayers.isEmpty()) { Log.info("Changing UUID of " + player.getName() + " to " + player.getUniqueId()); SuperiorPlayer playerWithNewUUID = plugin.getPlayers().getSuperiorPlayer(player.getUniqueId(), false); if (playerWithNewUUID != null) { // Even tho we have duplicates, there's already a record for the new player. // Therefore, we just want to delete the old records from DB and cache. Log.info("Detected a record for the new player uuid already - deleting old ones..."); // Delete all records duplicatedPlayers.forEach(duplicatedPlayer -> { plugin.getPlayers().replacePlayers(duplicatedPlayer, null); plugin.getPlayers().getPlayersContainer().removePlayer(duplicatedPlayer); }); // We make sure the new player is correctly set in all caches by removing it and adding it. plugin.getPlayers().getPlayersContainer().removePlayer(playerWithNewUUID); plugin.getPlayers().getPlayersContainer().addPlayer(playerWithNewUUID); } else { // We first want to remove all original players. duplicatedPlayers.forEach(plugin.getPlayers().getPlayersContainer()::removePlayer); // We now want to create the new player. SuperiorPlayer newPlayer = plugin.getPlayers().getSuperiorPlayer(player.getUniqueId(), true, false); // We now want to replace all existing players duplicatedPlayers.forEach(originalPlayer -> { if (originalPlayer != newPlayer) plugin.getPlayers().replacePlayers(originalPlayer, newPlayer); }); } } } private void onPlayerJoin(GameEvent e) { Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) superiorPlayer).release(); return; } // Updating the name of the player. if (!superiorPlayer.getName().equals(player.getName())) { PluginEventsFactory.callPlayerChangeNameEvent(superiorPlayer, player.getName()); superiorPlayer.updateName(); } // Handling player join if (superiorPlayer.isShownAsOnline()) IslandNotifications.notifyPlayerJoin(superiorPlayer); // Refresh PermissionsStore PlayerPermissionsStore permissionsStore = PlayerPermissionsStore.getPermissionsStore(player.getUniqueId()); if (permissionsStore != null) permissionsStore.refreshCache(player); MoveResult moveResult; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location playerLocation = player.getLocation(wrapper.getHandle()); island = plugin.getGrid().getIslandAt(playerLocation); moveResult = this.regionManagerService.get().handlePlayerJoin(superiorPlayer, playerLocation); } boolean teleportToSpawn = moveResult != MoveResult.SUCCESS; BukkitExecutor.sync(() -> { if (!player.isOnline()) return; // Updating skin of the player if (!plugin.getProviders().notifySkinsListeners(superiorPlayer)) plugin.getNMSPlayers().setSkinTexture(superiorPlayer); if (!superiorPlayer.hasBypassModeEnabled()) { Island delayedIsland; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { delayedIsland = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } // Checking if the player is in the islands world, not inside an island. if ((delayedIsland == island && teleportToSpawn) || (plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld()) && delayedIsland == null)) { superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); if (!teleportToSpawn) Message.ISLAND_GOT_DELETED_WHILE_INSIDE.send(superiorPlayer); } } // Checking auto language detection if (plugin.getSettings().isAutoLanguageDetection() && !player.hasPlayedBefore()) { Locale playerLocale = plugin.getNMSPlayers().getPlayerLocale(player); if (playerLocale != null && PlayerLocales.isValidLocale(playerLocale) && !superiorPlayer.getUserLocale().equals(playerLocale)) { if (PluginEventsFactory.callPlayerChangeLanguageEvent(superiorPlayer, playerLocale)) superiorPlayer.setUserLocale(playerLocale); } } }, 5L); } private void onPlayerQuit(GameEvent e) { Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) superiorPlayer).release(); return; } // Removing coop status from other islands. for (Island coopIsland : superiorPlayer.getCoopIslands()) { if (PluginEventsFactory.callIslandUncoopPlayerEvent(coopIsland, null, superiorPlayer, IslandUncoopPlayerEvent.UncoopReason.SERVER_LEAVE)) { coopIsland.removeCoop(superiorPlayer); IslandUtils.sendMessage(coopIsland, Message.UNCOOP_LEFT_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); } } // Handling player quit if (superiorPlayer.isShownAsOnline()) IslandNotifications.notifyPlayerQuit(superiorPlayer); // Remove coop players Island island = superiorPlayer.getIsland(); if (island != null && plugin.getSettings().isAutoUncoopWhenAlone() && !island.getCoopPlayers().isEmpty()) { boolean shouldRemoveCoops = island.getIslandMembers(true).stream().noneMatch(islandMember -> islandMember != superiorPlayer && island.hasPermission(islandMember, IslandPrivileges.UNCOOP_MEMBER) && islandMember.isOnline()); if (shouldRemoveCoops) { for (SuperiorPlayer coopPlayer : island.getCoopPlayers()) { island.removeCoop(coopPlayer); Message.UNCOOP_AUTO_ANNOUNCEMENT.send(coopPlayer); } } } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.regionManagerService.get().handlePlayerQuit(superiorPlayer, player.getLocation(wrapper.getHandle())); } // Remove all player chat-listeners PlayerChat.remove(player); } private void onPlayerGameModeChange(GameEvent e) { Player player = e.getArgs().player; if (e.getArgs().newGamemode == GameMode.SPECTATOR) { IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(player)); } else if (player.getGameMode() == GameMode.SPECTATOR) { IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(player)); } } /* PLAYER MOVES */ private void onPlayerMove(GameEvent e) { if (!(e.getArgs().entity instanceof Player)) return; Player player = (Player) e.getArgs().entity; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) superiorPlayer).release(); return; } if (superiorPlayer.hasPlayerStatus(PlayerStatus.VOID_TELEPORT)) return; MoveResult moveResult = this.regionManagerService.get().handlePlayerMove( superiorPlayer, e.getArgs().from, e.getArgs().to); switch (moveResult) { case VOID_TELEPORT: case SUCCESS: break; case LEAVE_ISLAND_TO_OUTSIDE: // Only cancel the event if player is not inside vehicle. If the player is inside the vehicle, // IslandOutsideListener will detect it and teleport him away. if (!player.isInsideVehicle()) e.setCancelled(); break; default: e.setCancelled(); break; } } private void onPlayerTeleport(GameEvent e) { if (e.getArgs().to == null || !(e.getArgs().entity instanceof Player)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity); if (superiorPlayer == null) return; if (superiorPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) superiorPlayer).release(); return; } MoveResult moveResult = this.regionManagerService.get().handlePlayerTeleport( superiorPlayer, e.getArgs().from, e.getArgs().to); if (moveResult != MoveResult.SUCCESS) e.setCancelled(); } private void onPlayerChangeWorld(GameEvent e) { Player player = e.getArgs().player; // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(player.getWorld())) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (island != null && superiorPlayer.hasIslandFlyEnabled() && !player.getAllowFlight() && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { BukkitExecutor.sync(() -> { player.setAllowFlight(true); player.setFlying(true); }, 1L); } } /* PVP */ private void onPlayerDamage(GameEvent e) { if (!(e.getArgs().entity instanceof Player)) return; Player player = (Player) e.getArgs().entity; SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (targetPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) targetPlayer).release(); return; } SuperiorPlayer damagerPlayer = e.getArgs().damager == null ? null : BukkitEntities.getPlayerSource(e.getArgs().damager) .map(plugin.getPlayers()::getSuperiorPlayer).orElse(null); // Some plugins, such as Sentinel, may actually cause a NPC to attack. if (damagerPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) damagerPlayer).release(); return; } if (damagerPlayer == null) { // We do not care about spawn island when spawn protection is disabled or player damage is enabled in spawn, // and therefore only island worlds are relevant. if ((!plugin.getSettings().getSpawn().isProtected() || plugin.getSettings().getSpawn().isPlayersDamage()) && !plugin.getGrid().isIslandsWorld(player.getWorld())) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } if (island != null) { if (island.isSpawn() ? (plugin.getSettings().getSpawn().isProtected() && !plugin.getSettings().getSpawn().isPlayersDamage()) : ((!plugin.getSettings().isCoopDamage() && island.isCoop(targetPlayer)) || (!plugin.getSettings().isVisitorsDamage() && island.isVisitor(targetPlayer, true)))) e.setCancelled(); } return; } boolean cancelFlames = false; boolean cancelEvent = false; Message messageToSend = null; HitActionResult hitActionResult = damagerPlayer.canHit(targetPlayer); switch (hitActionResult) { case ISLAND_TEAM_PVP: messageToSend = Message.HIT_ISLAND_MEMBER; break; case ISLAND_PVP_DISABLE: case TARGET_ISLAND_PVP_DISABLE: messageToSend = Message.HIT_PLAYER_IN_ISLAND; break; } if (hitActionResult != HitActionResult.SUCCESS) { cancelFlames = true; cancelEvent = true; } if (cancelEvent) e.setCancelled(); if (messageToSend != null) messageToSend.send(damagerPlayer); Player target = targetPlayer.asPlayer(); if (target != null && cancelFlames && e.getArgs().damager instanceof Arrow && target.getFireTicks() > 0) target.setFireTicks(0); } /* CHAT */ private void onPlayerChatLowest(GameEvent e) { PlayerChat playerChat = PlayerChat.getChatListener(e.getArgs().player); if (playerChat != null && playerChat.supply(e.getArgs().message)) e.setCancelled(); } private void onPlayerChat(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); Island island = superiorPlayer.getIsland(); if (superiorPlayer.hasTeamChatEnabled()) { if (island == null) { if (!PluginEventsFactory.callPlayerToggleTeamChatEvent(superiorPlayer)) return; superiorPlayer.toggleTeamChat(); return; } e.setCancelled(); String message = e.getArgs().message; IslandUtils.handleIslandChat(island, superiorPlayer, message); } else if (e.getArgs().format != null) { e.getArgs().format = Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(e.getArgs().format, superiorPlayer, island)); } } /* SCHEMATICS */ private void onSchematicSelection(GameEvent e) { Action action = e.getArgs().action; if (action != Action.RIGHT_CLICK_BLOCK && action != Action.LEFT_CLICK_BLOCK) return; Player player = e.getArgs().player; ItemStack usedItem = e.getArgs().usedItem; if (usedItem == null || usedItem.getType() != Materials.GOLDEN_AXE.toBukkitType()) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (!superiorPlayer.hasSchematicModeEnabled()) return; e.setCancelled(); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Block clickedBlock = e.getArgs().clickedBlock; Location location = clickedBlock.getLocation(wrapper.getHandle()); if (action == Action.RIGHT_CLICK_BLOCK) { Message.SCHEMATIC_RIGHT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(location)); superiorPlayer.setSchematicPos1(clickedBlock); } else { Message.SCHEMATIC_LEFT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(location)); superiorPlayer.setSchematicPos2(clickedBlock); } } if (superiorPlayer.getSchematicPos1() != null && superiorPlayer.getSchematicPos2() != null) Message.SCHEMATIC_READY_TO_CREATE.send(superiorPlayer); } /* ISLAND CHESTS */ private void onIslandChestInteract(GameEvent e) { InventoryView inventoryView = e.getArgs().bukkitEvent.getView(); InventoryHolder inventoryHolder = inventoryView.getTopInventory() == null ? null : inventoryView.getTopInventory().getHolder(); if (!(inventoryHolder instanceof IslandChest)) return; SIslandChest islandChest = (SIslandChest) inventoryHolder; if (islandChest.isUpdating()) { e.setCancelled(); } else { islandChest.updateContents(); } } /* VOID TELEPORT */ private void onPlayerFall(GameEvent e) { if (e.getArgs().damageCause != EntityDamageEvent.DamageCause.FALL || !(e.getArgs().entity instanceof Player)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity); if (superiorPlayer.hasPlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED)) { e.setCancelled(); } } /* PLAYER DEATH */ private void onPlayerRespawn(GameEvent e) { PlayerRespawnEvent bukkitRespawnEvent = e.getArgs().bukkitEvent; for (RespawnAction respawnAction : plugin.getSettings().getPlayerRespawn()) { if (respawnAction == RespawnActions.VANILLA || respawnAction.canPerform(bukkitRespawnEvent)) { respawnAction.perform(bukkitRespawnEvent); return; } } } private void onPlayerRespawnMonitor(GameEvent e) { Location respawnLocation = e.getArgs().bukkitEvent.getRespawnLocation(); Player player = e.getArgs().player; BukkitExecutor.sync(() -> { if (!player.isOnline()) return; Island respawnAtIsland = plugin.getGrid().getIslandAt(respawnLocation); if (respawnAtIsland != null) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); superiorPlayer.updateWorldBorder(respawnAtIsland); } }, 2L); } /* INTERNAL */ private void registerListeners() { registerCallback(GameEventType.PLAYER_LOGIN_EVENT, GameEventPriority.MONITOR, this::onPlayerLogin); registerCallback(GameEventType.PLAYER_JOIN_EVENT, GameEventPriority.MONITOR, this::onPlayerJoin); registerCallback(GameEventType.PLAYER_QUIT_EVENT, GameEventPriority.MONITOR, this::onPlayerQuit); registerCallback(GameEventType.PLAYER_GAMEMODE_CHANGE, GameEventPriority.MONITOR, this::onPlayerGameModeChange); registerCallback(GameEventType.ENTITY_MOVE_EVENT, GameEventPriority.NORMAL, this::onPlayerMove); registerCallback(GameEventType.ENTITY_TELEPORT_EVENT, GameEventPriority.HIGHEST, this::onPlayerTeleport); registerCallback(GameEventType.PLAYER_CHANGED_WORLD_EVENT, GameEventPriority.MONITOR, this::onPlayerChangeWorld); /* Set to NORMAL, so it doesn't conflict with vanish plugins */ registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onPlayerDamage); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, false, this::onSchematicSelection); registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.LOWEST, this::onIslandChestInteract); registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onPlayerFall); registerCallback(GameEventType.PLAYER_RESPAWN_EVENT, GameEventPriority.NORMAL, this::onPlayerRespawn); registerCallback(GameEventType.PLAYER_RESPAWN_EVENT, GameEventPriority.MONITOR, this::onPlayerRespawnMonitor); // PlayerChat should be on LOWEST priority so other chat plugins don't conflict. registerCallback(GameEventType.PLAYER_CHAT_EVENT, GameEventPriority.LOWEST, this::onPlayerChatLowest); registerCallback(GameEventType.PLAYER_CHAT_EVENT, GameEventPriority.NORMAL, this::onPlayerChat); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.service.portals.EntityPortalResult; import com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerTeleportEvent; public class PortalsListener extends AbstractGameEventListener { private final LazyReference portalsManager = new LazyReference() { @Override protected PortalsManagerService create() { return plugin.getServices().getService(PortalsManagerService.class); } }; public PortalsListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerListeners(); } private void registerListeners() { registerCallback(GameEventType.ENTITY_PORTAL_EVENT, GameEventPriority.HIGHEST, this::onEntityPortal); registerCallback(GameEventType.ENTITY_ENTER_PORTAL_EVENT, GameEventPriority.HIGHEST, this::onEntityEnterPortal); } private void onEntityPortal(GameEvent e) { if (e.getArgs().entity instanceof Player) handlePlayerPortal(e); else handleEntityPortalResult(e); } private void onEntityEnterPortal(GameEvent e) { // Simulate portals in the following cases: // - Using an end portal in the end // - The target world is disabled Entity entity = e.getArgs().entity; Location portalLocation = e.getArgs().portalLocation; World world = portalLocation.getWorld(); Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); } if (island == null) { if (plugin.getGrid().isIslandsWorld(world)) e.setCancelled(); return; } // Simulate end portal if (world.getEnvironment() == World.Environment.THE_END) { /* We teleport the player to his island instead of cancelling the event. Therefore, we must prevent the player from acting like he entered another island or left his island.*/ SuperiorPlayer teleportedPlayer = entity instanceof Player ? plugin.getPlayers().getSuperiorPlayer((Player) entity) : null; if (teleportedPlayer != null) teleportedPlayer.setPlayerStatus(PlayerStatus.LEAVING_ISLAND); BukkitExecutor.sync(() -> { Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(error -> { if (teleportedPlayer != null) teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); }).ifLeft(unused -> { EntityTeleports.teleportUntilSuccess(entity, island.getIslandHome(dimension), 5, () -> { if (teleportedPlayer != null) teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); }); }); }); }, 5L); } if (ServerVersion.isLessThan(ServerVersion.v1_16)) return; boolean isPlayer = entity instanceof Player; Material originalMaterial = portalLocation.getBlock().getType(); PortalType portalType = originalMaterial == Materials.NETHER_PORTAL.toBukkitType() ? PortalType.NETHER : PortalType.ENDER; if (isPlayer && (portalType == PortalType.NETHER ? Bukkit.getAllowNether() : Bukkit.getAllowEnd())) return; if (portalType == PortalType.NETHER) { int ticksDelay = !isPlayer ? 0 : ((Player) entity).getGameMode() == GameMode.CREATIVE ? 1 : 80; int portalTicks = plugin.getNMSEntities().getPortalTicks(entity); if (portalTicks != ticksDelay) return; } if (isPlayer) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(entity); this.portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, portalLocation, portalType, true); } else { this.portalsManager.get().handleEntityPortalFromIsland(entity, island, portalLocation, portalType); } } private void handlePlayerPortal(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity); if (superiorPlayer instanceof SuperiorNPCPlayer) { ((SuperiorNPCPlayer) superiorPlayer).release(); return; } Island island = plugin.getGrid().getIslandAt(e.getArgs().from); if (island == null) { if (plugin.getGrid().isIslandsWorld(e.getArgs().from.getWorld())) e.setCancelled(); return; } PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; Either destinationResult = calculateDestination(island, superiorPlayer, e.getArgs().from, portalType); EntityPortalResult portalResult; if (destinationResult.getLeft() != null) { portalResult = this.portalsManager.get().handlePlayerPortalFromIsland( superiorPlayer, island, e.getArgs().from, portalType, destinationResult.getLeft(), true); } else { portalResult = destinationResult.getRight(); } handleEntityPortalResult(portalResult, e); } public void handleEntityPortalResult(GameEvent e) { Location from = e.getArgs().from; Location to = e.getArgs().to; if (to == null || to.getWorld() == null || from == null || from.getWorld() == null) return; Island island = plugin.getGrid().getIslandAt(e.getArgs().from); if (island == null) return; Entity entity = e.getArgs().entity; PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; Either destinationResult = calculateDestination(island, null, e.getArgs().from, portalType); EntityPortalResult portalResult; if (destinationResult.getLeft() != null) { portalResult = this.portalsManager.get().handleEntityPortalFromIsland( entity, island, from, portalType, destinationResult.getLeft()); } else { portalResult = destinationResult.getRight(); } handleEntityPortalResult(portalResult, e); } @Nullable private Either calculateDestination(Island island, @Nullable SuperiorPlayer superiorPlayer, Location fromLocation, PortalType portalType) { if (island.isSpawn()) return Either.right(EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD); Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(fromLocation.getWorld()); if (portalDimension == null) return Either.right(EntityPortalResult.PORTAL_NOT_IN_ISLAND); SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDimension); Dimension portalDestination = dimensionConfig == null ? null : dimensionConfig.getPortalDestination(portalType); if (portalDestination == null) return Either.right(EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD); SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDestination); if (destinationConfig.isEnabled()) { // Check if the world actually exists WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, portalDestination); if (worldInfo != null) return Either.left(island.getCenter(portalDestination)); } if (superiorPlayer != null) Message.WORLD_NOT_ENABLED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(portalDestination.getName())); return Either.right(EntityPortalResult.DESTINATION_WORLD_DISABLED); } private void handleEntityPortalResult(EntityPortalResult portalResult, GameEvent event) { switch (portalResult) { case PORTAL_NOT_IN_ISLAND: return; case DESTINATION_WORLD_DISABLED: case PLAYER_IMMUNED_TO_PORTAL: case SCHEMATIC_GENERATING_COOLDOWN: case DESTINATION_NOT_ISLAND_WORLD: case PORTAL_EVENT_CANCELLED: case INVALID_SCHEMATIC: case WORLD_NOT_UNLOCKED: case DESTINATION_ISLAND_NOT_PERMITTED: case SUCCEED: event.setCancelled(); return; default: throw new IllegalStateException("No handling for result: " + portalResult); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.entity.Animals; import org.bukkit.entity.Egg; import org.bukkit.entity.EnderPearl; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.FishHook; import org.bukkit.entity.Hanging; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.entity.Vehicle; import org.bukkit.event.block.Action; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; import org.bukkit.util.Vector; import java.util.Iterator; import java.util.List; public class ProtectionListener extends AbstractGameEventListener { @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable private static final Material CHORUS_FRUIT = EnumHelper.getEnum(Material.class, "CHORUS_FRUIT"); @Nullable private static final Material BRUSH = EnumHelper.getEnum(Material.class, "BRUSH"); @Nullable private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "WIND_CHARGE"); @Nullable private static final Material POINTED_DRIPSTONE = EnumHelper.getEnum(Material.class, "POINTED_DRIPSTONE"); @Nullable private static final EntityType TRIDENT = EnumHelper.getEnum(EntityType.class, "TRIDENT"); @Nullable private static final Material DECORATED_POT = EnumHelper.getEnum(Material.class, "DECORATED_POT"); @Nullable private static final Material TARGET = EnumHelper.getEnum(Material.class, "TARGET"); private final LazyReference protectionManager = new LazyReference() { @Override protected RegionManagerService create() { return plugin.getServices().getService(RegionManagerService.class); } }; public ProtectionListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerListeners(); } /* BLOCK INTERACTS */ private void onBlockPlace(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().block); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onPlayerInteract(GameEvent e) { if (handleBlockFertilize(e)) return; if (handleBedPlace(e)) return; if (handleSignColorChange(e)) return; if (handleBrushUse(e)) return; if (handleMinecartPlace(e)) return; if (handleEntityInteract(e)) return; handleBlockInteract(e, e.getArgs().player, e.getArgs().action, e.getArgs().clickedBlock, e.getArgs().usedHand, e.getArgs().usedItem); } private void onEntityInteractBlock(GameEvent e) { Block clickedBlock = e.getArgs().block; if (clickedBlock == null) return; Entity entity = e.getArgs().entity; if (!(entity instanceof Projectile)) return; ProjectileSource projectileSource = ((Projectile) entity).getShooter(); if (!(projectileSource instanceof Player)) return; if (handleBlockInteract(e, (Player) projectileSource, Action.PHYSICAL, clickedBlock, null, null)) { // We want to remove the projectile as well when it is not possible to interact entity.remove(); } } private boolean handleBlockFertilize(GameEvent e) { Action action = e.getArgs().action; ItemStack usedItem = e.getArgs().usedItem; if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || !Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem)) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleBlockFertilize(superiorPlayer, e.getArgs().clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); return true; } return false; } // Patching a dupe glitch with crops and beds: https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1672 private boolean handleBedPlace(GameEvent e) { Action action = e.getArgs().action; ItemStack usedItem = e.getArgs().usedItem; if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || !Materials.isBed(usedItem.getType())) return false; // The player right-clicked a block with a bed in his hand SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); return true; } return false; } private boolean handleSignColorChange(GameEvent e) { Action action = e.getArgs().action; ItemStack usedItem = e.getArgs().usedItem; if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || ServerVersion.isLegacy() || !Materials.isDye(usedItem.getType())) return false; Block clickedBlock = e.getArgs().clickedBlock; BlockState blockState = clickedBlock.getState(); if (!(blockState instanceof Sign)) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); return true; } return false; } private boolean handleBrushUse(GameEvent e) { Action action = e.getArgs().action; ItemStack usedItem = e.getArgs().usedItem; if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || usedItem.getType() != BRUSH) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { interactionResult = this.protectionManager.get().handleCustomInteraction( superiorPlayer, e.getArgs().clickedBlock.getLocation(wrapper.getHandle()), IslandPrivileges.BRUSH); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); return true; } return false; } private boolean handleMinecartPlace(GameEvent e) { Action action = e.getArgs().action; ItemStack usedItem = e.getArgs().usedItem; if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null) return false; Material handItemType = usedItem.getType(); Material clickedBlockType = e.getArgs().clickedBlock.getType(); EntityType spawnType = Materials.isMinecart(handItemType) && Materials.isRail(clickedBlockType) ? EntityType.MINECART : Materials.isBoat(handItemType) ? EntityType.BOAT : null; if (spawnType == null) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(spawnType)); if (entityCategories.isEmpty()) return false; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location clickedBlockLocation = e.getArgs().clickedBlock.getLocation(wrapper.getHandle()); for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getSpawnPrivilege() != null) { InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction( superiorPlayer, clickedBlockLocation, entityCategory.getSpawnPrivilege()); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); return true; } } } } return false; } private boolean handleEntityInteract(GameEvent e) { if (e.getArgs().clickedEntity == null) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer, e.getArgs().clickedEntity, e.getArgs().usedItem); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); return true; } return false; } private boolean handleBlockInteract(GameEvent e, Player player, Action action, @Nullable Block clickedBlock, @Nullable PlayerHand usedHand, @Nullable ItemStack usedItem) { if (clickedBlock == null) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.protectionManager.get().handleBlockInteract( superiorPlayer, clickedBlock, action, usedItem); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, usedItem != null || usedHand != PlayerHand.OFF_HAND)) { e.setCancelled(); return true; } return false; } private void onBlockBreak(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleBlockBreak(superiorPlayer, e.getArgs().block); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onFrostWalker(GameEvent e) { Entity entity = e.getArgs().entity; if (!(entity instanceof Player)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().block); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, false)) e.setCancelled(); } private void onBucketEmpty(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onBucketFill(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onBucketDispense(GameEvent e) { Material itemType = e.getArgs().dispensedItem.getType(); if (!(itemType == Material.BUCKET || itemType == Material.WATER_BUCKET || itemType == Material.LAVA_BUCKET)) return; Vector velocity = e.getArgs().velocity; Location dispenseBlockLocation = new Location(e.getArgs().block.getWorld(), velocity.getBlockX(), velocity.getBlockY(), velocity.getBlockZ()); Island island = plugin.getGrid().getIslandAt(dispenseBlockLocation); if (island != null && !island.isInsideRange(dispenseBlockLocation)) e.setCancelled(); } private void onChorusFruitConsume(GameEvent e) { if (CHORUS_FRUIT == null || e.getArgs().consumedItem.getType() != CHORUS_FRUIT) return; Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { interactionResult = this.protectionManager.get().handlePlayerConsumeChorusFruit( superiorPlayer, player.getLocation(wrapper.getHandle())); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } /* ENTITY INTERACTS */ private void onEntityAttack(GameEvent e) { Entity entity = e.getArgs().entity; Entity damager = e.getArgs().damager; if (damager == null || entity instanceof Player) return; SuperiorPlayer damagerSource = BukkitEntities.getPlayerSource(damager) .map(plugin.getPlayers()::getSuperiorPlayer).orElse(null); InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(damager, entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, damagerSource, true)) e.setCancelled(); } private void onEntityShearing(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleEntityShear(superiorPlayer, e.getArgs().entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onHangingBreak(GameEvent e) { BukkitEntities.getPlayerSource(e.getArgs().remover).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(removerPlayer -> { InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(removerPlayer, e.getArgs().entity, null); if (ProtectionHelper.shouldPreventInteraction(interactionResult, removerPlayer, true)) e.setCancelled(); }); } private void onHangingPlace(GameEvent e) { if (!(e.getArgs().entity instanceof Hanging)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer, e.getArgs().entity, null); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onEntityTarget(GameEvent e) { Entity entity = e.getArgs().entity; Entity target = e.getArgs().target; if (!(target instanceof Player)) return; InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(target, entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) e.setCancelled(); } private void onVillagerTrade(GameEvent e) { Inventory openInventory = e.getArgs().bukkitEvent.getView().getTopInventory(); if (openInventory == null || openInventory.getType() != InventoryType.MERCHANT) return; HumanEntity humanEntity = e.getArgs().bukkitEvent.getWhoClicked(); SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(humanEntity); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = humanEntity.getLocation(wrapper.getHandle()); interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, location, IslandPrivileges.VILLAGER_TRADING); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) { e.setCancelled(); humanEntity.closeInventory(); } } private void onPlayerLeash(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleEntityLeash(superiorPlayer, e.getArgs().entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onPlayerUnleash(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleEntityLeash(superiorPlayer, e.getArgs().entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } /* VEHICLE INTERACTS */ private void onVehicleEnter(GameEvent e) { Entity rider = e.getArgs().entity; if (!(rider instanceof Player)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) rider); InteractionResult interactionResult = this.protectionManager.get().handleEntityRide(superiorPlayer, e.getArgs().vehicle); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onVehicleOpen(GameEvent e) { InventoryHolder inventoryHolder = e.getArgs().bukkitEvent.getInventory().getHolder(); if (!(inventoryHolder instanceof Vehicle)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().bukkitEvent.getPlayer()); List entityCategories = BukkitEntities.getCategories((Entity) inventoryHolder); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location minecartLocation = ((Vehicle) inventoryHolder).getLocation(wrapper.getHandle()); if (!entityCategories.isEmpty()) { InteractionResult interactionResult; for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getInteractPrivilege() != null) { interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, minecartLocation, entityCategory.getInteractPrivilege()); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); return; } } } } IslandPrivilege islandPrivilege = inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN; InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, minecartLocation, islandPrivilege); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); } } } private void onPlayerCollideWithEntity(GameEvent e) { Entity entity = e.getArgs().entity; if (!(entity instanceof Player)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location vehicleLocation = e.getArgs().target.getLocation(wrapper.getHandle()); interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, vehicleLocation, IslandPrivileges.MINECART_ENTER); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, false)) e.setCancelled(); } /* ITEMS */ private void onPlayerDropItem(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handlePlayerDropItem(superiorPlayer, e.getArgs().droppedItem); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onPlayerPickupItem(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getArgs().pickedUpItem); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } private void onPlayerPickupArrow(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getArgs().pickedUpItem); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } /* PROJECTILE INTERACTS */ private void onPlayerLaunchProjectile(GameEvent e) { Entity entity = e.getArgs().entity; BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(launcherPlayer -> { EntityType entityType = entity.getType(); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); if (entity instanceof Egg) { List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity)); for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getSpawnPrivilege() != null) { interactionResult = this.protectionManager.get().handleCustomInteraction(launcherPlayer, entityLocation, entityCategory.getSpawnPrivilege()); if (ProtectionHelper.shouldPreventInteraction(interactionResult, launcherPlayer, true)) { e.setCancelled(); return; } } } } IslandPrivilege islandPrivilege; if (entity instanceof FishHook && !ServerVersion.isLegacy()) { islandPrivilege = IslandPrivileges.FISH; } else if (entityType == TRIDENT) { islandPrivilege = IslandPrivileges.PICKUP_DROPS; } else if (entity instanceof EnderPearl) { islandPrivilege = IslandPrivileges.ENDER_PEARL; } else if (entityType == WIND_CHARGE) { islandPrivilege = IslandPrivileges.WIND_CHARGE; } else { return; } interactionResult = this.protectionManager.get().handleCustomInteraction(launcherPlayer, entityLocation, islandPrivilege); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, launcherPlayer, true)) e.setCancelled(); }); } private void onProjectileHit(GameEvent e) { Entity entity = e.getArgs().entity; BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> { Location location; IslandPrivilege islandPrivilege; Block hitBlock; InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (entity instanceof FishHook) { Entity hitEntity = e.getArgs().hitEntity; if (hitEntity == null) return; hitBlock = null; location = hitEntity.getLocation(wrapper.getHandle()); List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity)); interactionResult = InteractionResult.SUCCESS; for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getDamagePrivilege() != null) { interactionResult = this.protectionManager.get().handleCustomInteraction( shooterPlayer, location, entityCategory.getDamagePrivilege()); if (interactionResult != InteractionResult.SUCCESS) break; } } } else { hitBlock = e.getArgs().hitBlock; Material hitBlockType = hitBlock == null ? null : hitBlock.getType(); if (hitBlockType != CHORUS_FLOWER && hitBlockType != DECORATED_POT && hitBlockType != TARGET) return; IslandPrivilege requiredPrivilege = plugin.getSettings().getInteractablesMap() .getRequiredPrivilege(ConstantKeys.TARGET); location = hitBlock.getLocation(wrapper.getHandle()); islandPrivilege = hitBlockType == TARGET ? requiredPrivilege : IslandPrivileges.BREAK; if (islandPrivilege == null) return; interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, location, islandPrivilege); } } if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true)) { entity.remove(); if (hitBlock != null) { ICachedBlock cachedBlock = plugin.getNMSWorld().cacheBlock(hitBlock); hitBlock.setType(Material.AIR); BukkitExecutor.sync(() -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { cachedBlock.setBlock(hitBlock.getLocation(wrapper.getHandle())); } cachedBlock.release(); }, 1L); } } }); } private void onSoftExplodeEvent(GameEvent e) { if (!e.getArgs().isSoftExplosion) return; Entity entity = e.getArgs().entity; BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> { Iterator blocksIterator = e.getArgs().blocks.iterator(); while (blocksIterator.hasNext()) { Block block = blocksIterator.next(); Material blockType = block.getType(); IslandPrivilege islandPrivilege = blockType == CHORUS_FLOWER || blockType == POINTED_DRIPSTONE ? IslandPrivileges.BREAK : plugin.getSettings().getInteractablesMap().getRequiredPrivilege(Keys.of(block)); if (islandPrivilege == null) continue; InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, block.getLocation(wrapper.getHandle()), islandPrivilege); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true)) blocksIterator.remove(); } }); } /* WORLD EVENTS */ private void onRaidTrigger(GameEvent e) { if (!plugin.getGrid().isIslandsWorld(e.getArgs().world)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); Location raidLocation = e.getArgs().raidLocation; Island island = plugin.getGrid().getIslandAt(raidLocation); if (island == null || island.isSpawn() || !island.isInside(raidLocation) || !island.isMember(superiorPlayer)) e.setCancelled(); } /* INTERNAL */ private void registerListeners() { registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.NORMAL, this::onBlockPlace); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, this::onPlayerInteract); registerCallback(GameEventType.ENTITY_INTERACT_EVENT, GameEventPriority.NORMAL, this::onEntityInteractBlock); registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.NORMAL, this::onBlockBreak); registerCallback(GameEventType.ENTITY_BLOCK_FORM_EVENT, GameEventPriority.NORMAL, this::onFrostWalker); registerCallback(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, GameEventPriority.NORMAL, this::onBucketEmpty); registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.NORMAL, this::onBucketFill); registerCallback(GameEventType.BLOCK_DISPENSE_EVENT, GameEventPriority.NORMAL, this::onBucketDispense); registerCallback(GameEventType.PLAYER_ITEM_CONSUME_EVENT, GameEventPriority.NORMAL, this::onChorusFruitConsume); registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onEntityAttack); registerCallback(GameEventType.PLAYER_SHEAR_ENTITY_EVENT, GameEventPriority.NORMAL, this::onEntityShearing); registerCallback(GameEventType.HANGING_BREAK_EVENT, GameEventPriority.NORMAL, this::onHangingBreak); registerCallback(GameEventType.HANGING_PLACE_EVENT, GameEventPriority.NORMAL, this::onHangingPlace); registerCallback(GameEventType.ENTITY_TARGET_EVENT, GameEventPriority.NORMAL, this::onEntityTarget); registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.NORMAL, false, this::onVillagerTrade); registerCallback(GameEventType.PLAYER_LEASH_ENTITY_EVENT, GameEventPriority.NORMAL, this::onPlayerLeash); registerCallback(GameEventType.PLAYER_UNLEASH_ENTITY_EVENT, GameEventPriority.NORMAL, this::onPlayerUnleash); registerCallback(GameEventType.ENTITY_RIDE_EVENT, GameEventPriority.NORMAL, this::onVehicleEnter); registerCallback(GameEventType.INVENTORY_OPEN_EVENT, GameEventPriority.NORMAL, this::onVehicleOpen); registerCallback(GameEventType.ENTITY_COLLISION_EVENT, GameEventPriority.NORMAL, this::onPlayerCollideWithEntity); registerCallback(GameEventType.PLAYER_DROP_ITEM_EVENT, GameEventPriority.NORMAL, this::onPlayerDropItem); registerCallback(GameEventType.PLAYER_PICKUP_ITEM_EVENT, GameEventPriority.NORMAL, this::onPlayerPickupItem); registerCallback(GameEventType.PROJECTILE_LAUNCH_EVENT, GameEventPriority.NORMAL, this::onPlayerLaunchProjectile); registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.NORMAL, this::onProjectileHit); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.NORMAL, this::onSoftExplodeEvent); registerCallback(GameEventType.PLAYER_PICKUP_ARROW_EVENT, GameEventPriority.NORMAL, this::onPlayerPickupArrow); registerCallback(GameEventType.RAID_TRIGGER_EVENT, GameEventPriority.NORMAL, this::onRaidTrigger); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.world.SignType; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.Directional; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Iterator; public class SignsListener extends AbstractGameEventListener { private static final BlockFace[] NEARBY_BLOCKS = new BlockFace[]{ BlockFace.UP, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.EAST }; public SignsListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerListeners(); } private void onSignPlace(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Player player = e.getArgs().player; String[] lines = e.getArgs().lines; String[] signLines; IslandSigns.Result result; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location warpLocation = block.getLocation(wrapper.getHandle()); SignType signType = plugin.getNMSWorld().getSignType(block); // Hanging signs are not allowed if (signType == SignType.HANGING_SIGN || signType == SignType.HANGING_WALL_SIGN) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); signLines = lines.clone(); result = IslandSigns.handleSignPlace(superiorPlayer, warpLocation, signLines, true); } switch (result.getReason()) { case NOT_IN_ISLAND: return; case SUCCESS: break; default: Arrays.fill(signLines, ""); break; } // Only update the lines if changed if (Arrays.equals(signLines, lines)) return; // We want to update the sign only one tick later, so other plugins don't interface with it // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1916 BukkitExecutor.sync(() -> { BlockState blockState = block.getState(); if (blockState instanceof Sign) { Sign sign = (Sign) blockState; for (int i = 0; i < signLines.length; ++i) sign.setLine(i, signLines[i]); sign.update(); } }, 1L); } private void onSignBreak(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(block.getLocation(wrapper.getHandle())); } if (!isValidIsland(island)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); IslandSigns.Result result = handleBlockBreak(island, block, superiorPlayer); if (result.isCancelEvent()) e.setCancelled(); } private void onSignExplode(GameEvent e) { if (e.getArgs().isSoftExplosion) return; Entity entity = e.getArgs().entity; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); } if (!isValidIsland(island)) return; Iterator iterator = e.getArgs().blocks.iterator(); while (iterator.hasNext()) { Block block = iterator.next(); IslandSigns.Result result = handleBlockBreak(island, block, null); if (result.isCancelEvent()) iterator.remove(); } } private IslandSigns.Result handleBlockBreak(Island island, Block block, @Nullable SuperiorPlayer superiorPlayer) { BlockState blockState = block.getState(); if (blockState instanceof Sign) { return IslandSigns.handleSignBreak(island, superiorPlayer, (Sign) blockState); } for (BlockFace blockFace : NEARBY_BLOCKS) { Block faceBlock = block.getRelative(blockFace); blockState = faceBlock.getState(); if (!(blockState instanceof Sign)) continue; boolean isSignGonnaBreak; if (ServerVersion.isLegacy()) { org.bukkit.material.Sign sign = (org.bukkit.material.Sign) blockState.getData(); isSignGonnaBreak = sign.getAttachedFace().getOppositeFace() == blockFace; } else { Object blockData = plugin.getNMSWorld().getBlockData(faceBlock); switch (plugin.getNMSWorld().getSignType(blockData)) { case WALL_SIGN: // Wall signs will only be broken if they are attached to the block isSignGonnaBreak = ((Directional) blockData).getFacing() == blockFace; break; case STANDING_SIGN: // Standing signs will only be broken if they are placed on top of the block isSignGonnaBreak = blockFace == BlockFace.UP; break; case HANGING_WALL_SIGN: case HANGING_SIGN: // Hanging signs are not allowed as warp signs isSignGonnaBreak = false; break; default: throw new RuntimeException("Found sign that cannot be handled: " + blockData); } } if (isSignGonnaBreak) { return IslandSigns.handleSignBreak(null, superiorPlayer, (Sign) blockState); } } return new IslandSigns.Result(IslandSigns.Reason.SUCCESS, false); } private void registerListeners() { registerCallback(GameEventType.SIGN_CHANGE_EVENT, GameEventPriority.MONITOR, this::onSignPlace); registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onSignBreak); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onSignExplode); } private static boolean isValidIsland(Island island) { return island != null && (!island.getIslandWarps().isEmpty() || island.getVisitorsPosition(null) != null); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksServiceHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.EnumMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; public class StackedBlocksListener extends AbstractGameEventListener { @Nullable private static final Material COPPER_BLOCK = EnumHelper.getEnum(Material.class, "COPPER_BLOCK"); private static final Material HONEYCOMB = EnumHelper.getEnum(Material.class, "HONEYCOMB"); @Nullable private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BUILD_COPPERGOLEM"); @Nullable private static final Material COPPER_CHEST = EnumHelper.getEnum(Material.class, "COPPER_CHEST"); private final Map> ENTITY_TEMPLATE_OFFSETS = buildEntityTemplateOffsetsMap(); private final LazyReference stackedBlocksInteractionService = new LazyReference() { @Override protected StackedBlocksInteractionService create() { return plugin.getServices().getService(StackedBlocksInteractionService.class); } }; public StackedBlocksListener(SuperiorSkyblockPlugin plugin) { super(plugin); this.registerListeners(); } private void onStackedBlockInteract(GameEvent e) { if (e.getArgs().action != Action.RIGHT_CLICK_BLOCK) return; if (handleStackedBlockPlace(e)) return; if (handleStackedBlockUnstack(e)) return; } /* STACK LISTENERS */ private void onStackedBlockPlace(GameEvent e) { Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Block againstBlock = e.getArgs().againstBlock; if (againstBlock.equals(block)) return; if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) plugin.getStackedBlocks().setStackedBlock(block, 1); Player player = e.getArgs().player; PlayerHand usedHand = e.getArgs().usedHand; ItemStack inHand = e.getArgs().usedItem; if (inHand == null) { Log.error("BlockPlaceEvent by player ", player.getName(), " of block ", block.getType().name(), " with null hand item: ", usedHand); throw new RuntimeException("BlockPlaceEvent with null hand item"); } // We do not stack blocks when the hand items has a name or a lore. if (inHand.hasItemMeta() && (inHand.getItemMeta().hasDisplayName() || inHand.getItemMeta().hasLore())) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.stackedBlocksInteractionService.get().handleStackedBlockPlace( superiorPlayer, againstBlock, usedHand.getEquipmentSlot()); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) e.setCancelled(); } private boolean handleStackedBlockPlace(GameEvent e) { if (!plugin.getSettings().getStackedBlocks().isEnabled()) return false; boolean cancelled = false; Player player = e.getArgs().player; Block clickedBlock = e.getArgs().clickedBlock; PlayerHand usedHand = e.getArgs().usedHand; ItemStack usedItem = e.getArgs().usedItem; Material clickedBlockType = clickedBlock.getType(); if (clickedBlockType == Material.DRAGON_EGG) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) > 1) { e.setCancelled(); if (usedItem == null) this.stackedBlocksInteractionService.get().handleStackedBlockBreak(clickedBlock, superiorPlayer); cancelled = true; } if (usedItem != null) { InteractionResult interactionResult = this.stackedBlocksInteractionService.get() .handleStackedBlockPlace(superiorPlayer, clickedBlock, usedHand.getEquipmentSlot()); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) { e.setCancelled(); cancelled = true; } } } else if (clickedBlockType == COPPER_BLOCK && usedItem != null && usedItem.getType() == HONEYCOMB && plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) > 1) { e.setCancelled(); cancelled = true; } return cancelled; } /* UNSTACK LISTENERS */ private void onStackedBlockBreak(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.stackedBlocksInteractionService.get() .handleStackedBlockBreak(e.getArgs().block, superiorPlayer); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) e.setCancelled(); } private boolean handleStackedBlockUnstack(GameEvent e) { if (e.getArgs().usedItem != null || e.getArgs().usedHand != PlayerHand.MAIN_HAND) return false; Block clickedBlock = e.getArgs().clickedBlock; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld())) return false; if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) <= 1) return false; Player player = e.getArgs().player; if (plugin.getSettings().getStackedBlocks().getDepositMenu().isEnabled() && player.isSneaking()) { StackedBlocksDepositMenu depositMenu = new StackedBlocksDepositMenu(clickedBlock.getLocation()); player.openInventory(depositMenu.getInventory()); } else { ItemStack offHandItem = BukkitItems.getHandItem(player, PlayerHand.OFF_HAND); if (offHandItem != null && offHandItem.getType() == clickedBlock.getType()) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.stackedBlocksInteractionService.get() .handleStackedBlockBreak(clickedBlock, superiorPlayer); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) { e.setCancelled(); return true; } } return false; } private void onStackedBlockBreakByEntity(GameEvent e) { InteractionResult interactionResult = this.stackedBlocksInteractionService.get() .handleStackedBlockBreak(e.getArgs().block, null); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) e.setCancelled(); } private void onStackedBlockExplode(GameEvent e) { if (e.getArgs().isSoftExplosion) return; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().entity.getWorld())) return; Iterator blockIterator = e.getArgs().blocks.iterator(); while (blockIterator.hasNext()) { Block block = blockIterator.next(); // Check if block is stackable if (!plugin.getSettings().getStackedBlocks().getWhitelisted().contains(Keys.of(block))) continue; int amount = plugin.getStackedBlocks().getStackedBlockAmount(block); if (amount <= 1) continue; // All checks are done. We can remove the block from the list. blockIterator.remove(); ItemStack blockItem = block.getState().getData().toItemStack(amount); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = block.getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(location); if (island != null) island.handleBlockBreak(block, amount); plugin.getStackedBlocks().removeStackedBlock(location); block.setType(Material.AIR); // Dropping the item block.getWorld().dropItemNaturally(location, blockItem); } } } /* STACKED-BLOCKS PROTECTION */ private void onPistonExtend(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) return; for (Block block : e.getArgs().blocks) { if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) { e.setCancelled(); break; } } } public void onPistonRetract(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) return; for (Block block : e.getArgs().blocks) { if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) { e.setCancelled(); break; } } } private void onBlockChangeState(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) return; if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) e.setCancelled(); } private void onGolemCreate(GameEvent e) { List entityTemplateOffsets = ENTITY_TEMPLATE_OFFSETS.get(e.getArgs().spawnReason); if (entityTemplateOffsets == null) return; Entity entity = e.getArgs().entity; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); if (plugin.getStackedBlocks().getStackedBlockAmount(entityLocation) > 1) { e.setCancelled(); return; } for (BlockOffset blockOffset : entityTemplateOffsets) { if (plugin.getStackedBlocks().getStackedBlockAmount(blockOffset.applyToLocation(entityLocation)) > 1) { e.setCancelled(); if (e.getArgs().spawnReason == BUILD_COPPERGOLEM) onCopperGolemCancel(entityLocation); return; } } } } private void onCopperGolemCancel(Location entityLocation) { Block copperChestBlock = entityLocation.getBlock().getRelative(BlockFace.DOWN); BukkitExecutor.sync(() -> { if (copperChestBlock.getType() == COPPER_CHEST) { copperChestBlock.setType(COPPER_BLOCK); } }, 1L); } private void onSpongeAbsorb(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) return; if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) e.setCancelled(); } private void onStackedBlockPhysics(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) return; if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) e.setCancelled(); } /* INTERNAL */ private void registerListeners() { if (!plugin.getSettings().getStackedBlocks().isEnabled()) { // Even if stacked blocks are disabled, we might want to keep the break or change related listeners. // We only want to keep them if there are any stacked blocks registered. if (!plugin.getStackedBlocks().hasStackedBlocks()) return; } else { registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockPlace); } registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockBreak); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockInteract); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockBreakByEntity); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockExplode); registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.LOWEST, this::onPistonExtend); registerCallback(GameEventType.PISTON_RETRACT_EVENT, GameEventPriority.LOWEST, this::onPistonRetract); registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.LOWEST, this::onBlockChangeState); registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onGolemCreate); registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.LOWEST, this::onSpongeAbsorb); if (plugin.getSettings().isPhysicsListener()) registerCallback(GameEventType.BLOCK_PHYSICS_EVENT, GameEventPriority.LOWEST, this::onStackedBlockPhysics); } private static Map> buildEntityTemplateOffsetsMap() { EnumMap> offsetsMap = new EnumMap<>(CreatureSpawnEvent.SpawnReason.class); List blockOffsets = new LinkedList<>(); blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0)); blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 0)); blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 1)); blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, 0)); blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, -1)); blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0)); offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM, blockOffsets); blockOffsets = new LinkedList<>(); blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0)); blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0)); offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN, blockOffsets); blockOffsets = new LinkedList<>(); blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0)); blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 0)); blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 1)); blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, 0)); blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, -1)); blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0)); blockOffsets.add(SBlockOffset.fromOffsets(1, 2, 0)); blockOffsets.add(SBlockOffset.fromOffsets(1, 2, 1)); blockOffsets.add(SBlockOffset.fromOffsets(-1, 2, 0)); blockOffsets.add(SBlockOffset.fromOffsets(-1, 2, -1)); offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_WITHER, blockOffsets); if (BUILD_COPPERGOLEM != null) { blockOffsets = new LinkedList<>(); blockOffsets.add(SBlockOffset.fromOffsets(0, -1, 0)); offsetsMap.put(BUILD_COPPERGOLEM, blockOffsets); } return Collections.unmodifiableMap(offsetsMap); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java ================================================ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Location; import org.bukkit.block.Block; import java.util.List; import java.util.function.Function; public class WorldDestructionListener extends AbstractGameEventListener { public WorldDestructionListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerListeners(); } //Checking for structures growing outside island. private void onStructureGrow(GameEvent e) { Location location = e.getArgs().location; // We care about destruction of island worlds only if (!plugin.getGrid().isIslandsWorld(location.getWorld())) { return; } Island island = plugin.getGrid().getIslandAt(location); if (island != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { e.getArgs().blocks.removeIf(blockState -> !island.isInsideRange(blockState.getLocation(wrapper.getHandle()))); } } } //Checking for chorus flower spread outside island. private void onBlockSpread(GameEvent e) { Block block = e.getArgs().block; // We care about destruction of island worlds only if (!plugin.getGrid().isIslandsWorld(block.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventDestruction(e.getArgs().source.getLocation(wrapper.getHandle())) || preventDestruction(block.getLocation(wrapper.getHandle()))) e.setCancelled(); } } public void onPistonExtend(GameEvent e) { Block pistonBlock = e.getArgs().block; // We care about destruction of island worlds only if (!plugin.getGrid().isIslandsWorld(pistonBlock.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventMultiDestruction(pistonBlock.getLocation(wrapper.getHandle()), e.getArgs().blocks, block -> block.getRelative(e.getArgs().direction))) e.setCancelled(); } } public void onPistonRetract(GameEvent e) { Block pistonBlock = e.getArgs().block; // We care about destruction of island worlds only if (!plugin.getGrid().isIslandsWorld(pistonBlock.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventMultiDestruction(pistonBlock.getLocation(wrapper.getHandle()), e.getArgs().blocks, block -> block.getRelative(e.getArgs().direction))) e.setCancelled(); } } private void onBlockFlow(GameEvent e) { Block block = e.getArgs().toBlock; // We care about destruction of island worlds only if (!plugin.getGrid().isIslandsWorld(block.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); if (preventDestruction(blockLocation)) e.setCancelled(); } } /* INTERNAL */ private boolean preventDestruction(Location location) { Island island = plugin.getGrid().getIslandAt(location); return island == null || !island.isInsideRange(location); } private boolean preventMultiDestruction(Location islandLocation, List blockList, @Nullable Function blockTransform) { Island island = plugin.getGrid().getIslandAt(islandLocation); if (island == null) return true; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { for (Block block : blockList) { if (blockTransform != null) block = blockTransform.apply(block); if (!island.isInsideRange(block.getLocation(wrapper.getHandle()))) return true; } } return false; } private void registerListeners() { registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.NORMAL, this::onStructureGrow); registerCallback(GameEventType.BLOCK_SPREAD_EVENT, GameEventPriority.NORMAL, this::onBlockSpread); registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.NORMAL, this::onPistonExtend); registerCallback(GameEventType.PISTON_RETRACT_EVENT, GameEventPriority.NORMAL, this::onPistonRetract); registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.NORMAL, this::onBlockFlow); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java ================================================ package com.bgsoftware.superiorskyblock.mission; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class MissionData { private static int currentIndex = 0; private final int index; private final String missionName; private final List itemRewards = new LinkedList<>(); private final List commandRewards = new LinkedList<>(); private final boolean autoReward; private final boolean islandMission; private final boolean disbandReset; private final boolean leaveReset; private final boolean resetAfterFinish; private final int resetAmount; @Nullable private final TemplateItem notCompleted; @Nullable private final TemplateItem canComplete; @Nullable private final TemplateItem locked; @Nullable private final TemplateItem completed; MissionData(Mission mission, String missionCategoryName, ConfigurationSection section) { this.index = currentIndex++; this.missionName = mission.getName(); this.islandMission = section.getBoolean("island", false); this.autoReward = section.getBoolean("auto-reward", true); this.disbandReset = section.getBoolean("disband-reset", false); this.leaveReset = section.getBoolean("leave-reset", false); this.resetAmount = section.getInt("reset-amount", 1); this.resetAfterFinish = section.getBoolean("reset-after-finish", true); if (section.isConfigurationSection("rewards.items")) { for (String key : section.getConfigurationSection("rewards.items").getKeys(false)) { TemplateItem templateItem = MenuParserImpl.getInstance().getItemStack("config.yml", section.getConfigurationSection("rewards.items." + key)); if (templateItem != null) { ItemStack itemStack = templateItem.build(); itemStack.setAmount(section.getInt("rewards.items." + key + ".amount", 1)); this.itemRewards.add(itemStack); } } } this.commandRewards.addAll(section.getStringList("rewards.commands")); String missionFilePath = "modules/missions/categories/" + missionCategoryName + "/" + this.missionName + ".yml"; this.notCompleted = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection("icons.not-completed")); this.canComplete = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection("icons.can-complete")); this.locked = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection("icons.locked")); this.completed = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection("icons.completed")); } public boolean isAutoReward() { return autoReward; } public boolean isIslandMission() { return islandMission; } public List getItemRewards() { return Collections.unmodifiableList(itemRewards); } public List getCommandRewards() { return Collections.unmodifiableList(commandRewards); } public int getIndex() { return index; } public String getMissionName() { return this.missionName; } public boolean isDisbandReset() { return disbandReset; } public boolean isLeaveReset() { return leaveReset; } public int getResetAmount() { return resetAmount; } public boolean isResetAfterFinish() { return resetAfterFinish; } public boolean hasLocked() { return locked != null; } public ItemBuilder getCompleted() { return (completed == null ? TemplateItem.AIR : completed).getBuilder(); } public ItemBuilder getLocked() { return (locked == null ? TemplateItem.AIR : locked).getBuilder(); } public ItemBuilder getCanComplete() { return (canComplete == null ? TemplateItem.AIR : canComplete).getBuilder(); } public ItemBuilder getNotCompleted() { return (notCompleted == null ? TemplateItem.AIR : notCompleted).getBuilder(); } @Override public String toString() { return "MissionData{name=" + this.missionName + "}"; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/mission/MissionReference.java ================================================ package com.bgsoftware.superiorskyblock.mission; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.missions.Mission; import org.jetbrains.annotations.Nullable; import java.lang.ref.WeakReference; import java.util.Objects; public class MissionReference { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final String missionName; private WeakReference> reference; public MissionReference(Mission mission) { this.missionName = mission.getName(); this.reference = new WeakReference<>(mission); } @Nullable public Mission getMission() { Mission mission = this.reference.get(); if (mission == null) { mission = plugin.getMissions().getMission(this.missionName); if (mission != null) this.reference = new WeakReference<>(mission); } return mission; } public boolean isValid() { return this.getMission() != null; } @Override public int hashCode() { return this.missionName.hashCode(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MissionReference that = (MissionReference) o; return that.missionName.hashCode() == that.missionName.hashCode() && Objects.equals(missionName, that.missionName); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.mission; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.MissionsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.io.FileClassLoader; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.io.JarFiles; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.mission.container.MissionsContainer; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.world.BukkitItems; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.ItemStack; import javax.script.ScriptException; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; public class MissionsManagerImpl extends Manager implements MissionsManager { private static final Object DATA_FOLDER_MUTEX = new Object(); private final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; private final Map missionTypesClassLoaders = new HashMap<>(); private final MissionsContainer missionsContainer; public MissionsManagerImpl(SuperiorSkyblockPlugin plugin, MissionsContainer missionsContainer) { super(plugin); this.missionsContainer = missionsContainer; } @Override public void loadData() { if (!BuiltinModules.MISSIONS.isEnabled()) return; BukkitExecutor.asyncTimer(this::saveMissionsData, 6000L); // Save missions data every 5 minutes } public void clearData() { saveMissionsData(); List> missionsList = plugin.getMissions().getAllMissions(); this.missionsContainer.clearMissionsData(); for (Mission mission : missionsList) { // Unload the mission mission.unload(); } this.missionTypesClassLoaders.forEach((missionJarName, classLoader) -> { try { ((URLClassLoader) classLoader).close(); } catch (Exception error) { Log.error(error, "An error occurred while unloading mission jar ", missionJarName, ":"); } }); this.missionTypesClassLoaders.clear(); // This is an attempt to force Windows to free the handles of the file. System.gc(); } @Override public Mission getMission(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); return this.missionsContainer.getMission(name); } @Override public List> getAllMissions() { return this.missionsContainer.getAllMissions(); } @Override public List> getPlayerMissions() { return this.missionsContainer.getPlayerMissions(); } @Override public List> getIslandMissions() { return this.missionsContainer.getIslandMissions(); } @Nullable @Override public MissionCategory getMissionCategory(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); return this.missionsContainer.getMissionCategory(name); } @Override public List getMissionCategories() { return this.missionsContainer.getMissionCategories(); } @Override public boolean hasCompleted(SuperiorPlayer superiorPlayer, Mission mission) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Optional missionDataOptional = getMissionData(mission); if (!missionDataOptional.isPresent()) return false; MissionData missionData = missionDataOptional.get(); Island playerIsland = superiorPlayer.getIsland(); if (missionData.isIslandMission()) { if (playerIsland != null) return playerIsland.hasCompletedMission(mission); } else { return superiorPlayer.hasCompletedMission(mission); } return false; } @Override public boolean canComplete(SuperiorPlayer superiorPlayer, Mission mission) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(mission, "mission parameter cannot be null."); return canCompleteNoProgress(superiorPlayer, mission) && mission.getProgress(superiorPlayer) >= 1.0; } @Override public boolean canCompleteNoProgress(SuperiorPlayer superiorPlayer, Mission mission) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(mission, "mission parameter cannot be null."); return canCompleteAgain(superiorPlayer, mission) && hasAllRequiredMissions(superiorPlayer, mission) && canPassAllChecks(superiorPlayer, mission); } @Override public boolean canCompleteAgain(SuperiorPlayer superiorPlayer, Mission mission) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Optional missionDataOptional = getMissionData(mission); if (!missionDataOptional.isPresent()) return false; MissionData missionData = missionDataOptional.get(); Island playerIsland = superiorPlayer.getIsland(); if (missionData.isIslandMission()) { if (playerIsland != null) return playerIsland.canCompleteMissionAgain(mission); } else { return superiorPlayer.canCompleteMissionAgain(mission); } return false; } @Override public boolean hasAllRequiredMissions(SuperiorPlayer superiorPlayer, Mission mission) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(mission, "mission parameter cannot be null."); return mission.getRequiredMissions().stream().allMatch(_mission -> { Mission missionToCheck = _mission == null ? null : plugin.getMissions().getMission(_mission); return missionToCheck != null && hasCompleted(superiorPlayer, missionToCheck); }); } @Override public boolean canPassAllChecks(SuperiorPlayer superiorPlayer, Mission mission) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(mission, "mission parameter cannot be null."); OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer(); return offlinePlayer != null && mission.getRequiredChecks().stream().allMatch(check -> { check = this.placeholdersService.get().parsePlaceholders(offlinePlayer, check); try { return Boolean.parseBoolean(plugin.getScriptEngine().eval(check) + ""); } catch (ScriptException error) { Log.entering("ENTER", superiorPlayer.getName(), mission.getName()); Log.error(error, "An unexpected error occurred while checking mission requirements:"); return false; } }); } @Override public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); rewardMission(mission, superiorPlayer, checkAutoReward, false); } @Override public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward, boolean forceReward) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); rewardMission(mission, superiorPlayer, checkAutoReward, forceReward, null); } @Override public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, boolean checkAutoReward, boolean forceReward, @Nullable Consumer result) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Optional missionDataOptional = getMissionData(mission); if (!missionDataOptional.isPresent()) { if (result != null) result.accept(false); return; } Log.debug(Debug.REWARD_MISSION, mission.getName(), superiorPlayer.getName(), checkAutoReward, forceReward); MissionData missionData = missionDataOptional.get(); IMissionsHolder missionsHolder = missionData.isIslandMission() ? superiorPlayer.getIsland() : superiorPlayer; if (missionsHolder == null) { mission.onCompleteFail(superiorPlayer); if (result != null) result.accept(false); throw new IllegalStateException("Cannot reward island mission " + mission.getName() + " as the player " + superiorPlayer.getName() + " does not have island."); } BukkitExecutor.ensureAsync(() -> rewardMissionAsyncInternal(mission, missionData, superiorPlayer, missionsHolder, checkAutoReward, forceReward, result)); } private void rewardMissionAsyncInternal(Mission mission, MissionData missionData, SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, boolean checkAutoReward, boolean forceReward, @Nullable Consumer result) { boolean rewarded; synchronized (superiorPlayer) { rewarded = tryRewardMissionLockedInternal(mission, missionData, superiorPlayer, missionsHolder, checkAutoReward, forceReward); } if (result != null) result.accept(rewarded); } private boolean tryRewardMissionLockedInternal(Mission mission, MissionData missionData, SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, boolean checkAutoReward, boolean forceReward) { if (!forceReward) { if (!canCompleteAgain(superiorPlayer, mission)) { mission.onCompleteFail(superiorPlayer); return false; } if (!canComplete(superiorPlayer, mission)) { return false; } if (checkAutoReward) { boolean shouldAutoReward = isAutoReward(mission); if (shouldAutoReward && !BuiltinModules.MISSIONS.getConfiguration().isAutoRewardOutsideIslands() && !plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld())) { return false; } if (!shouldAutoReward) { if (canCompleteAgain(superiorPlayer, mission)) { Message.MISSION_NO_AUTO_REWARD.send(superiorPlayer, mission.getName()); return false; } } } } List itemRewards = new ArrayList<>(); List commandRewards; //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (missionData) { missionData.getItemRewards().forEach(itemStack -> itemRewards.add(itemStack.clone())); commandRewards = new LinkedList<>(missionData.getCommandRewards()); } PluginEvent event = PluginEventsFactory.callMissionCompleteEvent( superiorPlayer, missionsHolder, mission, itemRewards, commandRewards); if (event.isCancelled()) { if (!forceReward) mission.onCompleteFail(superiorPlayer); return false; } if (!forceReward) mission.onComplete(superiorPlayer); missionsHolder.completeMission(mission); if (missionData.isResetAfterFinish()) { mission.clearData(superiorPlayer); } else { // We want to add the data to the next missions as well Object playerMissionProgress = mission.get(superiorPlayer); for (Mission otherMission : mission.getMissionCategory().getMissions()) { if (otherMission.getRequiredMissions().contains(mission.getName()) && canCompleteNoProgress(superiorPlayer, otherMission)) { try { otherMission.insertData(superiorPlayer, playerMissionProgress); } catch (ClassCastException error) { // We use raw parameterized values, therefore cast-errors can occur. // In this case, we'll just ignore these. } } } } List rewardedItems = new LinkedList<>(); for (ItemStack itemStack : event.getArgs().itemRewards) { ItemStack toGive = new ItemBuilder(itemStack) .replaceAll("{0}", mission.getName()) .replaceAll("{1}", superiorPlayer.getName()) .replaceAll("{2}", getIslandPlaceholder(missionsHolder)) .build(); toGive.setAmount(itemStack.getAmount()); rewardedItems.add(toGive); } // Auto complete other missions that depend on the mission that was just completed for (Mission otherMission : getAllMissions()) { if (otherMission.getRequiredMissions().contains(mission.getName()) && otherMission.canComplete(superiorPlayer)) { // Auto reward the next mission rewardMission(otherMission, superiorPlayer, true); } } if (!rewardedItems.isEmpty() || !event.getArgs().commandRewards.isEmpty()) { BukkitExecutor.ensureMain(() -> { if (!rewardedItems.isEmpty()) { superiorPlayer.runIfOnline(player -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { for (ItemStack toGive : itemRewards) { BukkitItems.addItem(toGive, player.getInventory(), player.getLocation(wrapper.getHandle())); } } }); } for (String command : event.getArgs().commandRewards) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command .replace("%mission%", mission.getName()) .replace("%player%", superiorPlayer.getName()) .replace("%island%", getIslandPlaceholder(missionsHolder)) ); } }); } return true; } private boolean moveOldDataFolder(File newDataFolder) { File oldDataFolder = new File(BuiltinModules.MISSIONS.getModuleFolder(), "data"); if (!oldDataFolder.exists()) return true; newDataFolder.mkdirs(); for (File file : Files.listFolderFiles(oldDataFolder, false)) { File targetFile = new File(newDataFolder, file.getName()); if (!file.renameTo(targetFile)) return false; } Files.deleteDirectory(oldDataFolder); return true; } @SuppressWarnings("ResultOfMethodCallIgnored") @Override public void saveMissionsData() { File dataFolder = BuiltinModules.MISSIONS.getDataStoreFolder(); if (!dataFolder.exists()) dataFolder.mkdirs(); for (Mission mission : getAllMissions()) { YamlConfiguration data = new YamlConfiguration(); try { mission.saveProgress(data); } catch (Throwable error) { Log.error(error, "An unexpected error while saving mission data for ", mission.getName(), ":"); continue; } boolean anyDataToWrite = !data.getKeys(true).isEmpty(); File dataFile = new File(dataFolder, mission.getName() + ".yml"); boolean dataFileExists = dataFile.exists(); if (!anyDataToWrite) { if (dataFileExists) dataFile.delete(); continue; } try { if (!dataFileExists) dataFile.createNewFile(); synchronized (DATA_FOLDER_MUTEX) { data.save(dataFile); } } catch (IOException error) { Log.error(error, "An unexpected error occurred while saving missions data to file ", dataFile.getName(), ":"); } } } @Override public void loadMissionsData() { loadMissionsData(getAllMissions()); } @Override public void loadMissionsData(List> missionsList) { Preconditions.checkNotNull(missionsList, "missionsList parameter cannot be null."); // Convert old data file to new format. convertOldMissionsData(); File dataFolder = BuiltinModules.MISSIONS.getDataStoreFolder(); if (!moveOldDataFolder(dataFolder)) throw new IllegalStateException("Failed moving old missions folder."); if (!dataFolder.exists()) return; for (Mission mission : missionsList) { File dataFile = new File(dataFolder, mission.getName() + ".yml"); if (dataFile.exists()) { try { synchronized (DATA_FOLDER_MUTEX) { mission.loadProgress(YamlConfiguration.loadConfiguration(dataFile)); } } catch (Throwable error) { Log.error(error, "An unexpected error occurred while loading mission data for ", mission.getName(), ":"); } } } } public void convertPlayerData(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) { getAllMissions().forEach(mission -> mission.transferData(oldPlayer, newPlayer)); File dataFolder = BuiltinModules.MISSIONS.getDataStoreFolder(); if (!dataFolder.exists()) return; // Convert the data in the data files as well BukkitExecutor.async(() -> { for (File file : Files.listFolderFiles(dataFolder, false)) { synchronized (DATA_FOLDER_MUTEX) { Files.replaceString(file, oldPlayer.getUniqueId() + "", newPlayer.getUniqueId() + ""); } } }); } public void loadMissionCategory(MissionCategory missionCategory) { this.missionsContainer.addMissionCategory(missionCategory); } public boolean hasAllRequirements(Mission mission, SuperiorPlayer superiorPlayer) { return hasAllRequiredMissions(superiorPlayer, mission) && canPassAllChecks(superiorPlayer, mission); } public boolean canDisplayMission(Mission mission, SuperiorPlayer superiorPlayer, boolean removeCompleted) { if (mission.isOnlyShowIfRequiredCompleted() && !hasAllRequirements(mission, superiorPlayer)) return false; if (removeCompleted) { if (mission.getIslandMission() ? superiorPlayer.getIsland() != null && !superiorPlayer.getIsland().canCompleteMissionAgain(mission) : !superiorPlayer.canCompleteMissionAgain(mission)) return false; } return true; } public boolean isPlayerMissionCategory(MissionCategory missionCategory) { return this.missionsContainer.isPlayerMissionCategory(missionCategory); } public boolean hasAnyPlayerMissionCategories() { return this.missionsContainer.hasAnyPlayerMissionCategories(); } @SuppressWarnings("deprecation") public Mission loadMission(String missionName, String missionCategoryName, FilesLookup filesLookup, ConfigurationSection missionSection) { Mission newMission = null; try { Mission mission = plugin.getMissions().getMission(missionName); if (mission == null) { String missionJarName = missionSection.getString("mission-file") + ".jar"; File missionJar = filesLookup.getFile(missionJarName); if (!missionJar.exists()) throw new RuntimeException("The mission file " + missionJar.getName() + " is not valid."); FileClassLoader missionClassLoader = this.missionTypesClassLoaders.computeIfAbsent(missionJarName, n -> { try { return new FileClassLoader(missionJar, plugin.getPluginClassLoader(), plugin.getNMSAlgorithms().getClassProcessor()); } catch (IOException error) { throw new RuntimeException(error); } }); Either, Throwable> missionClassLookup = JarFiles.getClass(missionJar.toURL(), Mission.class, missionClassLoader); if (missionClassLookup.getRight() != null) throw new RuntimeException("An unexpected error occurred while reading " + missionJar.getName() + ".", missionClassLookup.getRight()); Class missionClass = missionClassLookup.getLeft(); if (missionClass == null) throw new RuntimeException("The mission file " + missionJar.getName() + " is not valid."); boolean islandMission = missionSection.getBoolean("island", false); List requiredMissions = missionSection.getStringList("required-missions"); List requiredChecks = missionSection.getStringList("required-checks"); boolean onlyShowIfRequiredCompleted = missionSection.getBoolean("only-show-if-required-completed", false); mission = createInstance(missionClass, missionName, islandMission, requiredMissions, requiredChecks, onlyShowIfRequiredCompleted); mission.load(plugin, missionSection); this.missionsContainer.addMission(mission); newMission = mission; } this.missionsContainer.addMissionData(new MissionData(mission, missionCategoryName, missionSection)); Log.info("Registered mission " + missionName); } catch (Exception error) { Log.error(error, "An unexpected error occurred while registering mission ", missionName, ":"); } return newMission; } public Optional getMissionData(Mission mission) { return Optional.ofNullable(this.missionsContainer.getMissionData(mission)); } private boolean isAutoReward(Mission mission) { Optional missionDataOptional = getMissionData(mission); return missionDataOptional.isPresent() && missionDataOptional.get().isAutoReward(); } private Mission createInstance(Class clazz, String name, boolean islandMission, List requiredMissions, List requiredChecks, boolean onlyShowIfRequiredCompleted) throws Exception { Preconditions.checkArgument(Mission.class.isAssignableFrom(clazz), "Class " + clazz + " is not a Mission."); for (Constructor constructor : clazz.getConstructors()) { if (constructor.getParameterCount() == 0) { if (!constructor.isAccessible()) constructor.setAccessible(true); Mission mission = (Mission) constructor.newInstance(); mission.setName(name); mission.setIslandMission(islandMission); mission.addRequiredMission(requiredMissions.toArray(new String[0])); mission.addRequiredCheck(requiredChecks.toArray(new String[0])); if (onlyShowIfRequiredCompleted) mission.toggleOnlyShowIfRequiredCompleted(); return mission; } } throw new IllegalArgumentException("Class " + clazz + " has no valid constructors."); } private static String getIslandPlaceholder(@Nullable IMissionsHolder missionsHolder) { if (!(missionsHolder instanceof Island)) return ""; Island island = (Island) missionsHolder; return island.getName().isEmpty() ? island.getOwner() == null ? "" : island.getOwner().getName() : island.getName(); } private void convertOldMissionsData() { File file = new File(BuiltinModules.MISSIONS.getModuleFolder(), "_data.yml"); if (!file.exists()) return; File dataFolder = BuiltinModules.MISSIONS.getDataStoreFolder(); YamlConfiguration oldData = YamlConfiguration.loadConfiguration(file); for (Mission mission : getAllMissions()) { if (oldData.isConfigurationSection(mission.getName())) { ConfigurationSection dataSection = oldData.getConfigurationSection(mission.getName()); YamlConfiguration data = convertSectionToYaml(dataSection, new YamlConfiguration()); if (data.getKeys(true).isEmpty()) continue; File dataFile = new File(dataFolder, mission.getName() + ".yml"); try { if (!dataFile.exists()) { dataFile.getParentFile().mkdirs(); dataFile.createNewFile(); } data.save(dataFile); } catch (IOException error) { Log.error(error, "An unexpected error occurred while saving old mission file ", mission.getName(), ":"); } } } file.delete(); } private static YamlConfiguration convertSectionToYaml(ConfigurationSection section, YamlConfiguration config) { for (String key : section.getKeys(false)) config.set(key, section.get(key)); return config; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/mission/SMissionCategory.java ================================================ package com.bgsoftware.superiorskyblock.mission; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import java.util.Collections; import java.util.List; public class SMissionCategory implements MissionCategory { private final String name; private final int slot; private final List> missions; public SMissionCategory(String name, int slot, List> missions) { this.name = name; this.slot = slot; this.missions = missions; missions.forEach(mission -> mission.setMissionCategory(this)); } @Override public String getName() { return this.name; } @Override public int getSlot() { return this.slot; } @Override public List> getMissions() { return Collections.unmodifiableList(this.missions); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/mission/container/DefaultMissionsContainer.java ================================================ package com.bgsoftware.superiorskyblock.mission.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.mission.MissionData; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.Predicate; public class DefaultMissionsContainer implements MissionsContainer { private final Set playerMissionCategoriesCache = new HashSet<>(); private final Map> missionMap = new HashMap<>(); private final Map missionDataMap = new HashMap<>(); private final Map missionCategoryMap = new HashMap<>(); @Override public void addMission(Mission mission) { this.missionMap.put(mission.getName().toLowerCase(Locale.ENGLISH), mission); } @Nullable @Override public Mission getMission(String name) { return this.missionMap.get(name.toLowerCase(Locale.ENGLISH)); } @Override public List> getAllMissions() { return getFilteredMissions(missionData -> true); } @Override public List> getPlayerMissions() { return getFilteredMissions(missionData -> !missionData.isIslandMission()); } @Override public List> getIslandMissions() { return getFilteredMissions(MissionData::isIslandMission); } @Override public void addMissionData(MissionData missionData) { this.missionDataMap.put(missionData.getMissionName(), missionData); } @Nullable @Override public MissionData getMissionData(Mission mission) { return this.missionDataMap.get(mission.getName()); } @Override public void addMissionCategory(MissionCategory missionCategory) { this.missionCategoryMap.put(missionCategory.getName().toLowerCase(Locale.ENGLISH), missionCategory); if (missionCategory.getMissions().stream().anyMatch(mission -> !mission.getIslandMission())) playerMissionCategoriesCache.add(missionCategory); } @Nullable @Override public MissionCategory getMissionCategory(String name) { return this.missionCategoryMap.get(name.toLowerCase(Locale.ENGLISH)); } @Override public List getMissionCategories() { return new SequentialListBuilder().build(missionCategoryMap.values()); } @Override public boolean isPlayerMissionCategory(MissionCategory missionCategory) { return playerMissionCategoriesCache.contains(missionCategory); } @Override public boolean hasAnyPlayerMissionCategories() { return !playerMissionCategoriesCache.isEmpty(); } @Override public void clearMissionsData() { this.playerMissionCategoriesCache.clear(); this.missionMap.clear(); this.missionDataMap.clear(); this.missionCategoryMap.clear(); } private List> getFilteredMissions(Predicate predicate) { return new SequentialListBuilder() .filter(predicate) .sorted(Comparator.comparingInt(MissionData::getIndex)) .map(missionDataMap.values(), missionData -> getMission(missionData.getMissionName())); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/mission/container/MissionsContainer.java ================================================ package com.bgsoftware.superiorskyblock.mission.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.mission.MissionData; import java.util.List; public interface MissionsContainer { void addMission(Mission mission); @Nullable Mission getMission(String name); List> getAllMissions(); List> getPlayerMissions(); List> getIslandMissions(); void addMissionData(MissionData missionData); @Nullable MissionData getMissionData(Mission mission); void addMissionCategory(MissionCategory missionCategory); @Nullable MissionCategory getMissionCategory(String name); List getMissionCategories(); boolean isPlayerMissionCategory(MissionCategory missionCategory); boolean hasAnyPlayerMissionCategories(); void clearMissionsData(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java ================================================ package com.bgsoftware.superiorskyblock.module; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.core.io.Resources; import org.bukkit.event.Listener; import java.io.File; import java.util.Objects; public abstract class BuiltinModule extends PluginModule { protected T configuration; public BuiltinModule(String moduleName) { super(moduleName, "Ome_R"); } @Override public final void onEnable(SuperiorSkyblock plugin) { onEnable((SuperiorSkyblockPlugin) plugin); } protected abstract void onEnable(SuperiorSkyblockPlugin plugin); @Override public final void onReload(SuperiorSkyblock plugin) { onReload((SuperiorSkyblockPlugin) plugin); } protected void onReload(SuperiorSkyblockPlugin plugin) { onPluginInit(plugin); } @Override public void onDisable(SuperiorSkyblock plugin) { onDisable((SuperiorSkyblockPlugin) plugin); } protected abstract void onDisable(SuperiorSkyblockPlugin plugin); @Override public void loadData(SuperiorSkyblock plugin) { loadData((SuperiorSkyblockPlugin) plugin); } protected abstract void loadData(SuperiorSkyblockPlugin plugin); @Override public Listener[] getModuleListeners(SuperiorSkyblock plugin) { return !isEnabled() ? null : getModuleListeners((SuperiorSkyblockPlugin) plugin); } protected abstract Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin); @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblock plugin) { return !isEnabled() ? null : getSuperiorCommands((SuperiorSkyblockPlugin) plugin); } protected abstract SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin); @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblock plugin) { return !isEnabled() ? null : getSuperiorAdminCommands((SuperiorSkyblockPlugin) plugin); } protected abstract SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin); public final T getConfiguration() { return Objects.requireNonNull(this.configuration); } @Override protected void onPluginInit(SuperiorSkyblock plugin) { onPluginInit((SuperiorSkyblockPlugin) plugin); } protected void onPluginInit(SuperiorSkyblockPlugin plugin) { File configFile = new File(getModuleFolder(), "config.yml"); boolean firstTime = false; if (!configFile.exists()) { Resources.saveResource("modules/" + getName() + "/config.yml"); firstTime = true; } CommentedConfiguration config = CommentedConfiguration.loadConfiguration(configFile); boolean commitChanges = onConfigCreate(plugin, config, firstTime); if (commitChanges) { try { config.save(configFile); } catch (Exception error) { this.logger().e("An error occurred while saving config file for module " + getName() + ":", error); } } try { config.syncWithConfig(configFile, Resources.getResource("modules/" + getName() + "/config.yml"), getIgnoredSections()); } catch (Exception error) { this.logger().e("An error occurred while loading config file:", error); } this.configuration = createConfigFile(config); } protected ModuleLogger logger() { return (ModuleLogger) super.getLogger(); } protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { return false; } public boolean isEnabled() { return this.configuration.isEnabled() && isInitialized(); } protected abstract T createConfigFile(CommentedConfiguration config); protected String[] getIgnoredSections() { return new String[0]; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModules.java ================================================ package com.bgsoftware.superiorskyblock.module; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.module.bank.BankModule; import com.bgsoftware.superiorskyblock.module.generators.GeneratorsModule; import com.bgsoftware.superiorskyblock.module.missions.MissionsModule; import com.bgsoftware.superiorskyblock.module.upgrades.UpgradesModule; import java.util.Locale; public class BuiltinModules { public static final GeneratorsModule GENERATORS = new GeneratorsModule(); public static final MissionsModule MISSIONS = new MissionsModule(); public static final BankModule BANK = new BankModule(); public static final UpgradesModule UPGRADES = new UpgradesModule(); private BuiltinModules() { } public static PluginModule getBuiltinModule(String name) { switch (name.toLowerCase(Locale.ENGLISH)) { case "generators": return GENERATORS; case "missions": return MISSIONS; case "bank": return BANK; case "upgrades": return UPGRADES; default: return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/IModuleConfiguration.java ================================================ package com.bgsoftware.superiorskyblock.module; public interface IModuleConfiguration { boolean isEnabled(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/ModuleData.java ================================================ package com.bgsoftware.superiorskyblock.module; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import org.bukkit.event.Listener; public class ModuleData { private final Listener[] listeners; private final SuperiorCommand[] commands; private final SuperiorCommand[] adminCommands; public ModuleData(Listener[] listeners, SuperiorCommand[] commands, SuperiorCommand[] adminCommands) { this.listeners = listeners; this.commands = commands; this.adminCommands = adminCommands; } public Listener[] getListeners() { return listeners; } public SuperiorCommand[] getCommands() { return commands; } public SuperiorCommand[] getAdminCommands() { return adminCommands; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.module; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.handlers.ModulesManager; import com.bgsoftware.superiorskyblock.api.modules.ModuleLoadTime; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.io.FileClassLoader; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.io.JarFiles; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.module.container.ModulesContainer; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.event.Listener; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.net.URLClassLoader; import java.util.Collection; import java.util.List; import java.util.stream.Stream; public class ModulesManagerImpl extends Manager implements ModulesManager { private final ModulesContainer modulesContainer; private final File modulesFolder; private final File dataFolder; public ModulesManagerImpl(SuperiorSkyblockPlugin plugin, ModulesContainer modulesContainer) { super(plugin); this.modulesContainer = modulesContainer; this.modulesFolder = new File(plugin.getDataFolder(), "modules"); this.dataFolder = new File(plugin.getDataFolder(), "datastore/modules"); } @Override public void loadData() { if (!modulesFolder.exists()) //noinspection ResultOfMethodCallIgnored modulesFolder.mkdirs(); registerModule(BuiltinModules.GENERATORS); registerModule(BuiltinModules.MISSIONS); registerModule(BuiltinModules.BANK); registerModule(BuiltinModules.UPGRADES); registerExternalModules(); } @Override public void registerModule(PluginModule pluginModule) { Preconditions.checkNotNull(pluginModule, "pluginModule parameter cannot be null."); this.modulesContainer.registerModule(pluginModule, modulesFolder, dataFolder); } @Override public PluginModule registerModule(File moduleFile) throws IOException, ReflectiveOperationException { Preconditions.checkArgument(moduleFile.exists(), "The file " + moduleFile.getName() + " does not exist."); Preconditions.checkArgument(moduleFile.getName().endsWith(".jar"), "The file " + moduleFile.getName() + " is not a valid jar file."); FileClassLoader moduleClassLoader = new FileClassLoader(moduleFile, plugin.getPluginClassLoader(), plugin.getNMSAlgorithms().getClassProcessor()); Either, Throwable> moduleClassLookup = JarFiles.getClass(moduleFile.toURL(), PluginModule.class, moduleClassLoader); if (moduleClassLookup.getRight() != null) throw new RuntimeException("An error occurred while reading " + moduleFile.getName(), moduleClassLookup.getRight()); Class moduleClass = moduleClassLookup.getLeft(); if (moduleClass == null) throw new RuntimeException("The module file " + moduleFile.getName() + " is not valid."); PluginModule pluginModule = createInstance(moduleClass); pluginModule.initModuleLoader(moduleFile, moduleClassLoader); registerModule(pluginModule); return pluginModule; } @Override public void unregisterModule(PluginModule pluginModule) { Preconditions.checkNotNull(pluginModule, "pluginModule parameter cannot be null."); Preconditions.checkState(getModule(pluginModule.getName()) != null, "PluginModule with the name " + pluginModule.getName() + " is not registered in the plugin anymore."); Log.info("Disabling the module ", pluginModule.getName(), "..."); try { pluginModule.onDisable(plugin); } catch (Throwable error) { Log.error("An unexpected error occurred while disabling the module ", pluginModule.getName(), "."); Log.error(error, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); } this.modulesContainer.unregisterModule(pluginModule); if (pluginModule instanceof BuiltinModule) return; // We now want to unload the ClassLoader and free the held handles for the file. ClassLoader classLoader = pluginModule.getClassLoader(); if (classLoader != plugin.getPluginClassLoader() && classLoader instanceof URLClassLoader) { try { ((URLClassLoader) classLoader).close(); // This is an attempt to force Windows to free the handles of the file. System.gc(); } catch (IOException ignored) { } } } @Override @Nullable public PluginModule getModule(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); return this.modulesContainer.getModule(name); } @Override public Collection getModules() { return this.modulesContainer.getModules(); } @Override public void enableModule(PluginModule pluginModule) { Preconditions.checkNotNull(pluginModule, "pluginModule parameter cannot be null."); long startTime = System.currentTimeMillis(); Log.info("Enabling the module ", pluginModule.getName(), "..."); try { pluginModule.onEnable(plugin); } catch (Throwable error) { Log.error("An unexpected error occurred while enabling the module ", pluginModule.getName(), "."); Log.error(error, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); try { // Unregistering the module. unregisterModule(pluginModule); } catch (Throwable error2) { Log.error("An unexpected error occurred while disabling the module ", pluginModule.getName(), "."); Log.error(error2, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); } return; } startupModuleInternal(pluginModule); Log.info("Finished enabling the module ", pluginModule.getName(), " (Took ", System.currentTimeMillis() - startTime, "ms)"); } @Override public void enableModules(ModuleLoadTime moduleLoadTime) { Preconditions.checkNotNull(moduleLoadTime, "moduleLoadTime parameter cannot be null."); } public void runModuleLifecycle(ModuleLoadTime moduleLoadTime, boolean isReload) { if (isReload) { reloadModulesInternal(moduleLoadTime); } else { enableModulesInternal(moduleLoadTime); } } private void reloadModulesInternal(ModuleLoadTime moduleLoadTime) { filterModules(moduleLoadTime).forEach(this::reloadModuleInternal); } private void enableModulesInternal(ModuleLoadTime moduleLoadTime) { filterModules(moduleLoadTime).forEach(this::enableModule); } private void reloadModuleInternal(PluginModule pluginModule) { try { pluginModule.onReload(plugin); } catch (Throwable error) { Log.error("An unexpected error occurred while reloading the module ", pluginModule.getName(), "."); Log.error(error, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); } // We remove the old module data, as all listeners and commands were cleared due to the reload this.modulesContainer.removeModuleData(pluginModule); // Register module data again startupModuleInternal(pluginModule); } private void startupModuleInternal(PluginModule pluginModule) { Listener[] listeners = pluginModule.getModuleListeners(plugin); SuperiorCommand[] commands = pluginModule.getSuperiorCommands(plugin); SuperiorCommand[] adminCommands = pluginModule.getSuperiorAdminCommands(plugin); if (listeners != null || commands != null || adminCommands != null) this.modulesContainer.addModuleData(pluginModule, new ModuleData(listeners, commands, adminCommands)); if (listeners != null) { for (Listener listener : listeners) Bukkit.getPluginManager().registerEvents(listener, plugin); } if (commands != null) { for (SuperiorCommand superiorCommand : commands) plugin.getCommands().registerCommand(superiorCommand); } if (adminCommands != null) { for (SuperiorCommand superiorCommand : adminCommands) plugin.getCommands().registerAdminCommand(superiorCommand); } } public void loadModulesData(SuperiorSkyblockPlugin plugin) { getModules().forEach(pluginModule -> { try { pluginModule.loadData(plugin); } catch (Throwable error) { Log.error("An unexpected error occurred while loading data for the module ", pluginModule.getName(), "."); Log.error(error, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); } }); } private void registerExternalModules() { List folderFiles = Files.listFolderFiles(modulesFolder, false, file -> file.getName().endsWith(".jar")); if (folderFiles.isEmpty()) return; try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(this.modulesFolder)) { for (File file : folderFiles) { String fileName = file.getName(); try { registerModule(filesLookup.getFile(fileName)); } catch (Exception error) { Log.error(error, "An unexpected error occurred while registering module ", fileName, ":"); } } } } private Stream filterModules(ModuleLoadTime moduleLoadTime) { return this.modulesContainer.getModules().stream() .filter(pluginModule -> pluginModule.getLoadTime() == moduleLoadTime); } private PluginModule createInstance(Class clazz) throws ReflectiveOperationException { Preconditions.checkArgument(PluginModule.class.isAssignableFrom(clazz), "Class " + clazz + " is not a PluginModule."); for (Constructor constructor : clazz.getConstructors()) { if (constructor.getParameterCount() == 0) { if (!constructor.isAccessible()) constructor.setAccessible(true); return (PluginModule) constructor.newInstance(); } } throw new IllegalArgumentException("Class " + clazz + " has no valid constructors."); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java ================================================ package com.bgsoftware.superiorskyblock.module.bank; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.module.BuiltinModule; import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminAddBankLimit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminDeposit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminSetBankLimit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminWithdraw; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdBalance; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdBank; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdDeposit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdWithdraw; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.Listener; import java.io.File; import java.math.BigDecimal; public class BankModule extends BuiltinModule { public BankModule() { super("bank"); } @Override protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { File oldConfigFile = new File(plugin.getDataFolder(), "config.yml"); if (!oldConfigFile.exists()) return false; CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldConfigFile); boolean updatedConfig = false; if (syncValues("bank-worth-rate", config, oldConfig)) updatedConfig = true; if (syncValues("disband-refund", config, oldConfig)) updatedConfig = true; if (syncValues("bank-logs", config, oldConfig)) updatedConfig = true; if (syncValues("cache-logs", config, oldConfig)) updatedConfig = true; if (syncValues("bank-interest", config, oldConfig)) updatedConfig = true; return updatedConfig; } @Override public void onEnable(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public void onDisable(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public void loadData(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { return null; } @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { return new SuperiorCommand[]{new CmdBalance(), new CmdBank(), new CmdDeposit(), new CmdWithdraw()}; } @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { return new SuperiorCommand[]{new CmdAdminAddBankLimit(), new CmdAdminDeposit(), new CmdAdminSetBankLimit(), new CmdAdminWithdraw()}; } @Override protected Configuration createConfigFile(CommentedConfiguration config) { return new Configuration(config); } private static boolean syncValues(String section, YamlConfiguration newConfig, YamlConfiguration oldConfig) { if (oldConfig.contains(section)) { newConfig.set(section, oldConfig.get(section)); return true; } return false; } public static class Configuration implements IModuleConfiguration { private final boolean enabled; private final double bankWorthRate; private final boolean hasDisbandRefund; private final BigDecimal disbandRefund; private final boolean bankLogs; private final boolean cacheAllLogs; private final boolean bankInterestEnabled; private final int bankInterestInterval; private final int bankInterestPercentage; private final int bankInterestRecentActive; Configuration(CommentedConfiguration config) { this.enabled = config.getBoolean("enabled"); int bankWorthRate = config.getInt("bank-worth-rate", 1000); this.bankWorthRate = bankWorthRate == 0 ? 0D : 1D / bankWorthRate; double disbandRefund = Math.max(0, Math.min(100, config.getDouble("disband-refund"))) / 100D; this.hasDisbandRefund = disbandRefund > 0; this.disbandRefund = BigDecimal.valueOf(disbandRefund); this.bankLogs = config.getBoolean("bank-logs", true); this.cacheAllLogs = config.getBoolean("cache-logs", true); this.bankInterestEnabled = config.getBoolean("bank-interest.enabled", true); this.bankInterestInterval = config.getInt("bank-interest.interval", 86400); this.bankInterestPercentage = config.getInt("bank-interest.percentage", 10); this.bankInterestRecentActive = config.getInt("bank-interest.recent-active", 86400); } @Override public boolean isEnabled() { return this.enabled; } public double getBankWorthRate() { return bankWorthRate; } public boolean hasDisbandRefund() { return hasDisbandRefund; } public BigDecimal getDisbandRefund() { return disbandRefund; } public boolean isBankLogs() { return bankLogs; } public boolean isCacheAllLogs() { return cacheAllLogs; } public boolean isBankInterestEnabled() { return bankInterestEnabled; } public int getBankInterestInterval() { return bankInterestInterval; } public int getBankInterestPercentage() { return bankInterestPercentage; } public int getBankInterestRecentActive() { return bankInterestRecentActive; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminAddBankLimit.java ================================================ package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class CmdAdminAddBankLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addbanklimit"); } @Override public String getPermission() { return "superior.admin.addbanklimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin addbanklimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { BigDecimal limit = CommandArguments.getBigDecimalAmount(sender, args[3]); if (limit == null) return; int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeBankLimitEvent( island, sender, island.getBankLimit().add(limit)); if (!event.isCancelled()) { island.setBankLimit(event.getArgs().bankLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_BANK_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_BANK_LIMIT_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_BANK_LIMIT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminDeposit.java ================================================ package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class CmdAdminDeposit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("deposit"); } @Override public String getPermission() { return "superior.admin.deposit"; } @Override public String getUsage(java.util.Locale locale) { return "admin deposit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_DEPOSIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { BigDecimal amount = CommandArguments.getBigDecimalAmount(sender, args[3]); if (amount == null) return; islands.forEach(island -> island.getIslandBank().depositAdminMoney(sender, amount)); if (targetPlayer == null) Message.ADMIN_DEPOSIT_MONEY_NAME.send(sender, Formatters.NUMBER_FORMATTER.format(amount), islands.size() == 1 ? islands.get(0).getName() : "all"); else Message.ADMIN_DEPOSIT_MONEY.send(sender, Formatters.NUMBER_FORMATTER.format(amount), targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminSetBankLimit.java ================================================ package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class CmdAdminSetBankLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setbanklimit"); } @Override public String getPermission() { return "superior.admin.setbanklimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin setbanklimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { BigDecimal limit = CommandArguments.getBigDecimalAmount(sender, args[3]); if (limit == null) return; int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeBankLimitEvent(island, sender, limit); if (!event.isCancelled()) { island.setBankLimit(event.getArgs().bankLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_BANK_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_BANK_LIMIT_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_BANK_LIMIT.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminWithdraw.java ================================================ package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class CmdAdminWithdraw implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("withdraw"); } @Override public String getPermission() { return "superior.admin.withdraw"; } @Override public String getUsage(java.util.Locale locale) { return "admin withdraw <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_WITHDRAW.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { BigDecimal amount = BigDecimal.valueOf(-1); if (args[3].equalsIgnoreCase("all") || args[3].equals("*")) { amount = island.getIslandBank().getBalance(); } else try { amount = new BigDecimal(args[3]); } catch (IllegalArgumentException ignored) { } if (amount.compareTo(BigDecimal.ZERO) <= 0) { Message.INVALID_AMOUNT.send(sender, args[3]); return; } if (island.getIslandBank().getBalance().compareTo(BigDecimal.ZERO) == 0) { Message.ISLAND_BANK_EMPTY.send(sender); return; } if (island.getIslandBank().getBalance().compareTo(amount) < 0) { Message.WITHDRAW_ALL_MONEY.send(sender, island.getIslandBank().getBalance().toString()); amount = island.getIslandBank().getBalance(); } island.getIslandBank().withdrawAdminMoney(sender, amount); if (targetPlayer == null) Message.WITHDRAWN_MONEY_NAME.send(sender, Formatters.NUMBER_FORMATTER.format(amount), island.getName()); else Message.WITHDRAWN_MONEY.send(sender, Formatters.NUMBER_FORMATTER.format(amount), targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdBalance.java ================================================ package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdBalance implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("balance", "bal", "money"); } @Override public String getPermission() { return "superior.island.balance"; } @Override public String getUsage(java.util.Locale locale) { return "balance [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_BALANCE.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = args.length == 1 ? CommandArguments.getIslandWhereStanding(plugin, sender) : CommandArguments.getIsland(plugin, sender, args[1]); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); SuperiorPlayer targetPlayer = arguments.getSuperiorPlayer(); if (island == superiorPlayer.getIsland()) Message.ISLAND_BANK_SHOW.send(sender, island.getIslandBank().getBalance()); else if (targetPlayer == null) Message.ISLAND_BANK_SHOW_OTHER_NAME.send(sender, island.getName(), island.getIslandBank().getBalance()); else Message.ISLAND_BANK_SHOW_OTHER.send(sender, targetPlayer.getName(), island.getIslandBank().getBalance()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length == 2 ? CommandTabCompletes.getPlayerIslandsExceptSender(plugin, sender, args[1], plugin.getSettings().isTabCompleteHideVanished()) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdBank.java ================================================ package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdBank implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("bank"); } @Override public String getPermission() { return "superior.island.bank"; } @Override public String getUsage(java.util.Locale locale) { if (BuiltinModules.BANK.getConfiguration().isBankLogs()) return "bank [logs]"; else return "bank"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_BANK.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return BuiltinModules.BANK.getConfiguration().isBankLogs() ? 2 : 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); if (args.length == 2 && args[1].equalsIgnoreCase("logs") && BuiltinModules.BANK.getConfiguration().isBankLogs()) { plugin.getMenus().openBankLogs(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } else { plugin.getMenus().openIslandBank(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return args.length != 2 || !BuiltinModules.BANK.getConfiguration().isBankLogs() ? Collections.emptyList() : CommandTabCompletes.getCustomComplete(args[1], "logs"); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdDeposit.java ================================================ package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class CmdDeposit implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("deposit"); } @Override public String getPermission() { return "superior.island.deposit"; } @Override public String getUsage(java.util.Locale locale) { return "deposit <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_DEPOSIT.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); BigDecimal moneyInBank = plugin.getProviders().getBankEconomyProvider().getBalance(superiorPlayer); BigDecimal amount = BigDecimal.valueOf(-1); if (args[1].equalsIgnoreCase("all") || args[1].equals("*")) { amount = moneyInBank; } else try { amount = BigDecimal.valueOf(Double.parseDouble(args[1])); } catch (IllegalArgumentException ignored) { } BankTransaction transaction = island.getIslandBank().depositMoney(superiorPlayer, amount); MenuActions.handleDeposit(superiorPlayer, island, transaction, null, null, amount); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdWithdraw.java ================================================ package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; public class CmdWithdraw implements ISuperiorCommand { @Override public List getAliases() { return Collections.singletonList("withdraw"); } @Override public String getPermission() { return "superior.island.withdraw"; } @Override public String getUsage(java.util.Locale locale) { return "withdraw <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_WITHDRAW.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); BigDecimal amount = BigDecimal.valueOf(-1); if (args[1].equalsIgnoreCase("all") || args[1].equals("*")) { amount = island.getIslandBank().getBalance(); } else try { amount = new BigDecimal(args[1]); } catch (IllegalArgumentException ignored) { } BankTransaction transaction = island.getIslandBank().withdrawMoney(superiorPlayer, amount, null); MenuActions.handleWithdraw(superiorPlayer, island, transaction, null, null, amount); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java ================================================ package com.bgsoftware.superiorskyblock.module.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.modules.ModuleInitializeData; import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.module.ModuleData; import com.bgsoftware.superiorskyblock.module.logging.ModuleLoggerFileHandler; import com.google.common.base.Preconditions; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import java.io.File; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class DefaultModulesContainer implements ModulesContainer { private final Map modulesMap = new HashMap<>(); private final Map modulesData = new ArrayMap<>(); private final SuperiorSkyblockPlugin plugin; private final File globalLogsFolder; private final File globalArchiveLogsFolder; public DefaultModulesContainer(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; this.globalLogsFolder = new File(plugin.getDataFolder(), "logs" + File.separator + "modules"); this.globalArchiveLogsFolder = new File(plugin.getDataFolder(), "logs" + File.separator + "archive"); } @Override public void registerModule(PluginModule pluginModule, File modulesFolder, File modulesDataFolder) { String moduleName = pluginModule.getName().toLowerCase(Locale.ENGLISH); Preconditions.checkState(!modulesMap.containsKey(moduleName), "PluginModule with the name " + moduleName + " already exists."); File dataFolder = new File(modulesDataFolder, pluginModule.getName()); File moduleFolder = new File(modulesFolder, pluginModule.getName()); File logsFolder = new File(this.globalLogsFolder, pluginModule.getName()); ModuleLogger moduleLogger = new ModuleLogger(pluginModule); ModuleLoggerFileHandler.addToLogger(logsFolder, this.globalArchiveLogsFolder, moduleLogger); try { ModuleInitializeDataImpl context = new ModuleInitializeDataImpl(dataFolder, moduleFolder, moduleLogger); pluginModule.initModule(plugin, context); } catch (Throwable error) { Log.error("An unexpected error occurred while initializing the module ", pluginModule.getName(), "."); Log.error(error, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); return; } modulesMap.put(moduleName, pluginModule); } @Override public void unregisterModule(PluginModule pluginModule) { ModuleData moduleData = modulesData.remove(pluginModule); if (moduleData != null) { if (moduleData.getListeners() != null) { for (Listener listener : moduleData.getListeners()) HandlerList.unregisterAll(listener); } if (moduleData.getCommands() != null) { for (SuperiorCommand superiorCommand : moduleData.getCommands()) plugin.getCommands().unregisterCommand(superiorCommand); } if (moduleData.getAdminCommands() != null) { for (SuperiorCommand superiorCommand : moduleData.getAdminCommands()) plugin.getCommands().unregisterAdminCommand(superiorCommand); } } pluginModule.disableModule(); modulesMap.remove(pluginModule.getName().toLowerCase(Locale.ENGLISH)); } @Nullable @Override public PluginModule getModule(String name) { return this.modulesMap.get(name.toLowerCase(Locale.ENGLISH)); } @Override public Collection getModules() { return new SequentialListBuilder().build(modulesMap.values()); } @Override public void addModuleData(PluginModule pluginModule, ModuleData moduleData) { this.modulesData.put(pluginModule, moduleData); } @Override public void removeModuleData(PluginModule module) { this.modulesData.remove(module); } private static class ModuleInitializeDataImpl implements ModuleInitializeData { private final File dataFolder; private final File moduleFolder; private final ModuleLogger logger; public ModuleInitializeDataImpl(File dataFolder, File moduleFolder, ModuleLogger logger) { this.dataFolder = dataFolder; this.moduleFolder = moduleFolder; this.logger = logger; } @Override public File getDataFolder() { return this.dataFolder; } @Override public File getModuleFolder() { return this.moduleFolder; } @Override public ModuleLogger getLogger() { return this.logger; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java ================================================ package com.bgsoftware.superiorskyblock.module.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.module.ModuleData; import java.io.File; import java.util.Collection; public interface ModulesContainer { void registerModule(PluginModule pluginModule, File modulesFolder, File modulesDataFolder); void unregisterModule(PluginModule pluginModule); @Nullable PluginModule getModule(String name); Collection getModules(); void addModuleData(PluginModule pluginModule, ModuleData moduleData); void removeModuleData(PluginModule module); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/generators/GeneratorsModule.java ================================================ package com.bgsoftware.superiorskyblock.module.generators; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.module.BuiltinModule; import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminAddGenerator; import com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminClearGenerator; import com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminSetGenerator; import com.bgsoftware.superiorskyblock.module.generators.listeners.GeneratorsListener; import org.bukkit.event.Listener; import java.io.File; public class GeneratorsModule extends BuiltinModule { public GeneratorsModule() { super("generators"); } @Override protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { File oldConfigFile = new File(plugin.getDataFolder(), "config.yml"); if (!oldConfigFile.exists()) return false; CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldConfigFile); boolean updatedConfig = false; if (oldConfig.contains("generators")) { config.set("enabled", oldConfig.getBoolean("generators")); } return updatedConfig; } @Override public void onEnable(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public void onDisable(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public void loadData(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { return new Listener[]{new GeneratorsListener(plugin)}; } @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { return null; } @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { return new SuperiorCommand[]{new CmdAdminAddGenerator(), new CmdAdminClearGenerator(), new CmdAdminSetGenerator()}; } @Override protected Configuration createConfigFile(CommentedConfiguration config) { return new Configuration(config); } public static class Configuration implements IModuleConfiguration { private final boolean enabled; private final boolean matchGeneratorWorld; Configuration(CommentedConfiguration config) { this.enabled = config.getBoolean("enabled"); this.matchGeneratorWorld = config.getBoolean("match-generator-world"); } @Override public boolean isEnabled() { return this.enabled; } public boolean isMatchGeneratorWorld() { return this.matchGeneratorWorld; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java ================================================ package com.bgsoftware.superiorskyblock.module.generators.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdAdminAddGenerator implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addgenerator"); } @Override public String getPermission() { return "superior.admin.addgenerator"; } @Override public String getUsage(java.util.Locale locale) { return "admin addgenerator <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_VALUE.getMessage(locale) + "> [" + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 6; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key material = Keys.ofMaterialAndData(args[3]); boolean percentage = args[4].endsWith("%"); if (percentage) args[4] = args[4].substring(0, args[4].length() - 1); NumberArgument arguments = CommandArguments.getAmount(sender, args[4]); if (!arguments.isSucceed()) return; int amount = arguments.getNumber(); if (amount == 0 || (percentage && (amount < 0 || amount > 100))) { Message.INVALID_PERCENTAGE.send(sender); return; } Dimension dimension = args.length == 5 ? plugin.getSettings().getWorlds().getDefaultWorldDimension() : CommandArguments.getDimension(sender, args[5]); if (dimension == null) return; int islandsChangedCount = 0; for (Island island : islands) { if (percentage) { int ratePercentage = Math.max(0, Math.min(100, island.getGeneratorPercentage(material, dimension) + amount)); if (!island.setGeneratorPercentage(material, ratePercentage, dimension, sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null, true)) { continue; } } else { int generatorRate = island.getGeneratorAmount(material, dimension) + amount; if (generatorRate <= 0) { if (!PluginEventsFactory.callIslandRemoveGeneratorRateEvent(island, sender, material, dimension)) continue; island.removeGeneratorAmount(material, dimension); } else { PluginEvent event = PluginEventsFactory.callIslandChangeGeneratorRateEvent( island, sender, material, dimension, island.getGeneratorAmount(material, dimension) + amount); if (event.isCancelled()) continue; island.setGeneratorAmount(material, event.getArgs().generatorRate, dimension); } } ++islandsChangedCount; } if (islandsChangedCount <= 0) return; if (islands.size() != 1) Message.GENERATOR_UPDATED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey())); else if (targetPlayer == null) Message.GENERATOR_UPDATED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()), islands.get(0).getName()); else Message.GENERATOR_UPDATED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getMaterialsForGenerators(args[3]) : args.length == 6 ? CommandTabCompletes.getDimensions(plugin, args[5]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java ================================================ package com.bgsoftware.superiorskyblock.module.generators.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminClearGenerator implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("cleargenerator", "cg"); } @Override public String getPermission() { return "superior.admin.cleargenerator"; } @Override public String getUsage(java.util.Locale locale) { return "admin cleargenerator <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> [" + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Dimension dimension = args.length == 3 ? plugin.getSettings().getWorlds().getDefaultWorldDimension() : CommandArguments.getDimension(sender, args[3]); if (dimension == null) return; int islandsChangedCount = 0; for (Island island : islands) { if (!PluginEventsFactory.callIslandClearGeneratorRatesEvent(island, sender, dimension)) continue; ++islandsChangedCount; island.clearGeneratorAmounts(dimension); } if (islandsChangedCount <= 0) return; if (islands.size() != 1) Message.GENERATOR_CLEARED_ALL.send(sender); else if (targetPlayer == null) Message.GENERATOR_CLEARED_NAME.send(sender, islands.get(0).getName()); else Message.GENERATOR_CLEARED.send(sender, targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java ================================================ package com.bgsoftware.superiorskyblock.module.generators.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdAdminSetGenerator implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setgenerator"); } @Override public String getPermission() { return "superior.admin.setgenerator"; } @Override public String getUsage(java.util.Locale locale) { return "admin setgenerator <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_VALUE.getMessage(locale) + "> [" + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 6; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key material = Keys.ofMaterialAndData(args[3]); boolean percentage = args[4].endsWith("%"); if (percentage) args[4] = args[4].substring(0, args[4].length() - 1); NumberArgument arguments = CommandArguments.getAmount(sender, args[4]); if (!arguments.isSucceed()) return; int amount = arguments.getNumber(); if (percentage && (amount < 0 || amount > 100)) { Message.INVALID_PERCENTAGE.send(sender); return; } Dimension dimension = args.length == 5 ? plugin.getSettings().getWorlds().getDefaultWorldDimension() : CommandArguments.getDimension(sender, args[5]); if (dimension == null) return; int islandsChangedCount = 0; for (Island island : islands) { if (percentage) { if (!island.setGeneratorPercentage(material, amount, dimension, sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null, true)) { continue; } } else { if (amount <= 0) { if (!PluginEventsFactory.callIslandRemoveGeneratorRateEvent(island, sender, material, dimension)) continue; island.removeGeneratorAmount(material, dimension); } else { PluginEvent event = PluginEventsFactory.callIslandChangeGeneratorRateEvent( island, sender, material, dimension, amount); if (event.isCancelled()) continue; island.setGeneratorAmount(material, event.getArgs().generatorRate, dimension); } } ++islandsChangedCount; } if (islandsChangedCount <= 0) return; if (islands.size() != 1) Message.GENERATOR_UPDATED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey())); else if (targetPlayer == null) Message.GENERATOR_UPDATED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()), islands.get(0).getName()); else Message.GENERATOR_UPDATED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(material.getGlobalKey()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getMaterialsForGenerators(args[3]) : args.length == 6 ? CommandTabCompletes.getDimensions(plugin, args[5]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java ================================================ package com.bgsoftware.superiorskyblock.module.generators.listeners; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.GeneratorType; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFromToEvent; import java.util.Optional; @SuppressWarnings("unused") public class GeneratorsListener implements Listener { private static final Material BASALT_MATERIAL = EnumHelper.getEnum(Material.class, "BASALT"); private static final Material LAVA_MATERIAL = EnumHelper.getEnum(Material.class, "STATIONARY_LAVA", "LAVA"); private final SuperiorSkyblockPlugin plugin; public GeneratorsListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockFormEvent(BlockFormEvent e) { if (!BuiltinModules.GENERATORS.isEnabled()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(blockLocation); if (island == null) return; GeneratorType generatorType = e.getNewState().getType() == BASALT_MATERIAL ? GeneratorType.BASALT : GeneratorType.NORMAL; if (e.getBlock().getType() != LAVA_MATERIAL || generatorType != GeneratorType.BASALT) return; Dimension dimension; if (BuiltinModules.GENERATORS.getConfiguration().isMatchGeneratorWorld()) { dimension = Dimensions.fromEnvironment(World.Environment.NETHER); } else { World blockWorld = blockLocation.getWorld(); dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment())); } Key generatedBlock = island.generateBlock(blockLocation, dimension, true); if (generatedBlock != null && !generatedBlock.equals(generatorType.getDefaultBlock())) e.setCancelled(true); } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockFromToEvent(BlockFromToEvent e) { if (!BuiltinModules.GENERATORS.isEnabled()) return; Block block = e.getToBlock(); // Should fix solid blocks from generating custom blocks // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/837 if (block.getType().isSolid()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); World blockWorld = blockLocation.getWorld(); Island island = plugin.getGrid().getIslandAt(blockLocation); if (island == null) return; if (e.getBlock().getType() != LAVA_MATERIAL) return; GeneratorType generatorType = GeneratorType.detectGenerator(block); if (generatorType == GeneratorType.NONE) return; Dimension dimension; if (BuiltinModules.GENERATORS.getConfiguration().isMatchGeneratorWorld()) { dimension = Dimensions.fromEnvironment(generatorType == GeneratorType.BASALT ? World.Environment.NETHER : World.Environment.NORMAL); } else { dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment())); } Key generatedBlock = island.generateBlock(blockLocation, dimension, true); if (generatedBlock != null && !generatedBlock.equals(generatorType.getDefaultBlock())) e.setCancelled(true); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java ================================================ package com.bgsoftware.superiorskyblock.module.logging; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Path; import java.nio.file.attribute.FileTime; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.ZoneOffset; import java.util.Date; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.logging.FileHandler; import java.util.logging.Formatter; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; public class ModuleLoggerFileHandler { private static final SimpleDateFormat ARCHIVE_DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy"); private static final Path BASE_LOGS_FOLDER = new File(SuperiorSkyblockPlugin.getPlugin().getDataFolder(), "logs").toPath(); public static Logger addToLogger(File logsFolder, File archiveFolder, Logger logger) { try { logsFolder.mkdirs(); File logsFile = new File(logsFolder, "latest.log"); long startOfDayTime = LocalDate.now().atStartOfDay(ZoneOffset.systemDefault()).toEpochSecond() * 1000; if (logsFile.exists() && logsFile.lastModified() < startOfDayTime) { // Save old file File dateLogsFileZipped = new File(archiveFolder, ARCHIVE_DATE_FORMAT.format(new Date(logsFile.lastModified())) + ".zip"); zipLogsFile(logsFile, BASE_LOGS_FOLDER.relativize(logsFile.toPath()).toString(), dateLogsFileZipped); } AsyncFileHandler asyncFileHandler = new AsyncFileHandler(archiveFolder); asyncFileHandler.setFile(logsFile); asyncFileHandler.setLevel(Level.ALL); logger.addHandler(asyncFileHandler); } catch (IOException error) { error.printStackTrace(); } return logger; } private static void zipLogsFile(File file, String name, File zipFile) { zipFile.getParentFile().mkdirs(); try { File tempFile = new File(zipFile.getAbsolutePath() + ".tmp"); byte[] buffer = new byte[1024]; try (ZipInputStream zis = zipFile.exists() ? new ZipInputStream(new FileInputStream(zipFile)) : null; ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tempFile))) { ZipEntry entry; if (zis != null) { // Copy existing entries while ((entry = zis.getNextEntry()) != null) { ZipEntry newEntry = new ZipEntry(entry.getName()); zos.putNextEntry(newEntry); newEntry.setLastModifiedTime(entry.getLastModifiedTime()); int len; while ((len = zis.read(buffer)) != -1) { zos.write(buffer, 0, len); } zos.closeEntry(); } } // Create new zip entry ZipEntry zipEntry = new ZipEntry(name); zos.putNextEntry(zipEntry); zipEntry.setLastModifiedTime(FileTime.fromMillis(file.lastModified())); zipEntry.setLastAccessTime(FileTime.fromMillis(file.lastModified())); try (FileInputStream input = new FileInputStream(file)) { int length; while ((length = input.read(buffer)) >= 0) { zos.write(buffer, 0, length); } } zos.closeEntry(); } finally { zipFile.delete(); tempFile.renameTo(zipFile); } } catch (Throwable error) { error.printStackTrace(); } file.delete(); } private static class AsyncFileHandler extends Handler implements ModuleLogger.ModuleFileHandler { private final BlockingQueue queue = new LinkedBlockingQueue<>(10000); private final Thread worker; private final File archiveFolder; private FileHandler fileHandler; private File logsFile; private volatile boolean running = true; private volatile long nextDayTime; private AsyncFileHandler(File archiveFolder) throws IOException { this.archiveFolder = archiveFolder; calculateTimeOfNextDay(); this.worker = new Thread(() -> { try { while (running || !queue.isEmpty()) { LogRecord record = queue.poll(100, TimeUnit.MILLISECONDS); if (record != null) { if (System.currentTimeMillis() > nextDayTime) { // Upgrade file nextDayLogsFile(); } fileHandler.publish(record); } } } catch (InterruptedException ignored) { } finally { fileHandler.flush(); fileHandler.close(); } }, "AsyncLoggerThread"); this.worker.setDaemon(true); this.worker.start(); } private void calculateTimeOfNextDay() { this.nextDayTime = LocalDate.now().plusDays(1).atStartOfDay(ZoneOffset.systemDefault()).toEpochSecond() * 1000; } public void setFile(File file) throws IOException { file.createNewFile(); this.fileHandler = new FileHandler(file.getAbsolutePath(), true); this.fileHandler.setFormatter(new DebugFormatter()); this.logsFile = file; } private void nextDayLogsFile() { this.fileHandler.close(); this.fileHandler = null; File dateLogsFileZipped = new File(archiveFolder, ARCHIVE_DATE_FORMAT.format(new Date(logsFile.lastModified())) + ".zip"); zipLogsFile(logsFile, BASE_LOGS_FOLDER.relativize(logsFile.toPath()).toString(), dateLogsFileZipped); try { setFile(this.logsFile); } catch (Throwable error) { error.printStackTrace(); } calculateTimeOfNextDay(); } @Override public void publish(LogRecord record) { if (!running) return; this.queue.offer(record); } @Override public void flush() { this.fileHandler.flush(); } @Override public void close() throws SecurityException { running = false; try { this.worker.join(1000); } catch (InterruptedException ignored) { } } } private static class DebugFormatter extends Formatter { private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss"); @Override public String format(LogRecord record) { String time = DATE_FORMAT.format(new Date(record.getMillis())); String level = record.getLevel().getLocalizedName(); return String.format("[%s %s]: %s%n", time, level, formatMessage(record)); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java ================================================ package com.bgsoftware.superiorskyblock.module.missions; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.io.Resources; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandMembers; import com.bgsoftware.superiorskyblock.mission.SMissionCategory; import com.bgsoftware.superiorskyblock.module.BuiltinModule; import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.missions.commands.CmdAdminMission; import com.bgsoftware.superiorskyblock.module.missions.commands.CmdMission; import com.bgsoftware.superiorskyblock.module.missions.commands.CmdMissions; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.Listener; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.Map; public class MissionsModule extends BuiltinModule { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final String[] IGNORED_SECTIONS = new String[]{"categories"}; private static final int MAX_MISSIONS_NAME_LENGTH = 255; public MissionsModule() { super("missions"); } @Override protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { boolean updatedConfig = false; if (convertOldMissions(plugin, config)) updatedConfig = true; if (convertNonCategorizedMissions(plugin, config)) updatedConfig = true; generateDefaultMissionJars(); if (firstTime) { generateDefaultFiles(); } return updatedConfig; } @Override protected void onEnable(SuperiorSkyblockPlugin plugin) { // Do nothing } @Override public void onReload(SuperiorSkyblockPlugin plugin) { plugin.getMissions().saveMissionsData(); // Before we continue with the reload, we want to unload all the missions. plugin.getMissions().clearData(); super.onReload(plugin); onEnable(plugin); plugin.getMissions().loadMissionsData(); } @Override public void onDisable(SuperiorSkyblockPlugin plugin) { if (isEnabled()) plugin.getMissions().saveMissionsData(); } @Override public void loadData(SuperiorSkyblockPlugin plugin) { List> missionsToLoad = this.configuration.missionsToLoad; if (!missionsToLoad.isEmpty()) { plugin.getMissions().loadMissionsData(missionsToLoad); missionsToLoad.clear(); } } @Override public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { return null; } @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { return new SuperiorCommand[]{new CmdMission(), new CmdMissions()}; } @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { return new SuperiorCommand[]{new CmdAdminMission()}; } @Override protected String[] getIgnoredSections() { return IGNORED_SECTIONS; } @Override protected Configuration createConfigFile(CommentedConfiguration config) { return new Configuration(config); } public class Configuration implements IModuleConfiguration { private final boolean enabled; private final boolean autoRewardOutsideIslands; private final List> missionsToLoad = new LinkedList<>(); Configuration(CommentedConfiguration config) { this.enabled = config.getBoolean("enabled"); this.autoRewardOutsideIslands = config.getBoolean("auto-reward-outside-islands"); if (this.enabled) { loadMissionCategories(config); } } @Override public boolean isEnabled() { return this.enabled; } public boolean isAutoRewardOutsideIslands() { return this.autoRewardOutsideIslands; } private void loadMissionCategories(CommentedConfiguration config) { ConfigurationSection categoriesSection = config.getConfigurationSection("categories"); if (categoriesSection != null) { for (String categoryName : categoriesSection.getKeys(false)) { ConfigurationSection categorySection = categoriesSection.getConfigurationSection(categoryName); if (categorySection == null) continue; List> categoryMissions = new LinkedList<>(); if (!canLoadCategory(categoryName, categoryMissions)) continue; int slot = categorySection.getInt("slot"); String formattedCategoryName = categorySection.getString("name", categoryName); plugin.getMissions().loadMissionCategory(new SMissionCategory(formattedCategoryName, slot, categoryMissions)); missionsToLoad.addAll(categoryMissions); } } } private boolean canLoadCategory(String categoryName, List> categoryMissions) { File categoryFolder = new File(getModuleFolder(), "categories/" + categoryName); if (!categoryFolder.exists()) { logger().w("The directory of the mission category " + categoryName + " doesn't exist, skipping..."); return false; } if (!categoryFolder.isDirectory()) { logger().w("The directory of the mission category " + categoryName + " is not valid, skipping..."); return false; } File[] missionFiles = categoryFolder.listFiles(file -> file.isFile() && file.getName().endsWith(".yml")); if (missionFiles == null || missionFiles.length == 0) { logger().w("The mission category " + categoryName + " doesn't have missions, skipping..."); return false; } Map, Integer> missionWeights = new ArrayMap<>(); try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(getModuleFolder())) { for (File missionFile : missionFiles) { String missionName = missionFile.getName().replace(".yml", ""); if (missionName.length() > MAX_MISSIONS_NAME_LENGTH) missionName = missionName.substring(0, MAX_MISSIONS_NAME_LENGTH); YamlConfiguration missionConfigFile = new YamlConfiguration(); try { missionConfigFile.load(missionFile); } catch (InvalidConfigurationException error) { logger().e("A format-error occurred while parsing the mission file " + missionFile.getName() + ":", error); continue; } catch (IOException error) { logger().e("An unexpected error occurred while parsing the mission file " + missionFile.getName() + ":", error); continue; } ConfigurationSection missionSection = missionConfigFile.getConfigurationSection(""); Mission mission = plugin.getMissions().loadMission(missionName, categoryName, filesLookup, missionSection); if (mission != null) { categoryMissions.add(mission); missionWeights.put(mission, missionSection.getInt("weight", 0)); } } } if (categoryMissions.isEmpty()) { logger().w("The mission category " + categoryName + " doesn't have missions, skipping..."); return false; } // Sort missions by their names and weights. categoryMissions.sort(new MissionsComparator(missionWeights)); return true; } } @SuppressWarnings("ResultOfMethodCallIgnored") private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, YamlConfiguration config) { ConfigurationSection missionsSection = config.getConfigurationSection("missions"); if (missionsSection == null) return false; ConfigurationSection categoriesSection = config.createSection("categories"); MenuParseResult menuLoadResult = MenuParserImpl.getInstance().loadMenu("missions.yml", null); if (menuLoadResult == null) return false; MenuPatternSlots menuPatternSlots = menuLoadResult.getPatternSlots(); YamlConfiguration missionsMenuConfig = menuLoadResult.getConfig(); List islandsCategorySlot = menuPatternSlots.getSlots(missionsMenuConfig.getString("island-missions", "")); if (islandsCategorySlot.isEmpty()) { categoriesSection.set("islands.name", "Islands"); categoriesSection.set("islands.slot", islandsCategorySlot.get(0)); } List playersCategorySlot = menuPatternSlots.getSlots(missionsMenuConfig.getString("player-missions", "")); if (playersCategorySlot.isEmpty()) { categoriesSection.set("players.name", "Players"); categoriesSection.set("players.slot", playersCategorySlot.get(0)); } File islandsCategoryFile = new File(getModuleFolder(), "categories/islands"); File playersCategoryFile = new File(getModuleFolder(), "categories/players"); islandsCategoryFile.mkdirs(); playersCategoryFile.mkdirs(); for (String missionName : missionsSection.getKeys(false)) { ConfigurationSection missionSection = missionsSection.getConfigurationSection(missionName); if (missionSection == null) continue; boolean islandsMission = missionSection.getBoolean("island", false); File missionFile = new File(islandsMission ? islandsCategoryFile : playersCategoryFile, missionName + ".yml"); try { missionFile.createNewFile(); } catch (IOException error) { logger().e("An unexpected error occurred while converting non-categorized mission " + missionName + ":", error); continue; } YamlConfiguration missionConfigFile = new YamlConfiguration(); missionSection.getValues(true).forEach(missionConfigFile::set); try { missionConfigFile.save(missionFile); } catch (Exception error) { logger().e("An unexpected error occurred while saving non-categorized mission " + missionName + ":", error); } } config.set("missions", ""); copyOldMissionsMenuFile(plugin); return true; } @SuppressWarnings("ResultOfMethodCallIgnored") private boolean convertOldMissions(SuperiorSkyblockPlugin plugin, YamlConfiguration config) { boolean updatedConfig = false; File oldMissionsFolder = new File(plugin.getDataFolder(), "missions"); if (oldMissionsFolder.exists()) { File oldMissionsFile = new File(oldMissionsFolder, "missions.yml"); if (oldMissionsFile.exists()) { YamlConfiguration oldConfig = YamlConfiguration.loadConfiguration(oldMissionsFile); config.set("missions", oldConfig.getConfigurationSection("")); updatedConfig = true; oldMissionsFile.delete(); } for (File jarFile : Files.listFolderFiles(oldMissionsFolder, false, f -> f.getName().endsWith(".jar"))) { jarFile.renameTo(new File(getModuleFolder(), jarFile.getName())); } File oldDataFile = new File(oldMissionsFolder, "_data.yml"); if (oldDataFile.exists()) oldDataFile.renameTo(new File(getModuleFolder(), "_data.yml")); Files.deleteDirectory(oldMissionsFolder); } return updatedConfig; } private void copyOldMissionsMenuFile(SuperiorSkyblockPlugin plugin) { File oldMissionsMenuFile = new File(plugin.getDataFolder(), "menus/island-missions.yml"); File newMissionsCategoryMenuFile = new File(plugin.getDataFolder(), "menus/missions-category.yml"); try { java.nio.file.Files.copy(Paths.get(oldMissionsMenuFile.toURI()), Paths.get(newMissionsCategoryMenuFile.toURI())); } catch (IOException error) { logger().e("An unexpected error occurred while copying old missions-menu to the new format:", error); return; } YamlConfiguration newMissionsCategoryMenuConfig = YamlConfiguration.loadConfiguration(newMissionsCategoryMenuFile); newMissionsCategoryMenuConfig.set("title", "&l{0} Missions"); try { newMissionsCategoryMenuConfig.save(newMissionsCategoryMenuFile); } catch (IOException ignored) { } } private void generateDefaultFiles() { File categoriesFolder = new File(getModuleFolder(), "categories"); if ((!categoriesFolder.exists() || !categoriesFolder.isDirectory()) && categoriesFolder.mkdirs()) { Resources.saveResource("modules/missions/categories/farmer/farmer_1.yml"); Resources.saveResource("modules/missions/categories/farmer/farmer_2.yml"); Resources.saveResource("modules/missions/categories/farmer/farmer_3.yml"); Resources.saveResource("modules/missions/categories/farmer/farmer_4.yml"); Resources.saveResource("modules/missions/categories/farmer/farmer_5.yml"); Resources.saveResource("modules/missions/categories/miner/miner_1.yml"); Resources.saveResource("modules/missions/categories/miner/miner_2.yml"); Resources.saveResource("modules/missions/categories/miner/miner_3.yml"); Resources.saveResource("modules/missions/categories/miner/miner_4.yml"); Resources.saveResource("modules/missions/categories/miner/miner_5.yml"); Resources.saveResource("modules/missions/categories/slayer/slayer_1.yml"); Resources.saveResource("modules/missions/categories/slayer/slayer_2.yml"); Resources.saveResource("modules/missions/categories/slayer/slayer_3.yml"); Resources.saveResource("modules/missions/categories/slayer/slayer_4.yml"); Resources.saveResource("modules/missions/categories/fisherman/fisherman_1.yml"); Resources.saveResource("modules/missions/categories/fisherman/fisherman_2.yml"); Resources.saveResource("modules/missions/categories/fisherman/fisherman_3.yml"); Resources.saveResource("modules/missions/categories/explorer/explorer_1.yml"); Resources.saveResource("modules/missions/categories/explorer/explorer_2.yml"); } } private void generateDefaultMissionJars() { Resources.copyResource("modules/missions/BlocksMissions"); Resources.copyResource("modules/missions/BrewingMissions"); Resources.copyResource("modules/missions/CraftingMissions"); Resources.copyResource("modules/missions/EnchantingMissions"); Resources.copyResource("modules/missions/FarmingMissions"); Resources.copyResource("modules/missions/FishingMissions"); Resources.copyResource("modules/missions/IslandMissions"); Resources.copyResource("modules/missions/ItemsMissions"); Resources.copyResource("modules/missions/KillsMissions"); Resources.copyResource("modules/missions/StatisticsMissions"); } private static class MissionsComparator implements Comparator> { private final Map, Integer> missionWeights; public MissionsComparator(Map, Integer> missionWeights) { this.missionWeights = missionWeights; } @Override public int compare(Mission o1, Mission o2) { int firstWeight = this.missionWeights.getOrDefault(o1, 0); int secondWeight = this.missionWeights.getOrDefault(o2, 0); return firstWeight == secondWeight ? o1.getName().compareTo(o2.getName()) : Integer.compare(firstWeight, secondWeight); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java ================================================ package com.bgsoftware.superiorskyblock.module.missions.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class CmdAdminMission implements IAdminPlayerCommand { @Override public List getAliases() { return Collections.singletonList("mission"); } @Override public String getPermission() { return "superior.admin.mission"; } @Override public String getUsage(java.util.Locale locale) { return "admin mission <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MISSION_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_MISSIONS.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_MISSION.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultiplePlayers() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { List> missions = CommandArguments.getMultipleMissions(plugin, sender, args[4]); if (missions.isEmpty()) return; if (args[3].equalsIgnoreCase("complete")) { missions.forEach(mission -> plugin.getMissions().rewardMission(mission, targetPlayer, false, true)); if (missions.size() == 1) Message.MISSION_STATUS_COMPLETE.send(sender, missions.get(0).getName(), targetPlayer.getName()); else Message.MISSION_STATUS_COMPLETE_ALL.send(sender, targetPlayer.getName()); return; } else if (args[3].equalsIgnoreCase("reset")) { Island island = targetPlayer.getIsland(); int islandsChangedCount = 0; for (Mission mission : missions) { IMissionsHolder missionsHolder = mission.getIslandMission() ? island : targetPlayer; if (missionsHolder != null && PluginEventsFactory.callMissionResetEvent(sender, missionsHolder, mission)) { ++islandsChangedCount; missionsHolder.resetMission(mission); } } if (islandsChangedCount <= 0) return; if (missions.size() == 1) Message.MISSION_STATUS_RESET.send(sender, missions.get(0).getName(), targetPlayer.getName()); else Message.MISSION_STATUS_RESET_ALL.send(sender, targetPlayer.getName()); return; } Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + " " + getUsage(PlayerLocales.getLocale(sender))); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { if (args.length == 4) { return CommandTabCompletes.getCustomComplete(args[3], "complete", "reset"); } else if (args.length == 5) { List list = new LinkedList<>(); if (args[3].equalsIgnoreCase("complete")) list.addAll(CommandTabCompletes.getMissions(plugin, args[4], mission -> plugin.getMissions().canCompleteAgain(targetPlayer, mission))); else if (args[3].equalsIgnoreCase("reset")) list.addAll(CommandTabCompletes.getMissions(plugin, args[4], mission -> !plugin.getMissions().canCompleteAgain(targetPlayer, mission))); if ("*".contains(args[4]) && !list.isEmpty()) list.add("*"); return Collections.unmodifiableList(list); } return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMission.java ================================================ package com.bgsoftware.superiorskyblock.module.missions.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; public class CmdMission implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("mission", "challenge"); } @Override public String getPermission() { return "superior.island.mission"; } @Override public String getUsage(java.util.Locale locale) { return "mission complete <" + Message.COMMAND_ARGUMENT_MISSION_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_MISSION.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (!args[1].equalsIgnoreCase("complete")) { Locale locale = PlayerLocales.getLocale(sender); Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + " " + getUsage(locale)); return; } Mission mission = CommandArguments.getMission(plugin, superiorPlayer, args[2]); if (mission == null) return; List requiredMissions = mission.getRequiredMissions(); if (!requiredMissions.isEmpty()) { StringBuilder stringBuilder = new StringBuilder(); requiredMissions.forEach(requiredMission -> { Mission _mission = plugin.getMissions().getMission(requiredMission); if (_mission != null && plugin.getMissions().canCompleteAgain(superiorPlayer, _mission)) stringBuilder.append(_mission.getName()).append(", "); }); if (stringBuilder.length() != 0) { Message.MISSION_NOT_COMPLETE_REQUIRED_MISSIONS.send(superiorPlayer, stringBuilder.substring(0, stringBuilder.length() - 2)); return; } } if (!plugin.getMissions().canComplete(superiorPlayer, mission)) { Message.MISSION_CANNOT_COMPLETE.send(superiorPlayer); return; } try { plugin.getMissions().rewardMission(mission, superiorPlayer, false); } catch (IllegalStateException ex) { Message.INVALID_MISSION.send(superiorPlayer, args[2]); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], "complete") : args.length == 3 && args[1].equalsIgnoreCase("complete") ? CommandTabCompletes.getMissions(plugin, args[2], mission -> mission.canComplete(superiorPlayer)) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java ================================================ package com.bgsoftware.superiorskyblock.module.missions.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdMissions implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("missions", "challenges"); } @Override public String getPermission() { return "superior.island.missions"; } @Override public String getUsage(java.util.Locale locale) { return "missions [" + Message.COMMAND_ARGUMENT_MISSION_CATEGORY.getMessage(locale) + "]"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_MISSIONS.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (args.length == 1) { if (!superiorPlayer.hasIsland() && !plugin.getMissions().hasAnyPlayerMissionCategories()) { Message.INVALID_ISLAND.send(superiorPlayer); return; } plugin.getMenus().openMissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); } else { MissionCategory missionCategory = CommandArguments.getMissionCategory(plugin, sender, args[1]); if (missionCategory == null) return; if (!superiorPlayer.hasIsland() && !plugin.getMissions().isPlayerMissionCategory(missionCategory)) { Message.INVALID_ISLAND.send(superiorPlayer); return; } plugin.getMenus().openMissionsCategory(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), missionCategory); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { if (args.length == 2) { boolean hasIsland = plugin.getPlayers().getSuperiorPlayer(sender).hasIsland(); return CommandTabCompletes.getMissionCategories(plugin, args[1], category -> hasIsland || plugin.getMissions().isPlayerMissionCategory(category)); } return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoadException; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgrade; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import com.bgsoftware.superiorskyblock.island.upgrade.UpgradeRequirement; import com.bgsoftware.superiorskyblock.island.upgrade.container.IslandUpgrades; import com.bgsoftware.superiorskyblock.module.BuiltinModule; import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRankup; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetUpgrade; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSyncUpgrades; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdRankup; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdUpgrade; import com.bgsoftware.superiorskyblock.module.upgrades.type.IUpgradeType; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeBlockLimits; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeMobDrops; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeSpawnerRates; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.Listener; import org.bukkit.potion.PotionEffectType; import java.io.File; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.Set; import java.util.stream.Collectors; public class UpgradesModule extends BuiltinModule { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final String[] IGNORED_SECTIONS = new String[]{"upgrades"}; private static final int MAX_UPGRADES_NAME_LENGTH = 255; private final Map, IUpgradeType> classToUpgrade = new IdentityHashMap<>(); public UpgradesModule() { super("upgrades"); } @Override protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { File oldUpgradesFile = new File(plugin.getDataFolder(), "upgrades.yml"); boolean updatedConfig = false; if (oldUpgradesFile.exists()) { CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldUpgradesFile); if (oldConfig.isConfigurationSection("upgrades")) config.set("upgrades", oldConfig.getConfigurationSection("upgrades")); oldUpgradesFile.delete(); } if (!config.isBoolean("enabled")) { boolean status = false; if (config.getBoolean("crop-growth", true)) status = true; else if (config.getBoolean("mob-drops", true)) status = true; else if (config.getBoolean("island-effects", true)) status = true; else if (config.getBoolean("spawner-rates", true)) status = true; else if (config.getBoolean("block-limits", true)) status = true; else if (config.getBoolean("entity-limits", true)) status = true; config.set("enabled", status); updatedConfig = true; } return updatedConfig; } @Override public void onEnable(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public void onDisable(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public void loadData(SuperiorSkyblockPlugin plugin) { // Do nothing. } @Override public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { List listenersList = new ArrayList<>(); for (IUpgradeType upgradeType : this.configuration.enabledUpgrades) { listenersList.addAll(upgradeType.getListeners()); } return listenersList.toArray(new Listener[0]); } @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { return new SuperiorCommand[]{new CmdRankup(), new CmdUpgrade()}; } @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { List adminCommands = this.configuration.enabledUpgrades.stream() .map(IUpgradeType::getCommands) .flatMap(List::stream) .collect(Collectors.toList()); adminCommands.add(new CmdAdminRankup()); adminCommands.add(new CmdAdminSetUpgrade()); adminCommands.add(new CmdAdminSyncUpgrades()); return adminCommands.toArray(new SuperiorCommand[0]); } @Override protected String[] getIgnoredSections() { return IGNORED_SECTIONS; } @Override protected Configuration createConfigFile(CommentedConfiguration config) { this.classToUpgrade.clear(); Configuration configuration = new Configuration(config); for (IUpgradeType enabledUpgrade : configuration.enabledUpgrades) { this.classToUpgrade.put(enabledUpgrade.getClass(), enabledUpgrade); } return configuration; } @Nullable public T getEnabledUpgradeType(Class clazz) { IUpgradeType enabledUpgrade = this.classToUpgrade.get(clazz); return enabledUpgrade == null ? null : (T) enabledUpgrade; } public boolean isUpgradeTypeEnabled(Class clazz) { return getEnabledUpgradeType(clazz) != null; } public class Configuration implements IModuleConfiguration { private final boolean enabled; private final List enabledUpgrades = new LinkedList<>(); Configuration(CommentedConfiguration config) { this.enabled = config.getBoolean("enabled", true); loadUpgrades(config); } @Override public boolean isEnabled() { return this.enabled; } private void loadUpgrades(CommentedConfiguration config) { plugin.getUpgrades().clearUpgrades(); if (!enabled) return; if (config.getBoolean("crop-growth", true)) enabledUpgrades.add(new UpgradeTypeCropGrowth(plugin)); if (config.getBoolean("mob-drops", true)) enabledUpgrades.add(new UpgradeTypeMobDrops(plugin)); if (config.getBoolean("island-effects", true)) enabledUpgrades.add(new UpgradeTypeIslandEffects(plugin)); if (config.getBoolean("spawner-rates", true)) enabledUpgrades.add(new UpgradeTypeSpawnerRates(plugin)); if (config.getBoolean("block-limits", true)) enabledUpgrades.add(new UpgradeTypeBlockLimits(plugin)); if (config.getBoolean("entity-limits", true)) enabledUpgrades.add(new UpgradeTypeEntityLimits(plugin)); ConfigurationSection upgrades = config.getConfigurationSection("upgrades"); if (upgrades != null) { for (String upgradeName : upgrades.getKeys(false)) { if (upgradeName.length() > MAX_UPGRADES_NAME_LENGTH) upgradeName = upgradeName.substring(0, MAX_UPGRADES_NAME_LENGTH); SUpgrade upgrade = new SUpgrade(upgradeName); for (String _level : upgrades.getConfigurationSection(upgradeName).getKeys(false)) { loadUpgradeLevelFromSection(plugin, upgrade, _level, upgrades.getConfigurationSection(upgradeName + "." + _level)); } plugin.getUpgrades().addUpgrade(upgrade); } } IslandUpgrades.onUpgradesUpdate(); } } private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade upgrade, String sectionName, ConfigurationSection levelSection) { int level = Integer.parseInt(sectionName); String priceType = levelSection.getString("price-type", "money"); UpgradeCostLoader costLoader = plugin.getUpgrades().getUpgradeCostLoader(priceType); if (costLoader == null) { this.logger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has invalid price-type. Skipping..."); return; } UpgradeCost upgradeCost; try { upgradeCost = costLoader.loadCost(levelSection); } catch (UpgradeCostLoadException error) { this.logger().e("Upgrade by name " + upgrade.getName() + " (level " + level + ") failed to initialize:", error); return; } List commands = levelSection.getStringList("commands"); String permission = levelSection.getString("permission", ""); Set requirements = new HashSet<>(); for (String line : levelSection.getStringList("required-checks")) { String[] sections = line.split(";"); requirements.add(new UpgradeRequirement(sections[0], Formatters.COLOR_FORMATTER.format(sections[1]))); } Value cropGrowth = Value.syncedFixed(readDouble(levelSection, "crop-growth")); Value spawnerRates = Value.syncedFixed(readDouble(levelSection, "spawner-rates")); Value mobDrops = Value.syncedFixed(readDouble(levelSection, "mob-drops")); Value teamLimit = Value.syncedFixed(readInt(levelSection, "team-limit")); Value warpsLimit = Value.syncedFixed(readInt(levelSection, "warps-limit")); Value coopLimit = Value.syncedFixed(readInt(levelSection, "coop-limit")); Value borderSize = Value.syncedFixed(readInt(levelSection, "border-size")); if (borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE) > plugin.getSettings().getMaxIslandSize()) { this.logger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has illegal border-size, skipping..."); return; } Value> bankLimit = Value.syncedFixed(readString(levelSection, "bank-limit").map(BigDecimal::new)); KeyMap blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); if (levelSection.isConfigurationSection("block-limits")) { for (String block : levelSection.getConfigurationSection("block-limits").getKeys(false)) { Key blockKey = Keys.ofMaterialAndData(block); blockLimits.put(blockKey, levelSection.getInt("block-limits." + block)); plugin.getBlockValues().addCustomBlockKey(blockKey); } } KeyMap entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); if (levelSection.isConfigurationSection("entity-limits")) { for (String entity : levelSection.getConfigurationSection("entity-limits").getKeys(false)) entityLimits.put(Keys.ofEntityType(entity), levelSection.getInt("entity-limits." + entity)); } EnumerateMap> generatorRates = new EnumerateMap<>(Dimension.values()); if (levelSection.isConfigurationSection("generator-rates")) { for (String blockOrEnv : levelSection.getConfigurationSection("generator-rates").getKeys(false)) { try { Dimension dimension = Dimension.getByName(blockOrEnv.toUpperCase(Locale.ENGLISH)); for (String block : levelSection.getConfigurationSection("generator-rates." + blockOrEnv).getKeys(false)) { generatorRates.computeIfAbsent(dimension, e -> KeyMaps.createArrayMap(KeyIndicator.MATERIAL)).put( Keys.ofMaterialAndData(block), levelSection.getInt("generator-rates." + blockOrEnv + "." + block)); } } catch (Exception ex) { generatorRates.computeIfAbsent(plugin.getSettings().getWorlds().getDefaultWorldDimension(), e -> KeyMaps.createArrayMap(KeyIndicator.MATERIAL)) .put(Keys.ofMaterialAndData(blockOrEnv), levelSection.getInt("generator-rates." + blockOrEnv)); } } } Map islandEffects = new ArrayMap<>(); if (levelSection.isConfigurationSection("island-effects")) { for (String effect : levelSection.getConfigurationSection("island-effects").getKeys(false)) { PotionEffectType potionEffectType = PotionEffectType.getByName(effect); if (potionEffectType != null) islandEffects.put(potionEffectType, levelSection.getInt("island-effects." + effect) - 1); } } Int2IntMapView rolesLimits = CollectionsFactory.createInt2IntArrayMap(); if (levelSection.isConfigurationSection("role-limits")) { for (String roleId : levelSection.getConfigurationSection("role-limits").getKeys(false)) { try { rolesLimits.put(Integer.parseInt(roleId), levelSection.getInt("role-limits." + roleId)); } catch (NumberFormatException ignored) { } } } SUpgradeLevel upgradeLevel = new SUpgradeLevel(level, upgradeCost, commands, permission, requirements, cropGrowth, spawnerRates, mobDrops, teamLimit, warpsLimit, coopLimit, borderSize, Value.syncedFixed(blockLimits), Value.syncedFixed(entityLimits), Value.syncedFixed(generatorRates), Value.syncedFixed(islandEffects), bankLimit, Value.syncedFixed(rolesLimits)); upgrade.addUpgradeLevel(level, upgradeLevel); } private static OptionalDouble readDouble(ConfigurationSection section, String key) { if (section.contains(key)) return OptionalDouble.of(section.getDouble(key)); return OptionalDouble.empty(); } private static OptionalInt readInt(ConfigurationSection section, String key) { if (section.contains(key)) return OptionalInt.of(section.getInt(key)); return OptionalInt.empty(); } private static Optional readString(ConfigurationSection section, String key) { if (section.contains(key)) return Optional.of(section.getString(key)); return Optional.empty(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddBlockLimit.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddBlockLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addblocklimit"); } @Override public String getPermission() { return "superior.admin.addblocklimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin addblocklimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key key = Keys.ofMaterialAndData(args[3]); NumberArgument arguments = CommandArguments.getLimit(sender, args[4]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeBlockLimitEvent(island, sender, key, island.getBlockLimit(key) + limit); if (!event.isCancelled()) { island.setBlockLimit(key, event.getArgs().blockLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName()); else Message.CHANGED_BLOCK_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getMaterials(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddCropGrowth.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddCropGrowth implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addcropgrowth"); } @Override public String getPermission() { return "superior.admin.addcropgrowth"; } @Override public String getUsage(java.util.Locale locale) { return "admin addcropgrowth <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getMultiplier(sender, args[3]); if (!arguments.isSucceed()) return; double multiplier = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeCropGrowthEvent( island, sender, island.getCropGrowthMultiplier() + multiplier); if (!event.isCancelled()) { island.setCropGrowthMultiplier(event.getArgs().cropGrowth); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_CROP_GROWTH_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_CROP_GROWTH_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_CROP_GROWTH.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEffect.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import org.bukkit.potion.PotionEffectType; import java.util.Collections; import java.util.List; public class CmdAdminAddEffect implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addeffect"); } @Override public String getPermission() { return "superior.admin.addeffect"; } @Override public String getUsage(java.util.Locale locale) { return "admin addeffect <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_EFFECT.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LEVEL.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { PotionEffectType effectType = CommandArguments.getPotionEffect(sender, args[3]); if (effectType == null) return; NumberArgument arguments = CommandArguments.getLevel(sender, args[4]); if (!arguments.isSucceed()) return; int level = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { int newLevel = island.getPotionEffectLevel(effectType) + level; if (newLevel <= 0) { if (PluginEventsFactory.callIslandRemoveEffectEvent(island, sender, effectType)) { ++islandsChangedCount; island.removePotionEffect(effectType); } } else { PluginEvent event = PluginEventsFactory.callIslandChangeEffectLevelEvent( island, sender, effectType, newLevel); if (!event.isCancelled()) { island.setPotionEffect(effectType, event.getArgs().effectLevel); ++islandsChangedCount; } } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_ISLAND_EFFECT_LEVEL_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName())); else if (targetPlayer == null) Message.CHANGED_ISLAND_EFFECT_LEVEL_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), islands.get(0).getName()); else Message.CHANGED_ISLAND_EFFECT_LEVEL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getPotionEffects(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEntityLimit.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddEntityLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addentitylimit"); } @Override public String getPermission() { return "superior.admin.addentitylimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin addentitylimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_ENTITY.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key entityKey = Keys.ofEntityType(args[3]); NumberArgument arguments = CommandArguments.getLimit(sender, args[4]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeEntityLimitEvent( island, sender, entityKey, island.getEntityLimit(entityKey) + limit); if (!event.isCancelled()) { island.setEntityLimit(entityKey, event.getArgs().entityLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), islands.get(0).getName()); else Message.CHANGED_ENTITY_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getEntitiesForLimit(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddMobDrops.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddMobDrops implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addmobdrops"); } @Override public String getPermission() { return "superior.admin.addmobdrops"; } @Override public String getUsage(java.util.Locale locale) { return "admin addmobdrops <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getMultiplier(sender, args[3]); if (!arguments.isSucceed()) return; double multiplier = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeMobDropsEvent( island, sender, island.getMobDropsMultiplier() + multiplier); if (!event.isCancelled()) { island.setMobDropsMultiplier(event.getArgs().mobDrops); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_MOB_DROPS_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_MOB_DROPS_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_MOB_DROPS.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddSpawnerRates.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminAddSpawnerRates implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("addspawnerrates"); } @Override public String getPermission() { return "superior.admin.addspawnerrates"; } @Override public String getUsage(java.util.Locale locale) { return "admin addspawnerrates <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getMultiplier(sender, args[3]); if (!arguments.isSucceed()) return; double multiplier = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeSpawnerRatesEvent( island, sender, island.getSpawnerRatesMultiplier() + multiplier); if (!event.isCancelled()) { island.setSpawnerRatesMultiplier(event.getArgs().spawnerRates); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_SPAWNER_RATES_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_SPAWNER_RATES_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_SPAWNER_RATES.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRankup.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; public class CmdAdminRankup implements IAdminIslandCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; @Override public List getAliases() { return Collections.singletonList("rankup"); } @Override public String getPermission() { return "superior.admin.rankup"; } @Override public String getUsage(java.util.Locale locale) { return "admin rankup <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_UPGRADE_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_RANKUP.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Upgrade upgrade = CommandArguments.getUpgrade(plugin, sender, args[3]); if (upgrade == null) return; SuperiorPlayer playerSender = sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null; islands.forEach(island -> { UpgradeLevel currentLevel = island.getUpgradeLevel(upgrade); UpgradeLevel nextLevel = upgrade.getUpgradeLevel(currentLevel.getLevel() + 1); PluginEvent event = PluginEventsFactory.callIslandUpgradeEvent( island, playerSender, upgrade, currentLevel, nextLevel, IslandUpgradeEvent.Cause.PLAYER_RANKUP); if (!event.isCancelled()) { SuperiorPlayer owner = island.getOwner(); for (String command : event.getArgs().commands) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), placeholdersService.get().parsePlaceholders(owner.asOfflinePlayer(), command .replace("%player%", owner.getName()) .replace("%leader%", owner.getName())) ); } } }); if (islands.size() > 1) Message.RANKUP_SUCCESS_ALL.send(sender, upgrade.getName()); else if (targetPlayer == null) Message.RANKUP_SUCCESS_NAME.send(sender, upgrade.getName(), islands.get(0).getName()); else Message.RANKUP_SUCCESS.send(sender, upgrade.getName(), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getUpgrades(plugin, args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveBlockLimit.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminRemoveBlockLimit implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("removeblocklimit", "remblocklimit"); } @Override public String getPermission() { return "superior.admin.removeblocklimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin removeblocklimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key key = Keys.ofMaterialAndData(args[3]); int islandsChangedCount = 0; for (Island island : islands) { if (PluginEventsFactory.callIslandRemoveBlockLimitEvent(island, sender, key)) { ++islandsChangedCount; island.removeBlockLimit(key); } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName()); else Message.CHANGED_BLOCK_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getMaterials(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveEntityLimit.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdAdminRemoveEntityLimit implements IAdminIslandCommand { @Override public List getAliases() { return Arrays.asList("removeentitylimit", "rementitylimit"); } @Override public String getPermission() { return "superior.admin.removeentitylimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin removeentitylimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_ENTITY.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key key = Keys.ofEntityType(args[3]); int islandsChangedCount = 0; for (Island island : islands) { if (PluginEventsFactory.callIslandRemoveEntityLimitEvent(island, sender, key)) { ++islandsChangedCount; island.removeEntityLimit(key); } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName()); else Message.CHANGED_ENTITY_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getEntitiesForLimit(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetBlockLimit.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetBlockLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setblocklimit"); } @Override public String getPermission() { return "superior.admin.setblocklimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin setblocklimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key key = Keys.ofMaterialAndData(args[3]); NumberArgument arguments = CommandArguments.getLimit(sender, args[4]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeBlockLimitEvent(island, sender, key, limit); if (!event.isCancelled()) { island.setBlockLimit(key, event.getArgs().blockLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName()); else Message.CHANGED_BLOCK_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getMaterials(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetCropGrowth.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetCropGrowth implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setcropgrowth"); } @Override public String getPermission() { return "superior.admin.setcropgrowth"; } @Override public String getUsage(java.util.Locale locale) { return "admin setcropgrowth <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getMultiplier(sender, args[3]); if (!arguments.isSucceed()) return; double multiplier = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeCropGrowthEvent( island, sender, multiplier); if (!event.isCancelled()) { island.setCropGrowthMultiplier(event.getArgs().cropGrowth); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_CROP_GROWTH_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_CROP_GROWTH_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_CROP_GROWTH.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEffect.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import org.bukkit.potion.PotionEffectType; import java.util.Collections; import java.util.List; public class CmdAdminSetEffect implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("seteffect"); } @Override public String getPermission() { return "superior.admin.seteffect"; } @Override public String getUsage(java.util.Locale locale) { return "admin seteffect <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_EFFECT.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LEVEL.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_EFFECT.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { PotionEffectType effectType = CommandArguments.getPotionEffect(sender, args[3]); if (effectType == null) return; NumberArgument arguments = CommandArguments.getLevel(sender, args[4]); if (!arguments.isSucceed()) return; int level = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { if (level <= 0) { if (PluginEventsFactory.callIslandRemoveEffectEvent(island, sender, effectType)) { ++islandsChangedCount; island.removePotionEffect(effectType); } } else { PluginEvent event = PluginEventsFactory.callIslandChangeEffectLevelEvent( island, sender, effectType, level); if (!event.isCancelled()) { island.setPotionEffect(effectType, event.getArgs().effectLevel); ++islandsChangedCount; } } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_ISLAND_EFFECT_LEVEL_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName())); else if (targetPlayer == null) Message.CHANGED_ISLAND_EFFECT_LEVEL_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), islands.get(0).getName()); else Message.CHANGED_ISLAND_EFFECT_LEVEL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getPotionEffects(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEntityLimit.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetEntityLimit implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setentitylimit"); } @Override public String getPermission() { return "superior.admin.setentitylimit"; } @Override public String getUsage(java.util.Locale locale) { return "admin setentitylimit <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_ENTITY.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key entityKey = Keys.ofEntityType(args[3]); NumberArgument arguments = CommandArguments.getLimit(sender, args[4]); if (!arguments.isSucceed()) return; int limit = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeEntityLimitEvent( island, sender, entityKey, limit); if (!event.isCancelled()) { island.setEntityLimit(entityKey, event.getArgs().entityLimit); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), islands.get(0).getName()); else Message.CHANGED_ENTITY_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getEntitiesForLimit(args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetMobDrops.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetMobDrops implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setmobdrops"); } @Override public String getPermission() { return "superior.admin.setmobdrops"; } @Override public String getUsage(java.util.Locale locale) { return "admin setmobdrops <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getMultiplier(sender, args[3]); if (!arguments.isSucceed()) return; double multiplier = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeMobDropsEvent( island, sender, multiplier); if (!event.isCancelled()) { island.setMobDropsMultiplier(event.getArgs().mobDrops); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_MOB_DROPS_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_MOB_DROPS_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_MOB_DROPS.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetSpawnerRates.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetSpawnerRates implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setspawnerrates"); } @Override public String getPermission() { return "superior.admin.setspawnerrates"; } @Override public String getUsage(java.util.Locale locale) { return "admin setspawnerrates <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MULTIPLIER.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES.getMessage(locale); } @Override public int getMinArgs() { return 4; } @Override public int getMaxArgs() { return 4; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { NumberArgument arguments = CommandArguments.getMultiplier(sender, args[3]); if (!arguments.isSucceed()) return; double multiplier = arguments.getNumber(); int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandChangeSpawnerRatesEvent( island, sender, multiplier); if (!event.isCancelled()) { island.setSpawnerRatesMultiplier(event.getArgs().spawnerRates); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.CHANGED_SPAWNER_RATES_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_SPAWNER_RATES_NAME.send(sender, islands.get(0).getName()); else Message.CHANGED_SPAWNER_RATES.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSetUpgrade implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("setupgrade"); } @Override public String getPermission() { return "superior.admin.setupgrade"; } @Override public String getUsage(java.util.Locale locale) { return "admin setupgrade <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_UPGRADE_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LEVEL.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE.getMessage(locale); } @Override public int getMinArgs() { return 5; } @Override public int getMaxArgs() { return 5; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Upgrade upgrade = CommandArguments.getUpgrade(plugin, sender, args[3]); if (upgrade == null) return; NumberArgument arguments = CommandArguments.getLevel(sender, args[4]); if (!arguments.isSucceed()) return; int level = arguments.getNumber(); int maxLevel = upgrade.getMaxUpgradeLevel(); if (level > maxLevel) { Message.MAXIMUM_LEVEL.send(sender, maxLevel); return; } int islandsChangedCount = 0; for (Island island : islands) { PluginEvent event = PluginEventsFactory.callIslandUpgradeEvent( island, sender, upgrade, upgrade.getUpgradeLevel(level), IslandUpgradeEvent.Cause.ADMIN_SET_UPGRADE); if (!event.isCancelled()) { island.setUpgradeLevel(upgrade, level); ++islandsChangedCount; } } if (islandsChangedCount <= 0) return; if (islandsChangedCount > 1) Message.SET_UPGRADE_LEVEL_ALL.send(sender, upgrade.getName()); else if (targetPlayer == null) Message.SET_UPGRADE_LEVEL_NAME.send(sender, upgrade.getName(), islands.get(0).getName()); else Message.SET_UPGRADE_LEVEL.send(sender, upgrade.getName(), targetPlayer.getName()); } @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getUpgrades(plugin, args[3]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSyncUpgrades.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; import java.util.List; public class CmdAdminSyncUpgrades implements IAdminIslandCommand { @Override public List getAliases() { return Collections.singletonList("syncupgrades"); } @Override public String getPermission() { return "superior.admin.syncupgrades"; } @Override public String getUsage(java.util.Locale locale) { return "admin syncupgrades <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES.getMessage(locale); } @Override public int getMinArgs() { return 3; } @Override public int getMaxArgs() { return 3; } @Override public boolean canBeExecutedByConsole() { return true; } @Override public boolean supportMultipleIslands() { return true; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { islands.forEach(Island::syncUpgrades); if (islands.size() > 1) Message.SYNC_UPGRADES_ALL.send(sender); else if (targetPlayer == null) Message.SYNC_UPGRADES_NAME.send(sender, islands.get(0).getName()); else Message.SYNC_UPGRADES.send(sender, targetPlayer.getName()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import org.bukkit.Bukkit; import java.time.Duration; import java.util.Collections; import java.util.List; public class CmdRankup implements IPermissibleCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override protected PlaceholdersService create() { return plugin.getServices().getService(PlaceholdersService.class); } }; @Override public List getAliases() { return Collections.singletonList("rankup"); } @Override public String getPermission() { return "superior.island.rankup"; } @Override public String getUsage(java.util.Locale locale) { return "rankup <" + Message.COMMAND_ARGUMENT_UPGRADE_NAME.getMessage(locale) + ">"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_RANKUP.getMessage(locale); } @Override public int getMinArgs() { return 2; } @Override public int getMaxArgs() { return 2; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public IslandPrivilege getPrivilege() { return IslandPrivileges.RANKUP; } @Override public Message getPermissionLackMessage() { return Message.NO_RANKUP_PERMISSION; } @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { Upgrade upgrade = CommandArguments.getUpgrade(plugin, superiorPlayer, args[1]); if (upgrade == null) return; UpgradeLevel currentLevel = island.getUpgradeLevel(upgrade); UpgradeLevel nextLevel = upgrade.getUpgradeLevel(currentLevel.getLevel() + 1); String permission = nextLevel == null ? "" : nextLevel.getPermission(); if (!permission.isEmpty() && !superiorPlayer.hasPermission(permission)) { Message.NO_UPGRADE_PERMISSION.send(superiorPlayer); return; } boolean hasNextLevel; if (island.hasActiveUpgradeCooldown()) { long timeNow = System.currentTimeMillis(); long lastUpgradeTime = island.getLastTimeUpgrade(); long duration = lastUpgradeTime + plugin.getSettings().getUpgradeCooldown() - timeNow; Message.UPGRADE_COOLDOWN_FORMAT.send(superiorPlayer, Formatters.TIME_FORMATTER.format( Duration.ofMillis(duration), superiorPlayer.getUserLocale())); hasNextLevel = false; } else { String requiredCheckFailure = nextLevel == null ? "" : nextLevel.checkRequirements(superiorPlayer); if (!requiredCheckFailure.isEmpty()) { Message.CUSTOM.send(superiorPlayer, requiredCheckFailure, false); hasNextLevel = false; } else { PluginEvent event = PluginEventsFactory.callIslandUpgradeEvent( island, superiorPlayer, upgrade, currentLevel, nextLevel, IslandUpgradeEvent.Cause.PLAYER_RANKUP); UpgradeCost upgradeCost = event.getArgs().upgradeCost; if (event.isCancelled()) { hasNextLevel = false; } else if (!upgradeCost.hasEnoughBalance(superiorPlayer)) { Message.NOT_ENOUGH_MONEY_TO_UPGRADE.send(superiorPlayer); hasNextLevel = false; } else { upgradeCost.withdrawCost(superiorPlayer); for (String command : event.getArgs().commands) { String parsedCommand = placeholdersService.get().parsePlaceholders(superiorPlayer.asOfflinePlayer(), command .replace("%player%", superiorPlayer.getName()) .replace("%leader%", island.getOwner().getName())); try { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsedCommand); } catch (Throwable error) { ModuleLogger logger = (ModuleLogger) BuiltinModules.UPGRADES.getLogger(); logger.e("An unexpected error occurred while executing command:\n" + parsedCommand, error); } } hasNextLevel = true; } } } SUpgradeLevel.ItemData itemData = ((SUpgradeLevel) currentLevel).getItemData(); if (itemData != null) { GameSound sound = hasNextLevel ? itemData.hasNextLevelSound : itemData.noNextLevelSound; if (sound != null) superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, sound)); } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { return args.length == 2 ? CommandTabCompletes.getUpgrades(plugin, args[1]) : Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdUpgrade.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; import java.util.Collections; import java.util.List; public class CmdUpgrade implements ISuperiorCommand { @Override public List getAliases() { return Arrays.asList("upgrade", "upgrades"); } @Override public String getPermission() { return "superior.island.upgrade"; } @Override public String getUsage(java.util.Locale locale) { return "upgrade"; } @Override public String getDescription(java.util.Locale locale) { return Message.COMMAND_DESCRIPTION_UPGRADE.getMessage(locale); } @Override public int getMinArgs() { return 1; } @Override public int getMaxArgs() { return 1; } @Override public boolean canBeExecutedByConsole() { return false; } @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); Island island = arguments.getIsland(); if (island == null) return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); plugin.getMenus().openUpgrades(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { return Collections.emptyList(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/IUpgradeType.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.type; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.event.Listener; import java.util.List; public interface IUpgradeType { List getListeners(); List getCommands(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.type; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddBlockLimit; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRemoveBlockLimit; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetBlockLimit; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockGrowEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.material.Directional; import org.bukkit.material.MaterialData; import java.util.Arrays; import java.util.Collections; import java.util.List; public class UpgradeTypeBlockLimits implements IUpgradeType { private final SuperiorSkyblockPlugin plugin; public UpgradeTypeBlockLimits(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public List getListeners() { return Collections.singletonList(new BlockLimitsListener()); } @Override public List getCommands() { return Arrays.asList(new CmdAdminAddBlockLimit(), new CmdAdminRemoveBlockLimit(), new CmdAdminSetBlockLimit()); } private class BlockLimitsListener implements Listener { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBlockPlace(BlockPlaceEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlockPlaced().getLocation(wrapper.getHandle())); } if (island == null) return; Key blockKey = Keys.of(e.getBlock()); if (island.hasReachedBlockLimit(blockKey)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPlayerRightClickBlock(PlayerInteractEvent e) { if (e.getAction() != Action.RIGHT_CLICK_BLOCK) return; PlayerHand playerHand = BukkitItems.getHand(e); if (playerHand != PlayerHand.MAIN_HAND) return; ItemStack handItem = BukkitItems.getHandItem(e.getPlayer(), playerHand); if (handItem == null) return; Material clickedBlockType = e.getClickedBlock().getType(); if (onCartPlaceInternal(e, clickedBlockType, handItem) || onSpawnerChangeInternal(e, clickedBlockType, handItem)) e.setCancelled(true); } private boolean onCartPlaceInternal(PlayerInteractEvent e, Material clickedBlockType, ItemStack handItem) { if (!Materials.isRail(clickedBlockType)) return false; Material handItemType = handItem.getType(); if (!Materials.isMinecart(handItemType)) return false; MutableObject minecraftKey = new MutableObject<>(null); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventMinecartPlace(handItemType, e.getClickedBlock().getLocation(wrapper.getHandle()), minecraftKey)) { Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format( minecraftKey.getValue().getGlobalKey())); return true; } } return false; } private boolean onSpawnerChangeInternal(PlayerInteractEvent e, Material clickedBlockType, ItemStack handItem) { if (clickedBlockType != Materials.SPAWNER.toBukkitType()) return false; Material handItemType = handItem.getType(); if (!Materials.isSpawnEgg(handItemType)) return false; Key oldSpawnerKey = Keys.of(e.getClickedBlock()); Key newSpawnerKey = Keys.ofSpawner(BukkitItems.getEntityType(e.getItem())); if (oldSpawnerKey.equals(newSpawnerKey)) return false; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle())); } if (island == null) return false; try { island.handleBlockBreak(oldSpawnerKey, 1, 0); if (island.hasReachedBlockLimit(newSpawnerKey)) { Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(newSpawnerKey.toString())); return true; } } finally { island.handleBlockPlace(oldSpawnerKey, 1, 0); } return false; } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) private void onMinecartPlaceByDispenser(BlockDispenseEvent e) { Material dispenseItemType = e.getItem().getType(); if (!Materials.isMinecart(dispenseItemType) || e.getBlock().getType() != Material.DISPENSER) return; Block targetBlock = null; if (ServerVersion.isLegacy()) { MaterialData materialData = e.getBlock().getState().getData(); if (materialData instanceof Directional) { targetBlock = e.getBlock().getRelative(((Directional) materialData).getFacing()); } } else { Object blockData = plugin.getNMSWorld().getBlockData(e.getBlock()); if (blockData instanceof org.bukkit.block.data.Directional) { targetBlock = e.getBlock().getRelative(((org.bukkit.block.data.Directional) blockData).getFacing()); } } if (targetBlock == null) return; if (!Materials.isRail(targetBlock.getType())) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventMinecartPlace(dispenseItemType, targetBlock.getLocation(wrapper.getHandle()), null)) e.setCancelled(true); } } private boolean preventMinecartPlace(Material minecartType, Location location, @Nullable MutableObject minecraftKey) { Island island = plugin.getGrid().getIslandAt(location); if (island == null) return false; Key key = null; switch (minecartType.name()) { case "HOPPER_MINECART": key = ConstantKeys.HOPPER; break; case "COMMAND_MINECART": case "COMMAND_BLOCK_MINECART": key = ConstantKeys.COMMAND_BLOCK; break; case "EXPLOSIVE_MINECART": case "TNT_MINECART": key = ConstantKeys.TNT; break; case "POWERED_MINECART": case "FURNACE_MINECART": key = ConstantKeys.FURNACE; break; case "STORAGE_MINECART": case "CHEST_MINECART": key = ConstantKeys.CHEST; break; } if (key != null && island.hasReachedBlockLimit(key)) { if (minecraftKey != null) minecraftKey.setValue(key); return true; } return false; } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBucketEmpty(PlayerBucketEmptyEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlockClicked().getLocation(wrapper.getHandle())); } if (island == null) return; Key blockKey = Keys.ofMaterialAndData(e.getBucket().name().replace("_BUCKET", "")); if (island.hasReachedBlockLimit(blockKey)) { e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBlockGrow(BlockGrowEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } if (island == null) return; Key blockKey = Keys.of(e.getNewState()); if (island.hasReachedBlockLimit(blockKey)) e.setCancelled(true); } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onStructureGrow(StructureGrowEvent e) { Island island = plugin.getGrid().getIslandAt(e.getLocation()); if (island == null) return; e.getBlocks().removeIf(blockState -> island.hasReachedBlockLimit(Keys.of(blockState))); } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBlockForm(BlockFormEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); } if (island == null) return; Key blockKey = Keys.of(e.getNewState()); if (island.hasReachedBlockLimit(blockKey)) { e.setCancelled(true); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.type; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetCropGrowth; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockGrowEvent; import java.util.Arrays; import java.util.Collections; import java.util.List; public class UpgradeTypeCropGrowth implements IUpgradeType { private final SuperiorSkyblockPlugin plugin; public UpgradeTypeCropGrowth(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public List getListeners() { return Collections.singletonList(new CropGrowthListener()); } @Override public List getCommands() { return Arrays.asList(new CmdAdminAddCropGrowth(), new CmdAdminSetCropGrowth()); } private class CropGrowthListener implements Listener { // Should potentially fix crop growth tile entities "disappearing" @EventHandler(priority = EventPriority.LOWEST) public void onBlockGrow(BlockGrowEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(blockLocation); if (island != null && island.isInsideRange(blockLocation)) plugin.getNMSChunks().startTickingChunk(island, e.getBlock().getChunk(), false); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.type; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.Location2ObjectMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddEntityLimit; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRemoveEntityLimit; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetEntityLimit; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Animals; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityBreedEvent; import org.bukkit.event.hanging.HangingPlaceEvent; import org.bukkit.event.player.PlayerInteractAtEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.vehicle.VehicleCreateEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; public class UpgradeTypeEntityLimits implements IUpgradeType { @Nullable private static final Material GOLDEN_DANDELION_TYPE = EnumHelper.getEnum(Material.class, "GOLDEN_DANDELION"); private final Map entityBreederPlayers = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); private final Map vehiclesOwners = AutoRemovalMap.newMap(2, TimeUnit.SECONDS, Location2ObjectMap::new); private final Map spawnEggPlayers = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); private final SuperiorSkyblockPlugin plugin; public UpgradeTypeEntityLimits(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public List getListeners() { List listeners = new LinkedList<>(); listeners.add(new EntityLimitsListener()); checkEntityBreedListener().ifPresent(listeners::add); return listeners; } @Override public List getCommands() { return Arrays.asList(new CmdAdminAddEntityLimit(), new CmdAdminRemoveEntityLimit(), new CmdAdminSetEntityLimit()); } private Optional checkEntityBreedListener() { try { Class.forName("org.bukkit.event.entity.EntityBreedEvent"); return Optional.of(new EntityLimitsBreedListener()); } catch (ClassNotFoundException error) { return Optional.empty(); } } private class EntityLimitsListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEntitySpawn(CreatureSpawnEvent e) { Entity entity = e.getEntity(); EntityType entityType = entity.getType(); if (BukkitEntities.canBypassEntityLimit(entity) || !BukkitEntities.canHaveLimit(entityType)) return; Island island = plugin.getGrid().getIslandAt(e.getLocation()); if (island == null) return; SpawningPlayerData spawningPlayerData = getSpawningPlayerFromSpawnEvent(e); Player spawningPlayer = spawningPlayerData == null ? null : spawningPlayerData.player.get(); boolean hasReachedLimit = island.hasReachedEntityLimit(Keys.of(entity)).join(); if (hasReachedLimit) { e.setCancelled(true); if (spawningPlayer != null && spawningPlayer.isOnline()) { Message.REACHED_ENTITY_LIMIT.send(spawningPlayer, Formatters.CAPITALIZED_FORMATTER.format(entityType.toString())); List itemsToGiveBack = spawningPlayerData.itemStacks; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = spawningPlayer.getLocation(wrapper.getHandle()); PlayerInventory inventory = spawningPlayer.getInventory(); for (ItemStack itemStack : itemsToGiveBack) { BukkitItems.addItem(itemStack, inventory, location); } } } } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onHangingPlace(HangingPlaceEvent e) { Entity entity = e.getEntity(); EntityType entityType = entity.getType(); if (BukkitEntities.canBypassEntityLimit(entity) || !BukkitEntities.canHaveLimit(entityType)) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); } if (island == null) return; boolean hasReachedLimit = island.hasReachedEntityLimit(Keys.of(entity)).join(); if (hasReachedLimit) { e.setCancelled(true); Message.REACHED_ENTITY_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(entityType.toString())); } } @EventHandler public void onVehicleSpawn(PlayerInteractEvent e) { if (e.getAction() != Action.RIGHT_CLICK_BLOCK) return; PlayerHand playerHand = BukkitItems.getHand(e); if (playerHand != PlayerHand.MAIN_HAND) return; ItemStack handItem = BukkitItems.getHandItem(e.getPlayer(), playerHand); if (handItem == null) return; Material handType = handItem.getType(); // Check if minecart or boat boolean isMinecart = Materials.isRail(e.getClickedBlock().getType()) && Materials.isMinecart(handType); boolean isBoat = Materials.isBoat(handType); if (!isMinecart && !isBoat) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = e.getClickedBlock().getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(blockLocation); if (island == null) return; Location futureEntitySpawnLocation = isMinecart ? blockLocation : blockLocation.add(0, 1, 0); vehiclesOwners.put(futureEntitySpawnLocation, new SpawningPlayerData(e.getPlayer())); } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onVehicleSpawn(VehicleCreateEvent e) { Entity entity = e.getVehicle(); EntityType entityType = entity.getType(); if (BukkitEntities.canBypassEntityLimit(entity) || !BukkitEntities.canHaveLimit(entityType)) return; Island island; SpawningPlayerData vehicleOwnerData; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); island = plugin.getGrid().getIslandAt(entityLocation); if (island == null) return; vehicleOwnerData = vehiclesOwners.remove(entityLocation); } Player vehicleOwner = vehicleOwnerData == null ? null : vehicleOwnerData.player.get(); boolean hasReachedLimit = island.hasReachedEntityLimit(Keys.of(entity)).join(); if (hasReachedLimit) { entity.remove(); if (vehicleOwner != null && vehicleOwner.isOnline()) { Message.REACHED_ENTITY_LIMIT.send(vehicleOwner, Formatters.CAPITALIZED_FORMATTER.format(entityType.toString())); } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnEggUse(PlayerInteractEvent e) { if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getItem() == null) return; PlayerHand usedHand = BukkitItems.getHand(e); ItemStack usedItem = BukkitItems.getHandItem(e.getPlayer(), usedHand); EntityType spawnEggEntityType = usedItem == null ? EntityType.UNKNOWN : usedItem.getType() == Material.ARMOR_STAND ? EntityType.ARMOR_STAND : BukkitItems.getEntityType(usedItem); if (spawnEggEntityType == EntityType.UNKNOWN || !BukkitEntities.canHaveLimit(spawnEggEntityType)) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle())); } if (island == null) return; spawnEggPlayers.put(spawnEggEntityType, new SpawningPlayerData(e.getPlayer())); } @Nullable private SpawningPlayerData getSpawningPlayerFromSpawnEvent(CreatureSpawnEvent event) { EntityType entityType = event.getEntityType(); if (entityType == EntityType.ARMOR_STAND) { return spawnEggPlayers.remove(entityType); } switch (event.getSpawnReason()) { case SPAWNER_EGG: return spawnEggPlayers.remove(entityType); case BREEDING: return entityBreederPlayers.remove(entityType); } return null; } } private class EntityLimitsBreedListener implements Listener { private final Int2ObjectMapView trackedBreedItems = CollectionsFactory.createInt2ObjectArrayMap(); @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityBreed(EntityBreedEvent e) { Entity child = e.getEntity(); EntityType childEntityType = child.getType(); if (!(e.getBreeder() instanceof Player) || !BukkitEntities.canHaveLimit(childEntityType)) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(child.getLocation(wrapper.getHandle())); } if (island == null) return; ItemStack fatherBreedItem = trackedBreedItems.remove(e.getFather().getEntityId()); ItemStack motherBreedItem = e.getFather().equals(e.getMother()) ? null : trackedBreedItems.remove(e.getMother().getEntityId()); entityBreederPlayers.put(childEntityType, new SpawningPlayerData((Player) e.getBreeder(), fatherBreedItem, motherBreedItem)); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityFeed(PlayerInteractAtEntityEvent e) { if (!(e.getRightClicked() instanceof Animals)) return; PlayerHand usedHand = BukkitItems.getHand(e); ItemStack usedItem = BukkitItems.getHandItem(e.getPlayer(), usedHand); if (usedItem == null || (usedItem.getType() != GOLDEN_DANDELION_TYPE && !plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) e.getRightClicked()))) return; // We want to calculate the amount of items consumed by breeding this animal. // We do that by checking the held item one tick later, and subtracting the // amount after 1 tick of the item from the original amount. int mainHandSlot = e.getPlayer().getInventory().getHeldItemSlot(); int originalAmount = usedItem.getAmount(); ItemStack breedItem = usedItem.clone(); BukkitExecutor.sync(() -> { ItemStack inventoryItem = usedHand == PlayerHand.MAIN_HAND ? e.getPlayer().getInventory().getItem(mainHandSlot) : BukkitItems.getHandItem(e.getPlayer(), PlayerHand.OFF_HAND); boolean isInventoryItemEmpty = inventoryItem == null || inventoryItem.getType() == Material.AIR; if (!isInventoryItemEmpty && !inventoryItem.isSimilar(usedItem)) return; int currAmount = isInventoryItemEmpty ? 0 : inventoryItem.getAmount(); int consumedAmount = originalAmount - currAmount; if (consumedAmount <= 0) return; breedItem.setAmount(consumedAmount); trackedBreedItems.put(e.getRightClicked().getEntityId(), breedItem); }, 5L); } } private static class SpawningPlayerData { private final WeakReference player; private final List itemStacks = new LinkedList<>(); SpawningPlayerData(Player player) { this(player, (ItemStack) null); } SpawningPlayerData(Player player, @Nullable ItemStack itemStack) { this.player = new WeakReference<>(player); addItem(itemStack); } SpawningPlayerData(Player player, ItemStack... itemStacks) { this.player = new WeakReference<>(player); for (ItemStack itemStack : itemStacks) addItem(itemStack); } private void addItem(@Nullable ItemStack itemStack) { if (itemStack != null && itemStack.getType() != Material.AIR && itemStack.getAmount() > 0) this.itemStacks.add(itemStack); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.type; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddEffect; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetEffect; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityPotionEffectEvent; import java.util.Arrays; import java.util.Collections; import java.util.List; public class UpgradeTypeIslandEffects implements IUpgradeType { private final SuperiorSkyblockPlugin plugin; public UpgradeTypeIslandEffects(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public List getListeners() { return ServerVersion.isAtLeast(ServerVersion.v1_15) ? Collections.singletonList(new IslandEffectsListener()) : Collections.emptyList(); } @Override public List getCommands() { return Arrays.asList(new CmdAdminAddEffect(), new CmdAdminSetEffect()); } private class IslandEffectsListener implements Listener { @EventHandler(ignoreCancelled = true) public void onPlayerEffect(EntityPotionEffectEvent e) { if (e.getAction() == EntityPotionEffectEvent.Action.ADDED || !(e.getEntity() instanceof Player) || e.getCause() == EntityPotionEffectEvent.Cause.PLUGIN || e.getCause() == EntityPotionEffectEvent.Cause.BEACON) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); } if (island == null) return; int islandEffectLevel = island.getPotionEffectLevel(e.getModifiedType()); if (islandEffectLevel > 0 && (e.getOldEffect() == null || e.getOldEffect().getAmplifier() == islandEffectLevel)) { e.setCancelled(true); } } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.type; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddMobDrops; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetMobDrops; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.inventory.ItemStack; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class UpgradeTypeMobDrops implements IUpgradeType { private final SuperiorSkyblockPlugin plugin; private final boolean isWildStackerInstalled; public UpgradeTypeMobDrops(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; isWildStackerInstalled = Bukkit.getPluginManager().isPluginEnabled("WildStacker"); } @Override public List getListeners() { return Collections.singletonList(new MobDropsListener()); } @Override public List getCommands() { return Arrays.asList(new CmdAdminAddMobDrops(), new CmdAdminSetMobDrops()); } private static boolean canDupeDropsForEntity(Entity entity) { return entity instanceof LivingEntity && !(entity instanceof Player) && !(entity instanceof ArmorStand); } private class MobDropsListener implements Listener { // Priority is set to HIGH for fixing detection with WildStacker // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/540 @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onLastDamageEntity(EntityDamageEvent e) { if (!canDupeDropsForEntity(e.getEntity())) return; LivingEntity livingEntity = (LivingEntity) e.getEntity(); if (livingEntity.getHealth() - e.getFinalDamage() > 0) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(livingEntity.getLocation(wrapper.getHandle())); } if (island == null) return; BukkitEntities.cacheEntityEquipment(livingEntity); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onEntityDeath(EntityDeathEvent e) { if (!canDupeDropsForEntity(e.getEntity())) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); } if (island == null) return; if (plugin.getSettings().isDropsUpgradePlayersMultiply()) { EntityDamageEvent lastDamage = e.getEntity().getLastDamageCause(); if (!(lastDamage instanceof EntityDamageByEntityEvent) || !BukkitEntities.getPlayerSource(((EntityDamageByEntityEvent) lastDamage).getDamager()).isPresent()) return; } double mobDropsMultiplier = island.getMobDropsMultiplier(); if (mobDropsMultiplier > 1) modifyEventDrops(e.getDrops(), e.getEntity(), mobDropsMultiplier); BukkitEntities.clearEntityEquipment(e.getEntity()); } private void modifyEventDrops(List drops, LivingEntity livingEntity, double mobDropsMultiplier) { List dropsToAdd = isWildStackerInstalled ? null : new LinkedList<>(); for (ItemStack itemStack : drops) { if (itemStack != null && !BukkitEntities.isEquipment(livingEntity, itemStack)) { int newAmount = (int) Math.floor(itemStack.getAmount() * mobDropsMultiplier); if (isWildStackerInstalled) { itemStack.setAmount(newAmount); } else { int stackAmounts = newAmount / itemStack.getMaxStackSize(); int leftOvers = newAmount % itemStack.getMaxStackSize(); boolean usedOriginal = false; if (stackAmounts > 0) { itemStack.setAmount(itemStack.getMaxStackSize()); usedOriginal = true; ItemStack stackItem = itemStack.clone(); stackItem.setAmount(itemStack.getMaxStackSize()); for (int i = 0; i < stackAmounts - 1; i++) dropsToAdd.add(itemStack.clone()); } if (leftOvers > 0) { if (usedOriginal) { ItemStack leftOversItem = itemStack.clone(); leftOversItem.setAmount(leftOvers); dropsToAdd.add(leftOversItem); } else { itemStack.setAmount(leftOvers); } } } } } if (dropsToAdd != null) drops.addAll(dropsToAdd); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeSpawnerRates.java ================================================ package com.bgsoftware.superiorskyblock.module.upgrades.type; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddSpawnerRates; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetSpawnerRates; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.world.ChunkLoadEvent; import java.util.Arrays; import java.util.Collections; import java.util.List; public class UpgradeTypeSpawnerRates implements IUpgradeType { private final SuperiorSkyblockPlugin plugin; public UpgradeTypeSpawnerRates(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public List getListeners() { return Collections.singletonList(new SpawnerRatesListener()); } @Override public List getCommands() { return Arrays.asList(new CmdAdminAddSpawnerRates(), new CmdAdminSetSpawnerRates()); } public void handleSpawnerPlace(Block block) { Location location = block.getLocation(); Island island = plugin.getGrid().getIslandAt(location); if (island == null) return; // We want to replace the spawner in a delay so other plugins that might change the spawner will be taken in action as well. BukkitExecutor.sync(() -> { if (block.getType() == Materials.SPAWNER.toBukkitType()) plugin.getNMSWorld().listenSpawner(location, spawnDelay -> calculateNewSpawnerDelay(island, spawnDelay)); }, 20L); } private int calculateNewSpawnerDelay(Island island, int spawnDelay) { double spawnerRatesMultiplier = island.getSpawnerRatesMultiplier(); if (spawnerRatesMultiplier > 1) { return (int) Math.round(spawnDelay / spawnerRatesMultiplier); } else { return spawnDelay; } } private class SpawnerRatesListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerPlace(BlockPlaceEvent e) { if (e.getBlock().getType() == Materials.SPAWNER.toBukkitType()) handleSpawnerPlace(e.getBlock()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onChunkLoad(ChunkLoadEvent e) { List chunkIslands = plugin.getGrid().getIslandsAt(e.getChunk()); chunkIslands.forEach(island -> handleIslandChunkLoad(island, e.getChunk())); } private void handleIslandChunkLoad(Island island, Chunk chunk) { List blockEntities = plugin.getNMSChunks().getBlockEntities(chunk); if (blockEntities.isEmpty()) return; // We want to replace the spawner in a delay so other plugins that might change the spawner will be taken in action as well. // Block entities that are not spawners will not be touched. BukkitExecutor.sync(() -> { if (chunk.isLoaded()) { blockEntities.forEach(blockEntity -> { plugin.getNMSWorld().listenSpawner(blockEntity, spawnDelay -> calculateNewSpawnerDelay(island, spawnDelay)); }); } }, 20L); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/ICachedBlock.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import org.bukkit.Location; public interface ICachedBlock extends ObjectsPool.Releasable { void setBlock(Location location); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import com.bgsoftware.superiorskyblock.listener.BukkitEventsListener; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Minecart; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; import java.util.Optional; public interface NMSAlgorithms { EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge() { @Override public Biome[] getValues() { return Biome.values(); } @Override public String getName(Biome enumValue) { return enumValue.name(); } }; void registerCommand(BukkitCommand command); String parseSignLine(String original); int getCombinedId(Location location); int getCombinedId(Material material, byte data); Optional getTileEntityIdFromCombinedId(int combinedId); int compareMaterials(Material o1, Material o2); short getBlockDataValue(BlockState blockState); short getBlockDataValue(Block block); short getMaxBlockDataValue(Material material); Key getBlockKey(int combinedId); Key getMinecartBlock(Minecart minecart); Key getFallingBlockType(FallingBlock fallingBlock); void setCustomModel(ItemMeta itemMeta, int customModel); void setItemModel(ItemMeta itemMeta, String itemModel); void setRarity(ItemMeta itemMeta, String rarity) throws IllegalArgumentException; void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) throws IllegalArgumentException; void setHideTooltip(ItemMeta itemMeta); void addPotion(PotionMeta potionMeta, PotionEffect potionEffect); String getMinecraftKey(ItemStack itemStack); void makeItemGlow(ItemMeta itemMeta); @Nullable Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title); int getMaxWorldSize(); double getCurrentTps(); int getDataVersion(); Biome getBiome(String biomeName); default ClassProcessor getClassProcessor() { return null; } default void handlePaperChatRenderer(Object event) { throw new UnsupportedOperationException(); } default void hideAttributes(ItemMeta itemMeta) { } default EnumBridge getBiomeBridge() { return BIOME_ENUM_BRIDGE; } default BukkitEventsListener.GameEventCreator getGenericGameCreator() { throw new UnsupportedOperationException("Not supported in this version"); } interface EnumBridge { T[] getValues(); String getName(T enumValue); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSChunks.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.block.Biome; import org.bukkit.entity.Player; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; public interface NMSChunks { void setBiome(List chunkPositions, Biome biome, Collection playersToUpdate); void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish); CompletableFuture> calculateChunks(List chunkPositions, Synchronized> unloadedChunksCache); CompletableFuture> calculateChunkEntities(Collection chunkPositions); void injectChunkSections(Chunk chunk); boolean isChunkEmpty(Chunk chunk); @Nullable Chunk getChunkIfLoaded(ChunkPosition chunkPosition); void startTickingChunk(Island island, Chunk chunk, boolean stop); void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier); void shutdown(); List getBlockEntities(Chunk chunk); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSDragonFight.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.EnderDragon; import org.bukkit.entity.Player; public interface NMSDragonFight { void prepareEndWorld(World bukkitWorld); @Nullable EnderDragon getEnderDragon(Island island, Dimension dimension); void startDragonBattle(Island island, Location location); void removeDragonBattle(Island island, Dimension dimension); void awardTheEndAchievement(Player player); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSDragonFightChooser.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.common.nmsloader.NMSLoadException; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.EnderDragon; import org.bukkit.entity.Player; public class NMSDragonFightChooser implements NMSDragonFight { private final SuperiorSkyblockPlugin plugin; private final NMSDragonFightSupplier enabledInstanceSupplier; private NMSDragonFight delegate; public NMSDragonFightChooser(SuperiorSkyblockPlugin plugin, NMSDragonFightSupplier enabledInstanceSupplier) { this.plugin = plugin; this.enabledInstanceSupplier = enabledInstanceSupplier; } @Override public void prepareEndWorld(World bukkitWorld) { getDelegate().prepareEndWorld(bukkitWorld); } @Override public EnderDragon getEnderDragon(Island island, Dimension dimension) { return getDelegate().getEnderDragon(island, dimension); } @Override public void startDragonBattle(Island island, Location location) { getDelegate().startDragonBattle(island, location); } @Override public void removeDragonBattle(Island island, Dimension dimension) { getDelegate().removeDragonBattle(island, dimension); } @Override public void awardTheEndAchievement(Player player) { getDelegate().awardTheEndAchievement(player); } private NMSDragonFight getDelegate() { if (this.delegate == null) { if (plugin.getSettings() == null) throw new RuntimeException("Called NMSDragonFightChooser#getDelegate before settings initialized"); for (Dimension dimension : Dimension.values()) { if (dimension.getEnvironment() == World.Environment.THE_END) { SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); if (dimensionConfig instanceof SettingsManager.Worlds.End && ((SettingsManager.Worlds.End) dimensionConfig).isDragonFight()) { try { this.delegate = this.enabledInstanceSupplier.get(); } catch (NMSLoadException error) { Log.error(error, "Failed to load NMSDragonFight, disabling it..."); this.delegate = new NMSDragonFightImpl(); } return this.delegate; } } } this.delegate = new NMSDragonFightImpl(); } return this.delegate; } public interface NMSDragonFightSupplier { NMSDragonFight get() throws NMSLoadException; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSDragonFightImpl.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.EnderDragon; import org.bukkit.entity.Player; public class NMSDragonFightImpl implements NMSDragonFight { @Override public void prepareEndWorld(World bukkitWorld) { // Do nothing. } @Nullable @Override public EnderDragon getEnderDragon(Island island, Dimension dimension) { return null; } @Override public void startDragonBattle(Island island, Location location) { // Do nothing. } @Override public void removeDragonBattle(Island island, Dimension dimension) { // Do nothing. } @Override public void awardTheEndAchievement(Player player) { // Do nothing. } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java ================================================ package com.bgsoftware.superiorskyblock.nms; import org.bukkit.entity.Animals; import org.bukkit.entity.Entity; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; public interface NMSEntities { ItemStack[] getEquipment(EntityEquipment entityEquipment); boolean isAnimalFood(ItemStack itemStack, Animals animals); boolean isMinecartFuel(ItemStack itemStack, PoweredMinecart minecart); int getPortalTicks(Entity entity); default boolean canShearSaddleFromEntity(Entity entity) { // Not implemented for most versions return false; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSHolograms.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import org.bukkit.Location; import org.bukkit.entity.Entity; public interface NMSHolograms { Hologram createHologram(Location location); boolean isHologram(Entity entity); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSPlayers.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.mojang.authlib.properties.Property; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; public interface NMSPlayers { OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer); void setSkinTexture(SuperiorPlayer superiorPlayer); void setSkinTexture(SuperiorPlayer superiorPlayer, Property property); void sendActionBar(Player player, String message); BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun); void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut); boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer); @Nullable Locale getPlayerLocale(Player player); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSTags.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.util.Set; public interface NMSTags { CompoundTag serializeItem(ItemStack itemStack); ItemStack deserializeItem(CompoundTag compoundTag); default ItemStack getSkullWithTexture(ItemStack itemStack, String texture) { return ItemSkulls.getPlayerHeadNoNMS(itemStack, texture); } void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag); byte[] getNBTByteArrayValue(Object object); byte getNBTByteValue(Object object); Set getNBTCompoundValue(Object object); double getNBTDoubleValue(Object object); float getNBTFloatValue(Object object); int[] getNBTIntArrayValue(Object object); int getNBTIntValue(Object object); Object getNBTListIndexValue(Object object, int index); long getNBTLongValue(Object object); short getNBTShortValue(Object object); String getNBTStringValue(Object object); Object parseList(ListTag listTag); Object getNBTCompoundTag(Object object, String key); void setNBTCompoundTagValue(Object object, String key, Object value); int getNBTTagListSize(Object object); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java ================================================ package com.bgsoftware.superiorskyblock.nms; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import java.util.function.IntFunction; public interface NMSWorld { Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z); boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z); void listenSpawner(Location location, IntFunction delayChangeCallback); default void replaceTrialBlockPlayerDetector(Island island, Location location) { // Does not exist. } default void replaceSculkSensorListener(Island island, Location location) { // Does not exist. } void setWorldBorder(SuperiorPlayer superiorPlayer, Island island); Object getBlockData(Block block); void setBlock(Location location, int combinedId); ICachedBlock cacheBlock(Block block); boolean isWaterLogged(Block block); default SignType getSignType(Block block) { return getSignType(getBlockData(block)); } SignType getSignType(Object sign); default boolean hasBerries(Block block) { return false; } PistonPushReaction getPistonReaction(Block block); int getDefaultAmount(Block block); int getDefaultAmount(BlockState blockState); boolean canPlayerSuffocate(Block block); void placeSign(Island island, Location location); void playGeneratorSound(Location location); void playBreakAnimation(Block block); void playPlaceSound(Location location); int getMinHeight(World world); void removeAntiXray(World world); void setOceanLevel(World world); void listenBlockStateChanges(World world); IslandsGenerator createGenerator(Dimension dimension); WorldEditSession createEditSession(World world); WorldEditSession createPartialEditSession(Dimension dimension); ChunkReader createChunkReader(Chunk chunk); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/bridge/PistonPushReaction.java ================================================ package com.bgsoftware.superiorskyblock.nms.bridge; public enum PistonPushReaction { /* Keep in sync with PushReaction nms */ NORMAL, DESTROY, BLOCK, IGNORE, PUSH_ONLY } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/player/OfflinePlayerData.java ================================================ package com.bgsoftware.superiorskyblock.nms.player; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import org.bukkit.Location; import org.bukkit.entity.Player; public interface OfflinePlayerData extends ObjectsPool.Releasable { Player getFakeOnlinePlayer(); void setLocation(Location location); void applyChanges(); @Override void release(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/world/ChunkReader.java ================================================ package com.bgsoftware.superiorskyblock.nms.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.EntityType; public interface ChunkReader { int getX(); int getZ(); Material getType(int x, int y, int z); short getData(int x, int y, int z); @Nullable CompoundTag getTileEntity(int x, int y, int z); @Nullable CompoundTag readBlockStates(int x, int y, int z); byte[] getLightLevels(int x, int y, int z); void forEachEntity(EntityConsumer consumer); interface EntityConsumer { void apply(EntityType entityType, CompoundTag entityTag, Location location); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java ================================================ package com.bgsoftware.superiorskyblock.nms.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import org.bukkit.Chunk; import org.bukkit.Location; import java.util.List; public interface WorldEditSession extends ObjectsPool.Releasable { void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData); List getAffectedChunks(); void applyBlocks(Chunk chunk); void finish(Island island); Data readData(Location baseLocation); void applyData(Data data, Location baseLocation); interface Data { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/IPlatform.java ================================================ package com.bgsoftware.superiorskyblock.platform; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; public interface IPlatform { void notifyGameEvent(GameEvent gameEvent, GameEventPriority priority); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEvent.java ================================================ package com.bgsoftware.superiorskyblock.platform.event; import com.bgsoftware.superiorskyblock.core.events.IEvent; import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; public class GameEvent implements IEvent> { private final GameEventType type; private final Args args; private boolean cancelled = false; public GameEvent(GameEventType type, Args args) { this.type = type; this.args = args; } @Override public GameEventType getType() { return type; } @Override public boolean isCancelled() { return this.cancelled; } public Args getArgs() { return args; } public void setCancelled() { this.cancelled = true; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventCallback.java ================================================ package com.bgsoftware.superiorskyblock.platform.event; import com.bgsoftware.superiorskyblock.core.events.EventCallback; import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; public interface GameEventCallback extends EventCallback> { void execute(GameEvent gameEvent); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventFlags.java ================================================ package com.bgsoftware.superiorskyblock.platform.event; public @interface GameEventFlags { int ENTITY_EVENT = 1 << 0; int MAYBE_ENTITY_EVENT = 1 << 1; int BLOCK_EVENT = 1 << 2; int MAYBE_BLOCK_EVENT = 1 << 3; int PLAYER_EVENT = 1 << 4; int GENERIC_WORLD_EVENT = 1 << 5; int INVENTORY_EVENT = 1 << 5; } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventPriority.java ================================================ package com.bgsoftware.superiorskyblock.platform.event; public enum GameEventPriority { LOWEST, LOW, NORMAL, HIGH, HIGHEST, MONITOR } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java ================================================ package com.bgsoftware.superiorskyblock.platform.event; import com.bgsoftware.superiorskyblock.core.events.EventType; import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockBreakEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockBurnEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockDispenseEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFadeEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFormEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFromToEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockGrowEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockIgniteEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockPhysicsEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockPlaceEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockRedstoneEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockSpreadEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockUpdateShapeEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ChunkLoadEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ChunkUnloadEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityBlockFormEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityChangeBlockEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityCollisionEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityDamageEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityDeathEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityEnterPortalEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityExplodeEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityInteractEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityMoveEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityPortalEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityRideEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntitySpawnEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityTargetEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityTeleportEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.GenericGameEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.HangingBreakEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.HangingPlaceEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryClickEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryCloseEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryOpenEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.LeavesDecayEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PistonExtendEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PistonRetractEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerChangedWorldEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerChatEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerCommandEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerDropItemEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerEmptyBucketEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerFillBucketEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerGamemodeChangeEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerInteractEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerItemConsumeEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerJoinEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerLeashEntityEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerLoginEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerPickupArrowEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerPickupItemEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerQuitEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerRespawnEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerShearEntityEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerUnleashEntityEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ProjectileHitEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ProjectileLaunchEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.RaidTriggerEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.SignChangeEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.SpongeAbsorbEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.StructureGrowEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.WorldUnloadEvent; public class GameEventType extends EventType> { private static final List> ALL_TYPES = new LinkedList<>(); // Block Events public static final GameEventType BLOCK_BREAK_EVENT = register(BlockBreakEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT); public static final GameEventType BLOCK_BURN_EVENT = register(BlockBurnEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_DISPENSE_EVENT = register(BlockDispenseEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_FADE_EVENT = register(BlockFadeEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_FORM_EVENT = register(BlockFormEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_FROM_TO_EVENT = register(BlockFromToEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_GROW_EVENT = register(BlockGrowEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_IGNITE_EVENT = register(BlockIgniteEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_PHYSICS_EVENT = register(BlockPhysicsEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_PLACE_EVENT = register(BlockPlaceEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT); public static final GameEventType BLOCK_REDSTONE_EVENT = register(BlockRedstoneEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_SPREAD_EVENT = register(BlockSpreadEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType BLOCK_UPDATE_SHAPE_EVENT = register(BlockUpdateShapeEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType LEAVES_DECAY_EVENT = register(LeavesDecayEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType PISTON_EXTEND_EVENT = register(PistonExtendEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType PISTON_RETRACT_EVENT = register(PistonRetractEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType SIGN_CHANGE_EVENT = register(SignChangeEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT); public static final GameEventType SPONGE_ABSORB_EVENT = register(SpongeAbsorbEvent.class, GameEventFlags.BLOCK_EVENT); public static final GameEventType STRUCTURE_GROW_EVENT = register(StructureGrowEvent.class, GameEventFlags.BLOCK_EVENT); // World Events public static final GameEventType CHUNK_LOAD_EVENT = register(ChunkLoadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT); public static final GameEventType CHUNK_UNLOAD_EVENT = register(ChunkUnloadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT); public static final GameEventType WORLD_UNLOAD_EVENT = register(WorldUnloadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT); public static final GameEventType RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class, GameEventFlags.GENERIC_WORLD_EVENT | GameEventFlags.PLAYER_EVENT); public static final GameEventType GENERIC_GAME_EVENT = register(GenericGameEvent.class, GameEventFlags.GENERIC_WORLD_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT | GameEventFlags.MAYBE_ENTITY_EVENT); // Entity Events public static final GameEventType ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_CHANGE_BLOCK_EVENT = register(EntityChangeBlockEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_COLLISION_EVENT = register(EntityCollisionEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_DAMAGE_EVENT = register(EntityDamageEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_DEATH_EVENT = register(EntityDeathEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_ENTER_PORTAL_EVENT = register(EntityEnterPortalEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_EXPLODE_EVENT = register(EntityExplodeEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_INTERACT_EVENT = register(EntityInteractEvent.class, GameEventFlags.ENTITY_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); public static final GameEventType ENTITY_MOVE_EVENT = register(EntityMoveEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_PORTAL_EVENT = register(EntityPortalEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_RIDE_EVENT = register(EntityRideEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_SPAWN_EVENT = register(EntitySpawnEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_TARGET_EVENT = register(EntityTargetEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_TELEPORT_EVENT = register(EntityTeleportEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType HANGING_BREAK_EVENT = register(HangingBreakEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType HANGING_PLACE_EVENT = register(HangingPlaceEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType PROJECTILE_HIT_EVENT = register(ProjectileHitEvent.class, GameEventFlags.ENTITY_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); public static final GameEventType PROJECTILE_LAUNCH_EVENT = register(ProjectileLaunchEvent.class, GameEventFlags.ENTITY_EVENT); // Inventory Events public static final GameEventType INVENTORY_CLICK_EVENT = register(InventoryClickEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT); public static final GameEventType INVENTORY_CLOSE_EVENT = register(InventoryCloseEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT); public static final GameEventType INVENTORY_OPEN_EVENT = register(InventoryOpenEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT); // Player Events public static final GameEventType PLAYER_CHANGED_WORLD_EVENT = register(PlayerChangedWorldEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_CHAT_EVENT = register(PlayerChatEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_COMMAND_EVENT = register(PlayerCommandEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_DROP_ITEM_EVENT = register(PlayerDropItemEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); public static final GameEventType PLAYER_EMPTY_BUCKET_EVENT = register(PlayerEmptyBucketEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.BLOCK_EVENT); public static final GameEventType PLAYER_FILL_BUCKET_EVENT = register(PlayerFillBucketEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.BLOCK_EVENT); public static final GameEventType PLAYER_GAMEMODE_CHANGE = register(PlayerGamemodeChangeEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_INTERACT_EVENT = register(PlayerInteractEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT | GameEventFlags.MAYBE_ENTITY_EVENT); public static final GameEventType PLAYER_ITEM_CONSUME_EVENT = register(PlayerItemConsumeEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_JOIN_EVENT = register(PlayerJoinEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_LEASH_ENTITY_EVENT = register(PlayerLeashEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); public static final GameEventType PLAYER_LOGIN_EVENT = register(PlayerLoginEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_PICKUP_ARROW_EVENT = register(PlayerPickupArrowEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); public static final GameEventType PLAYER_PICKUP_ITEM_EVENT = register(PlayerPickupItemEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); public static final GameEventType PLAYER_QUIT_EVENT = register(PlayerQuitEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_RESPAWN_EVENT = register(PlayerRespawnEvent.class, GameEventFlags.PLAYER_EVENT); public static final GameEventType PLAYER_SHEAR_ENTITY_EVENT = register(PlayerShearEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); public static final GameEventType PLAYER_UNLEASH_ENTITY_EVENT = register(PlayerUnleashEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); @GameEventFlags private final int flags; private GameEventType(@GameEventFlags int flags) { this.flags = flags; } @GameEventFlags public int getFlags() { return this.flags; } public GameEvent createEvent(Args args) { return new GameEvent<>(this, args); } private static GameEventType register(Class eventArgsType, @GameEventFlags int flags) { GameEventType eventType = new GameEventType<>(flags); ALL_TYPES.add(eventType); return eventType; } public static Collection> values() { return Collections.unmodifiableList(ALL_TYPES); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java ================================================ package com.bgsoftware.superiorskyblock.platform.event; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.events.EventsDispatcher; import com.bgsoftware.superiorskyblock.listener.AbstractGameEventListener; public class GameEventsDispatcher extends EventsDispatcher< AbstractGameEventListener, GameEventType, GameEventPriority, GameEvent> { @GameEventFlags private int capturedEventsFlags = 0; public GameEventsDispatcher(SuperiorSkyblockPlugin plugin) { super(plugin, GameEventPriority.class, GameEventType.values()); } @Override public void startCaptureEvents() { this.startCaptureEvents(0xFFFFFFFF); } public void startCaptureEvents(@GameEventFlags int capturedEventsFlags) { super.startCaptureEvents(); this.capturedEventsFlags = capturedEventsFlags; } @Override protected boolean filterCapturedEvent(GameEvent event) { return this.capturedEventsFlags == 0xFFFFFFFF || (event.getType().getFlags() & this.capturedEventsFlags) != 0; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java ================================================ package com.bgsoftware.superiorskyblock.platform.event.args; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.PlayerHand; import org.bukkit.Chunk; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.entity.Vehicle; import org.bukkit.event.block.Action; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import java.util.List; public class GameEventArgs implements IEventArgs { private GameEventArgs() { } public static class BlockFromToEvent extends BlockEvent { public Block toBlock; } public static class BlockIgniteEvent extends BlockEvent { public org.bukkit.event.block.BlockIgniteEvent.IgniteCause igniteCause; } public static class PistonExtendEvent extends PistonEvent { } public static class PistonRetractEvent extends PistonEvent { } public static class BlockPlaceEvent extends BlockEvent { public Player player; public Block againstBlock; public BlockState replacedState; public PlayerHand usedHand; public ItemStack usedItem; } public static class ChunkLoadEvent extends ChunkEvent { public boolean isNewChunk; } public static class EntityChangeBlockEvent extends EntityEvent { public Block block; public Key newType; } public static class EntityDamageEvent extends EntityEvent { public org.bukkit.event.entity.EntityDamageEvent.DamageCause damageCause; @Nullable public Entity damager; } public static class EntityMoveEvent extends EntityEvent { public Location from; public Location to; } public static class EntityRideEvent extends EntityEvent { public Vehicle vehicle; } public static class HangingBreakEvent extends EntityEvent { public Entity remover; public org.bukkit.event.hanging.HangingBreakEvent.RemoveCause removeCause; } public static class HangingPlaceEvent extends EntitySpawnEvent { public Player player; } public static class EntityTargetEvent extends EntityEvent { public Entity target; } public static class InventoryClickEvent extends GameEventArgs { public org.bukkit.event.inventory.InventoryClickEvent bukkitEvent; } public static class PlayerChangedWorldEvent extends PlayerEvent { public World from; } public static class PlayerChatEvent extends PlayerEvent { public String message; @Nullable public String format; } public static class PlayerCommandEvent extends PlayerEvent { public String command; } public static class PlayerGamemodeChangeEvent extends PlayerEvent { public GameMode newGamemode; } public static class PlayerInteractEvent extends PlayerEvent { public Action action; @Nullable public PlayerHand usedHand; @Nullable public ItemStack usedItem; @Nullable public Block clickedBlock; @Nullable public Entity clickedEntity; } public static class PlayerRespawnEvent extends PlayerEvent { public org.bukkit.event.player.PlayerRespawnEvent bukkitEvent; } public static class SpongeAbsorbEvent extends BlockEvent { public List blocks; } public static class StructureGrowEvent extends WorldEvent { public Location location; public List blocks; } public static class PlayerJoinEvent extends PlayerEvent { } public static class PlayerQuitEvent extends PlayerEvent { } public static class PlayerEmptyBucketEvent extends PlayerBucketEvent { } public static class PlayerFillBucketEvent extends PlayerBucketEvent { } public static class BlockGrowEvent extends BlockTransformEvent { } public static class BlockFormEvent extends BlockTransformEvent { } public static class BlockSpreadEvent extends BlockTransformEvent { public Block source; } public static class BlockBreakEvent extends BlockEvent { public Player player; } public static class EntityDeathEvent extends EntityEvent { } public static class LeavesDecayEvent extends BlockEvent { } public static class EntityExplodeEvent extends EntityEvent { public List blocks; public boolean isSoftExplosion; } public static class ProjectileHitEvent extends EntityEvent { @Nullable public Block hitBlock; @Nullable public Entity hitEntity; } public static class ProjectileLaunchEvent extends EntityEvent { } public static class ChunkUnloadEvent extends ChunkEvent { } public static class WorldUnloadEvent extends WorldEvent { } public static class EntitySpawnEvent extends EntityEvent { public CreatureSpawnEvent.SpawnReason spawnReason; } public static class BlockBurnEvent extends BlockEvent { } public static class EntityTeleportEvent extends EntityMoveEvent { public PlayerTeleportEvent.TeleportCause cause; } public static class BlockRedstoneEvent extends BlockEvent { } public static class InventoryCloseEvent extends GameEventArgs { public org.bukkit.event.inventory.InventoryCloseEvent bukkitEvent; } public static class InventoryOpenEvent extends GameEventArgs { public org.bukkit.event.inventory.InventoryOpenEvent bukkitEvent; } public static class PlayerLoginEvent extends PlayerEvent { } public static class EntityPortalEvent extends EntityTeleportEvent { } public static class EntityEnterPortalEvent extends EntityEvent { public Location portalLocation; } public static class EntityBlockFormEvent extends BlockFormEvent { public Entity entity; } public static class BlockDispenseEvent extends BlockEvent { public ItemStack dispensedItem; public Vector velocity; } public static class BlockFadeEvent extends BlockEvent { public BlockState newState; } public static class PlayerItemConsumeEvent extends PlayerEvent { public ItemStack consumedItem; } public static class PlayerShearEntityEvent extends PlayerEvent { public Entity entity; } public static class PlayerLeashEntityEvent extends PlayerEvent { public Entity entity; } public static class PlayerUnleashEntityEvent extends PlayerEvent { public Entity entity; } public static class EntityCollisionEvent extends EntityEvent { public Entity target; } public static class PlayerDropItemEvent extends PlayerEvent { public Item droppedItem; } public static class PlayerPickupItemEvent extends PlayerEvent { public Item pickedUpItem; } public static class PlayerPickupArrowEvent extends PlayerPickupItemEvent { } public static class RaidTriggerEvent extends WorldEvent { public Player player; public Location raidLocation; } public static class SignChangeEvent extends BlockEvent { public Player player; public String[] lines; } public static class BlockPhysicsEvent extends BlockEvent { } public static class BlockUpdateShapeEvent extends BlockEvent { public BlockState oldState; } public static class GenericGameEvent extends WorldEvent { public String gameEvent; public Location location; } public static class EntityInteractEvent extends EntityEvent { @Nullable public Block block; } private static class BlockEvent extends GameEventArgs { public Block block; } private static class PistonEvent extends BlockEvent { public List blocks; public BlockFace direction; } private static class ChunkEvent extends GameEventArgs { public Chunk chunk; } private static class EntityEvent extends GameEventArgs { public Entity entity; } private static class PlayerEvent extends GameEventArgs { public Player player; } private static class WorldEvent extends GameEventArgs { public World world; } private static class BlockTransformEvent extends BlockEvent { public BlockState newState; } private static class PlayerBucketEvent extends PlayerEvent { public Material bucket; public Block clickedBlock; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/IEventArgs.java ================================================ package com.bgsoftware.superiorskyblock.platform.event.args; public interface IEventArgs { } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/PlayerLocales.java ================================================ package com.bgsoftware.superiorskyblock.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.google.common.base.Preconditions; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.HashSet; import java.util.Locale; import java.util.Set; import java.util.regex.Pattern; public class PlayerLocales { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Pattern RTL_LOCALE_PATTERN = Pattern.compile( "^(ar|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)"); private static final Pattern LOCALE_PATTERN = Pattern.compile("^[a-zA-Z]{2}[_|-][a-zA-Z]{2}$"); private static final Set locales = new HashSet<>(); private static java.util.Locale defaultLocale = null; private PlayerLocales() { } public static Locale getLocale(CommandSender sender) { return sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender).getUserLocale() : defaultLocale; } public static java.util.Locale getLocale(String str) throws IllegalArgumentException { str = str.replace("_", "-"); Preconditions.checkArgument(LOCALE_PATTERN.matcher(str).matches(), "String " + str + " is not a valid language."); String[] numberFormatSections = str.split("-"); return new java.util.Locale(numberFormatSections[0], numberFormatSections[1]); } public static boolean isRightToLeft(Locale locale) { return RTL_LOCALE_PATTERN.matcher(locale.getLanguage()).matches(); } public static void clearLocales() { locales.clear(); } public static void registerLocale(java.util.Locale locale) { if (locales.isEmpty()) defaultLocale = locale; locales.add(locale); } public static java.util.Locale getDefaultLocale() { return defaultLocale; } public static void setDefaultLocale(Locale defaultLocale) { PlayerLocales.defaultLocale = defaultLocale; } public static boolean isValidLocale(java.util.Locale locale) { return locales.contains(locale); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.player; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.PlayersManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.List; import java.util.Objects; import java.util.UUID; import java.util.function.Predicate; public class PlayersManagerImpl extends Manager implements PlayersManager { private PlayersContainer playersContainer; public PlayersManagerImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @Override public void loadData() { // Data is loaded by the database bridge. if (this.playersContainer == null) throw new RuntimeException("PlayersManager was not initialized correctly. Contact Ome_R regarding this!"); } @Override public SuperiorPlayer getSuperiorPlayer(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); return this.playersContainer.getSuperiorPlayer(name); } @Override public SuperiorPlayer getSuperiorPlayer(Player player) { Preconditions.checkNotNull(player, "player parameter cannot be null."); return player.hasMetadata("NPC") ? SuperiorNPCPlayer.obtain(player) : getSuperiorPlayer(player.getUniqueId()); } @Override public SuperiorPlayer getSuperiorPlayer(UUID uuid) { return Objects.requireNonNull(getSuperiorPlayer(uuid, true)); } @Nullable public SuperiorPlayer getSuperiorPlayer(UUID uuid, boolean createIfNotExists) { return this.getSuperiorPlayer(uuid, createIfNotExists, true); } @Nullable public SuperiorPlayer getSuperiorPlayer(UUID uuid, boolean createIfNotExists, boolean saveToDatabase) { Preconditions.checkNotNull(uuid, "uuid parameter cannot be null."); SuperiorPlayer superiorPlayer = this.playersContainer.getSuperiorPlayer(uuid); if (createIfNotExists && superiorPlayer == null) { superiorPlayer = plugin.getFactory().createPlayer(uuid); this.playersContainer.addPlayer(superiorPlayer); if (saveToDatabase) PlayersDatabaseBridge.insertPlayer(superiorPlayer); } return superiorPlayer; } @Override public List getAllPlayers() { return this.playersContainer.getAllPlayers(); } @Override @Deprecated public PlayerRole getPlayerRole(int index) { return plugin.getRoles().getPlayerRole(index); } @Override @Deprecated public PlayerRole getPlayerRoleFromId(int id) { return plugin.getRoles().getPlayerRoleFromId(id); } @Override @Deprecated public PlayerRole getPlayerRole(String name) { return plugin.getRoles().getPlayerRole(name); } @Override @Deprecated public PlayerRole getDefaultRole() { return plugin.getRoles().getDefaultRole(); } @Override @Deprecated public PlayerRole getLastRole() { return plugin.getRoles().getLastRole(); } @Override @Deprecated public PlayerRole getGuestRole() { return plugin.getRoles().getGuestRole(); } @Override @Deprecated public PlayerRole getCoopRole() { return plugin.getRoles().getCoopRole(); } @Override @Deprecated public List getRoles() { return plugin.getRoles().getRoles(); } @Override public PlayersContainer getPlayersContainer() { return this.playersContainer; } @Override public void setPlayersContainer(PlayersContainer playersContainer) { Preconditions.checkNotNull(playersContainer, "playersContainer parameter cannot be null"); this.playersContainer = playersContainer; } public SuperiorPlayer getSuperiorPlayer(CommandSender commandSender) { return getSuperiorPlayer((Player) commandSender); } public List matchAllPlayers(Predicate predicate) { return new SequentialListBuilder() .filter(predicate) .build(this.playersContainer.getAllPlayers()); } public void replacePlayers(SuperiorPlayer originPlayer, @Nullable SuperiorPlayer newPlayer) { Log.debug(Debug.REPLACE_PLAYER, originPlayer, newPlayer); // We first want to replace the player for his own island Island playerIsland = originPlayer.getIsland(); if (playerIsland != null) { playerIsland.replacePlayers(originPlayer, newPlayer); if (playerIsland.getOwner() != newPlayer) Log.debugResult(Debug.REPLACE_PLAYER, "Owner was not replaced", "Curr owner: " + playerIsland.getOwner().getUniqueId()); } for (Island island : plugin.getGrid().getIslands()) { if (island != playerIsland) island.replacePlayers(originPlayer, newPlayer); } if (newPlayer == null) { PlayersDatabaseBridge.deletePlayer(originPlayer); } else { newPlayer.merge(originPlayer); PluginEventsFactory.callPlayerReplaceEvent(originPlayer, newPlayer); } } // Updating last time status public void savePlayers() { for (Player player : Bukkit.getOnlinePlayers()) PlayersDatabaseBridge.saveLastTimeStatus(getSuperiorPlayer(player)); List modifiedPlayers = new SequentialListBuilder() .filter(PlayersDatabaseBridge::isModified) .build(getAllPlayers()); if (!modifiedPlayers.isEmpty()) modifiedPlayers.forEach(PlayersDatabaseBridge::executeFutureSaves); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java ================================================ package com.bgsoftware.superiorskyblock.player; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.HitActionResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.config.PvPWorldsCache; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.mission.MissionData; import com.bgsoftware.superiorskyblock.mission.MissionReference; import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; import com.bgsoftware.superiorskyblock.player.cache.PlayerCacheImpl; import com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryView; import org.bukkit.scheduler.BukkitTask; import java.lang.ref.WeakReference; import java.util.Collections; import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Function; public class SSuperiorPlayer implements SuperiorPlayer { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static PvPWorldsCache pvpWorldsCache = null; private final DatabaseBridge databaseBridge; private final PlayerTeleportAlgorithm playerTeleportAlgorithm; @Nullable private PersistentDataContainer persistentDataContainer; // Lazy loading private final LazyReference playerCache = new LazyReference() { @Override protected PlayerCache create() { return new PlayerCacheImpl(SSuperiorPlayer.this); } }; private final PlayerPermissionsStore permissionsStore; private final Map completedMissions = new ConcurrentHashMap<>(); private final List pendingInvites = new LinkedList<>(); private final List coopIslands = new LinkedList<>(); private final UUID uuid; private Island playerIsland = null; private String name; private String textureValue; private WeakReference playerRole; private int playerRoleId; private java.util.Locale userLocale; private boolean worldBorderEnabled; private boolean blocksStackerEnabled = plugin.getSettings().isDefaultStackedBlocks(); private boolean schematicModeEnabled = false; private boolean bypassModeEnabled = false; private boolean teamChatEnabled = false; private boolean toggledPanel; private boolean islandFly; private boolean adminSpyEnabled = false; private SBlockPosition schematicPos1 = null; private SBlockPosition schematicPos2 = null; private int disbands; private BorderColor borderColor; private long lastTimeStatus; private BukkitTask teleportTask = null; private EnumSet playerStatuses = EnumSet.noneOf(PlayerStatus.class); public SSuperiorPlayer(SuperiorPlayerBuilderImpl builder) { this.uuid = builder.uuid; this.name = builder.name; setPlayerRoleInternal(builder.playerRole); this.disbands = builder.disbands; this.userLocale = builder.locale; this.textureValue = builder.textureValue; this.lastTimeStatus = builder.lastTimeUpdated; this.toggledPanel = builder.toggledPanel; this.islandFly = builder.islandFly; this.borderColor = builder.borderColor; this.worldBorderEnabled = builder.worldBorderEnabled; this.completedMissions.putAll(builder.completedMissions); if (builder.persistentData.length > 0) getPersistentDataContainer().load(builder.persistentData); this.databaseBridge = plugin.getFactory().createDatabaseBridge(this); this.playerTeleportAlgorithm = plugin.getFactory().createPlayerTeleportAlgorithm(this); this.permissionsStore = new PlayerPermissionsStore(this); databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } /* * General Methods */ private static HitActionResult checkPvPAllow(SuperiorPlayer player, boolean target) { // Checks for online status if (!player.isOnline()) return target ? HitActionResult.TARGET_NOT_ONLINE : HitActionResult.NOT_ONLINE; // Checks for pvp warm-up if (player.hasPlayerStatus(PlayerStatus.PVP_IMMUNED)) return target ? HitActionResult.TARGET_PVP_WARMUP : HitActionResult.PVP_WARMUP; // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(player.getWorld())) return HitActionResult.SUCCESS; Island standingIsland; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { standingIsland = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } if (standingIsland != null && (plugin.getSettings().getSpawn().isProtected() || !standingIsland.isSpawn())) { // Checks for pvp status if (!standingIsland.hasSettingsEnabled(IslandFlags.PVP)) return target ? HitActionResult.TARGET_ISLAND_PVP_DISABLE : HitActionResult.ISLAND_PVP_DISABLE; if (!plugin.getSettings().isCoopDamage() && standingIsland.isCoop(player)) { // Checks for coop damage return target ? HitActionResult.TARGET_COOP_DAMAGE : HitActionResult.COOP_DAMAGE; } else if (!plugin.getSettings().isVisitorsDamage() && standingIsland.isVisitor(player, true)) { // Checks for visitors damage return target ? HitActionResult.TARGET_VISITOR_DAMAGE : HitActionResult.VISITOR_DAMAGE; } } return HitActionResult.SUCCESS; } @Override public UUID getUniqueId() { return uuid; } @Override public String getName() { return name; } @Override public PlayerCache getCache() { return this.playerCache.get(); } @Override public String getTextureValue() { return textureValue; } @Override public void setTextureValue(String textureValue) { Preconditions.checkNotNull(textureValue, "textureValue parameter cannot be null."); Log.debug(Debug.SET_TEXTURE_VALUE, getName(), textureValue); String oldTextureValue = this.textureValue; // We first update the texture value, even if they are equal. this.textureValue = textureValue; // We now compare them but remove the timestamp when comparing. if (Objects.equals(removeTextureValueTimeStamp(oldTextureValue), removeTextureValueTimeStamp(textureValue))) return; // We only save the value if it's actually different. PlayersDatabaseBridge.saveTextureValue(this); } @Override public void updateLastTimeStatus() { setLastTimeStatus(System.currentTimeMillis() / 1000); } @Override public void setLastTimeStatus(long lastTimeStatus) { Log.debug(Debug.SET_PLAYER_LAST_TIME_UPDATED, getName(), lastTimeStatus); if (this.lastTimeStatus == lastTimeStatus) return; this.lastTimeStatus = lastTimeStatus; PlayersDatabaseBridge.saveLastTimeStatus(this); } @Override public long getLastTimeStatus() { return lastTimeStatus; } @Override public void updateName() { Player player = asPlayer(); if (player != null) this.setName(player.getName()); } @Override public void setName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); if (Objects.equals(this.name, name)) return; try { plugin.getPlayers().getPlayersContainer().removePlayer(this); this.name = name; PlayersDatabaseBridge.savePlayerName(this); } finally { plugin.getPlayers().getPlayersContainer().addPlayer(this); } } @Override public Player asPlayer() { return Bukkit.getPlayer(uuid); } @Override public OfflinePlayer asOfflinePlayer() { return Bukkit.getOfflinePlayer(uuid); } @Override public boolean isOnline() { OfflinePlayer offlinePlayer = asOfflinePlayer(); return offlinePlayer != null && offlinePlayer.isOnline(); } @Override public void runIfOnline(Consumer toRun) { Player player = asPlayer(); if (player != null) toRun.accept(player); } @Override public boolean hasFlyGamemode() { Player player = asPlayer(); return player != null && (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR); } @Nullable @Override public MenuView getOpenedView() { Player player = asPlayer(); if (player != null) { InventoryView openInventory = player.getOpenInventory(); if (openInventory != null && openInventory.getTopInventory() != null) { InventoryHolder inventoryHolder = openInventory.getTopInventory().getHolder(); if (inventoryHolder instanceof MenuView) return (MenuView) inventoryHolder; } } return null; } @Override public boolean isAFK() { Player player = asPlayer(); return player != null && plugin.getProviders().isAFK(player); } @Override public boolean isVanished() { Player player = asPlayer(); return player != null && plugin.getProviders().getVanishProvider().isVanished(player); } @Override public boolean isShownAsOnline() { Player player = asPlayer(); return player != null && player.getGameMode() != GameMode.SPECTATOR && !isVanished(); } @Override public boolean hasPermission(String permission) { Preconditions.checkNotNull(permission, "permission parameter cannot be null."); Log.debugResult(Debug.PERMISSION_LOOKUP, "Checking for permission", permission); if (permission.isEmpty()) return true; Log.debug(Debug.PERMISSION_LOOKUP, getName(), permission); Player player = asPlayer(); if (player == null) { Log.debugResult(Debug.PERMISSION_LOOKUP, "Result", "Player is not online"); return false; } boolean res = player.hasPermission(permission); Log.debugResult(Debug.PERMISSION_LOOKUP, "Result", res); return res; } @Override public boolean hasPermissionWithoutOP(String permission) { Preconditions.checkNotNull(permission, "permission parameter cannot be null."); Log.debugResult(Debug.PERMISSION_LOOKUP, "Checking for permission", permission); if (permission.isEmpty()) return true; Log.debug(Debug.PERMISSION_LOOKUP, getName(), permission, "No-Op Check"); Player player = asPlayer(); PlayerPermissionsStore.PermissionResult permissionResult = this.permissionsStore.hasCustomPermission(player, permission); Log.debugResult(Debug.PERMISSION_LOOKUP, "Result", permissionResult); return permissionResult == PlayerPermissionsStore.PermissionResult.PRIVILEGED; } @Override public boolean hasPermission(IslandPrivilege permission) { Preconditions.checkNotNull(permission, "permission parameter cannot be null."); Island island = getIsland(); return island != null && island.hasPermission(this, permission); } @Override public boolean hasBypassPermission(IslandPrivilege permission) { Preconditions.checkNotNull(permission, "permission parameter cannot be null."); Log.debugResult(Debug.PERMISSION_LOOKUP, "Checking for IslandPrivilege bypass permission", permission); Player player = asPlayer(); PlayerPermissionsStore.PermissionResult permissionResult = this.permissionsStore.hasBypassPermission(player, permission); Log.debugResult(Debug.PERMISSION_LOOKUP, "Result", permissionResult); return permissionResult == PlayerPermissionsStore.PermissionResult.PRIVILEGED; } /* * Location Methods */ @Override public HitActionResult canHit(SuperiorPlayer otherPlayer) { Preconditions.checkNotNull(otherPlayer, "otherPlayer parameter cannot be null."); // Players can hit themselves if (equals(otherPlayer)) return HitActionResult.SUCCESS; World world = getWorld(); // Checks for island teammates pvp Island island = getIsland(); if (island != null && island == otherPlayer.getIsland() && (world == null || !isPvPWorldInternal(world.getName()))) return HitActionResult.ISLAND_TEAM_PVP; // Checks if this player can bypass all pvp restrictions { HitActionResult selfResult = checkPvPAllow(this, false); if (selfResult != HitActionResult.SUCCESS) return selfResult; } // Checks if target player can bypass all pvp restrictions { HitActionResult targetResult = checkPvPAllow(otherPlayer, true); if (targetResult != HitActionResult.SUCCESS) return targetResult; } return HitActionResult.SUCCESS; } @Override public World getWorld() { Player player = asPlayer(); return player == null ? null : player.getWorld(); } @Override public Location getLocation() { Player player = asPlayer(); return player == null ? null : player.getLocation(); } @Override public Location getLocation(@Nullable Location location) { if (location != null) { Player player = asPlayer(); if (player != null) player.getLocation(location); } return location; } @Override public void teleport(Location location) { teleport(location, null); } @Override public void teleport(Location location, @Nullable Consumer teleportResult) { Player player = asPlayer(); if (player != null) { playerTeleportAlgorithm.teleport(player, location).whenComplete((result, error) -> { if (teleportResult != null) teleportResult.accept(error == null && result); }); } else if (teleportResult != null) { teleportResult.accept(false); } } @Override public void teleport(Island island) { this.teleport(island, (Consumer) null); } @Override public void teleport(Island island, Dimension dimension) { this.teleport(island, dimension, null); } @Override public void teleport(Island island, @Nullable Consumer teleportResult) { this.teleport(island, plugin.getSettings().getWorlds().getDefaultWorldDimension(), teleportResult); } @Override public void teleport(Island island, Dimension dimension, @Nullable Consumer teleportResult) { Player player = asPlayer(); if (player != null) { setPlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED); playerTeleportAlgorithm.teleport(player, island, dimension).whenComplete((result, error) -> { boolean successful = error == null && result; player.setFallDistance(0f); removePlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED); if (teleportResult != null) teleportResult.accept(successful); }); } else if (teleportResult != null) { teleportResult.accept(false); } } @Override public boolean isInsideIsland() { Player player = asPlayer(); Island island = getIsland(); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return player != null && island != null && island.isInside(player.getLocation(wrapper.getHandle())); } } /* * Island Methods */ @Override public SuperiorPlayer getIslandLeader() { Island island = getIsland(); return island == null ? this : island.getOwner(); } @Override public void setIslandLeader(SuperiorPlayer islandLeader) { setIsland(islandLeader.getIsland()); } @Override public Island getIsland() { return playerIsland; } @Override public void setIsland(Island island) { Log.debug(Debug.SET_PLAYER_ISLAND, getName(), island == null ? "null" : island.getOwner().getName()); this.playerIsland = island; if (this.playerIsland == null) { setPlayerRoleInternal(null); } } @Override public boolean hasIsland() { return getIsland() != null; } @Override public void addInvite(Island island) { this.pendingInvites.add(island.getUniqueId()); } @Override public void removeInvite(Island island) { this.pendingInvites.remove(island.getUniqueId()); } @Override public List getInvites() { return new SequentialListBuilder() .map(this.pendingInvites, uuid -> plugin.getGrid().getIslandByUUID(uuid)); } @Override public void addCoop(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null"); Preconditions.checkArgument(island.isCoop(this), "player is not coop of given island"); this.coopIslands.add(island); } @Override public void removeCoop(Island island) { Preconditions.checkNotNull(island, "island parameter cannot be null"); this.coopIslands.remove(island); } @Override public List getCoopIslands() { return new SequentialListBuilder().build(this.coopIslands); } @Override public PlayerRole getPlayerRole() { PlayerRole playerRole = this.playerRole.get(); if (playerRole == null) { // Reference doesn't exist anymore, let's get it from roles manager again playerRole = plugin.getRoles().getPlayerRoleFromId(this.playerRoleId); this.playerRole = new WeakReference<>(playerRole); } if (this.playerIsland == null && playerRole != SPlayerRole.guestRole()) { setPlayerRoleInternal(null); playerRole = this.playerRole.get(); } return playerRole; } @Override public void setPlayerRole(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); Log.debug(Debug.SET_PLAYER_ROLE, getName(), playerRole.getName()); setPlayerRoleInternal(playerRole); Island island = getIsland(); if (island != null && island.getOwner() != this) IslandsDatabaseBridge.saveMemberRole(island, this); } @Override public int getDisbands() { return disbands; } @Override public void setDisbands(int disbands) { Log.debug(Debug.SET_DISBANDS, getName(), disbands); if (this.disbands == disbands) return; this.disbands = disbands; PlayersDatabaseBridge.saveDisbands(this); } @Override public boolean hasDisbands() { return disbands > 0; } /* * Preferences Methods */ @Override public java.util.Locale getUserLocale() { if (userLocale == null) userLocale = PlayerLocales.getDefaultLocale(); return userLocale; } @Override public void setUserLocale(java.util.Locale userLocale) { Preconditions.checkNotNull(userLocale, "userLocale parameter cannot be null."); Preconditions.checkArgument(PlayerLocales.isValidLocale(userLocale), "Locale " + userLocale + " is not a valid locale."); Log.debug(Debug.SET_LANGUAGE, getName(), userLocale.getLanguage() + "-" + userLocale.getCountry()); if (Objects.equals(this.userLocale, userLocale)) return; this.userLocale = userLocale; PlayersDatabaseBridge.saveUserLocale(this); } @Override public boolean hasWorldBorderEnabled() { return worldBorderEnabled; } @Override public void toggleWorldBorder() { setWorldBorderEnabled(!worldBorderEnabled); } @Override public void setWorldBorderEnabled(boolean enabled) { Log.debug(Debug.SET_TOGGLED_BORDER, getName(), enabled); if (this.worldBorderEnabled == enabled) return; this.worldBorderEnabled = enabled; PlayersDatabaseBridge.saveToggledBorder(this); } @Override public void updateWorldBorder(@Nullable Island island) { plugin.getNMSWorld().setWorldBorder(this, island); } @Override public boolean hasBlocksStackerEnabled() { return blocksStackerEnabled; } @Override public void toggleBlocksStacker() { setBlocksStacker(!blocksStackerEnabled); } @Override public void setBlocksStacker(boolean enabled) { Log.debug(Debug.SET_TOGGLED_STACKER, getName(), enabled); blocksStackerEnabled = enabled; } @Override public boolean hasSchematicModeEnabled() { return schematicModeEnabled; } @Override public void toggleSchematicMode() { setSchematicMode(!schematicModeEnabled); } @Override public void setSchematicMode(boolean enabled) { Log.debug(Debug.SET_TOGGLED_SCHEMATIC, getName(), enabled); schematicModeEnabled = enabled; } @Override public boolean hasTeamChatEnabled() { return teamChatEnabled; } @Override public void toggleTeamChat() { setTeamChat(!teamChatEnabled); } @Override public void setTeamChat(boolean enabled) { Log.debug(Debug.SET_TEAM_CHAT, getName(), enabled); teamChatEnabled = enabled; } @Override public boolean hasBypassModeEnabled() { Player player = asPlayer(); if (bypassModeEnabled && player != null && !player.hasPermission("superior.admin.bypass")) bypassModeEnabled = false; return bypassModeEnabled; } @Override public void toggleBypassMode() { setBypassMode(!bypassModeEnabled); } @Override public void setBypassMode(boolean enabled) { Log.debug(Debug.SET_ADMIN_BYPASS, getName(), enabled); bypassModeEnabled = enabled; } @Override public boolean hasToggledPanel() { return toggledPanel; } @Override public void setToggledPanel(boolean toggledPanel) { Log.debug(Debug.SET_TOGGLED_PANEL, getName(), toggledPanel); if (this.toggledPanel == toggledPanel) return; this.toggledPanel = toggledPanel; PlayersDatabaseBridge.saveToggledPanel(this); } @Override public boolean hasIslandFlyEnabled() { Player player = asPlayer(); if (islandFly && player != null && !player.hasPermission("superior.island.fly")) { islandFly = false; if (player.getAllowFlight()) { player.setFlying(false); player.setAllowFlight(false); } } return islandFly; } @Override public void toggleIslandFly() { setIslandFly(!islandFly); } @Override public void setIslandFly(boolean enabled) { Log.debug(Debug.SET_ISLAND_FLY, getName(), enabled); if (this.islandFly == enabled) return; this.islandFly = enabled; PlayersDatabaseBridge.saveIslandFly(this); } @Override public boolean hasAdminSpyEnabled() { return adminSpyEnabled; } @Override public void toggleAdminSpy() { setAdminSpy(!adminSpyEnabled); } @Override public void setAdminSpy(boolean enabled) { Log.debug(Debug.SET_ADMIN_SPY, getName(), enabled); adminSpyEnabled = enabled; } @Override public BorderColor getBorderColor() { return borderColor; } @Override public void setBorderColor(BorderColor borderColor) { Preconditions.checkNotNull(borderColor, "borderColor parameter cannot be null."); Log.debug(Debug.SET_BORDER_COLOR, getName(), borderColor); if (this.borderColor == borderColor) return; this.borderColor = borderColor; PlayersDatabaseBridge.saveBorderColor(this); } /* * Schematics Methods */ @Override public BlockPosition getSchematicPos1() { return schematicPos1; } @Override public void setSchematicPos1(@Nullable Block block) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? "null" : block.getLocation(wrapper.getHandle())); } this.schematicPos1 = block == null ? null : SBlockPosition.of(block); } @Override public SBlockPosition getSchematicPos2() { return schematicPos2; } @Override public void setSchematicPos2(@Nullable Block block) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? "null" : block.getLocation(wrapper.getHandle())); } this.schematicPos2 = block == null ? null : SBlockPosition.of(block); } /* * Missions Methods */ /* * Data Methods */ @Override @Deprecated public boolean isImmunedToPvP() { return this.hasPlayerStatus(PlayerStatus.PVP_IMMUNED); } @Override @Deprecated public void setImmunedToPvP(boolean immunedToPvP) { if (immunedToPvP) setPlayerStatus(PlayerStatus.PVP_IMMUNED); else removePlayerStatus(PlayerStatus.PVP_IMMUNED); } @Override @Deprecated public boolean isLeavingFlag() { return this.hasPlayerStatus(PlayerStatus.LEAVING_ISLAND); } @Override @Deprecated public void setLeavingFlag(boolean leavingFlag) { if (leavingFlag) setPlayerStatus(PlayerStatus.LEAVING_ISLAND); else removePlayerStatus(PlayerStatus.LEAVING_ISLAND); } @Override public boolean isImmunedToPortals() { return this.hasPlayerStatus(PlayerStatus.PORTALS_IMMUNED); } @Override public void setImmunedToPortals(boolean immuneToTeleport) { if (immuneToTeleport) setPlayerStatus(PlayerStatus.PORTALS_IMMUNED); else removePlayerStatus(PlayerStatus.PORTALS_IMMUNED); } @Override public BukkitTask getTeleportTask() { return teleportTask; } @Override public void setTeleportTask(BukkitTask teleportTask) { if (this.teleportTask != null) this.teleportTask.cancel(); this.teleportTask = teleportTask; } @Override public PlayerStatus getPlayerStatus() { for (PlayerStatus playerStatus : PlayerStatus.values()) { if (this.playerStatuses.contains(playerStatus)) return playerStatus; } return PlayerStatus.NONE; } @Override public void setPlayerStatus(PlayerStatus playerStatus) { Preconditions.checkNotNull(playerStatus, "playerStatus cannot be null"); Preconditions.checkArgument(playerStatus != PlayerStatus.NONE, "Cannot set PlayerStatus.NONE"); if (this.hasPlayerStatus(playerStatus)) return; Log.debug(Debug.SET_PLAYER_STATUS, getName(), playerStatus.name()); this.playerStatuses.add(playerStatus); } @Override public void removePlayerStatus(PlayerStatus playerStatus) { Preconditions.checkNotNull(playerStatus, "playerStatus cannot be null"); Preconditions.checkArgument(playerStatus != PlayerStatus.NONE, "Cannot remove PlayerStatus.NONE"); if (!this.hasPlayerStatus(playerStatus)) return; Log.debug(Debug.REMOVE_PLAYER_STATUS, getName(), playerStatus.name()); this.playerStatuses.remove(playerStatus); } @Override public boolean hasPlayerStatus(PlayerStatus playerStatus) { Preconditions.checkNotNull(playerStatus, "playerStatus cannot be null"); Preconditions.checkArgument(playerStatus != PlayerStatus.NONE, "Cannot check PlayerStatus.NONE"); return this.playerStatuses.contains(playerStatus); } @Override public void merge(SuperiorPlayer otherPlayer) { Preconditions.checkNotNull(otherPlayer, "otherPlayer parameter cannot be null."); this.name = otherPlayer.getName(); this.playerIsland = otherPlayer.getIsland(); setPlayerRoleInternal(otherPlayer.getPlayerRole()); this.userLocale = otherPlayer.getUserLocale(); this.worldBorderEnabled |= otherPlayer.hasWorldBorderEnabled(); this.blocksStackerEnabled |= otherPlayer.hasBlocksStackerEnabled(); this.schematicModeEnabled |= otherPlayer.hasSchematicModeEnabled(); this.bypassModeEnabled |= otherPlayer.hasBypassModeEnabled(); this.teamChatEnabled |= otherPlayer.hasTeamChatEnabled(); this.toggledPanel |= otherPlayer.hasToggledPanel(); this.islandFly |= otherPlayer.hasToggledPanel(); this.adminSpyEnabled |= otherPlayer.hasAdminSpyEnabled(); this.disbands = otherPlayer.getDisbands(); this.borderColor = otherPlayer.getBorderColor(); this.lastTimeStatus = otherPlayer.getLastTimeStatus(); this.completedMissions.clear(); otherPlayer.getCompletedMissionsWithAmounts().forEach((mission, finishCount) -> this.completedMissions.put(new MissionReference(mission), new Counter(finishCount))); if (!otherPlayer.isPersistentDataContainerEmpty()) { byte[] data = otherPlayer.getPersistentDataContainer().serialize(); getPersistentDataContainer().load(data); } // Convert data for missions plugin.getMissions().convertPlayerData(otherPlayer, this); // Replace player in DB. PlayersDatabaseBridge.replacePlayer(otherPlayer, this); } @Override public DatabaseBridge getDatabaseBridge() { return databaseBridge; } @Override public PersistentDataContainer getPersistentDataContainer() { if (persistentDataContainer == null) persistentDataContainer = plugin.getFactory().createPersistentDataContainer(this); return persistentDataContainer; } @Override public boolean isPersistentDataContainerEmpty() { return persistentDataContainer == null || persistentDataContainer.isEmpty(); } @Override public void savePersistentDataContainer() { PlayersDatabaseBridge.executeFutureSaves(this, PlayersDatabaseBridge.FutureSave.PERSISTENT_DATA); } @Override public void completeMission(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(!mission.getIslandMission(), "mission parameter must be player-mission."); this.changeAmountMissionsCompletedInternal(mission, false, counter -> counter.inc(1)); } @Override public void resetMission(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(!mission.getIslandMission(), "mission parameter must be player-mission."); this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.inc(-1)); } @Override public boolean hasCompletedMission(Mission mission) { return getAmountMissionCompleted(mission) > 0; } @Override public boolean canCompleteMissionAgain(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); if (mission.getIslandMission()) return false; Optional missionDataOptional = plugin.getMissions().getMissionData(mission); if (missionDataOptional.isPresent()) { int resetAmount = missionDataOptional.get().getResetAmount(); return resetAmount <= 0 || getAmountMissionCompleted(mission) < resetAmount; } return false; } @Override public int getAmountMissionCompleted(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Counter finishCount = mission.getIslandMission() ? null : completedMissions.get(new MissionReference(mission)); return finishCount == null ? 0 : finishCount.get(); } @Override public void setAmountMissionCompleted(Mission mission, int finishCount) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(!mission.getIslandMission(), "mission parameter must be player-mission."); this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.set(finishCount)); } private void changeAmountMissionsCompletedInternal(Mission mission, boolean clearData, Function action) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); MissionReference missionReference = new MissionReference(mission); Counter finishCount = completedMissions.computeIfAbsent(missionReference, r -> new Counter(0)); int oldFinishCount = action.apply(finishCount); int newFinishCount = finishCount.get(); Log.debug(Debug.SET_PLAYER_MISSION_COMPLETED, getName(), mission.getName(), newFinishCount); if (clearData) mission.clearData(this); if (newFinishCount > 0) { if (newFinishCount == oldFinishCount) return; PlayersDatabaseBridge.saveMission(this, mission, newFinishCount); } else { completedMissions.remove(missionReference); if (oldFinishCount <= 0) return; PlayersDatabaseBridge.removeMission(this, mission); } } @Override public List> getCompletedMissions() { return new SequentialListBuilder() .filter(MissionReference::isValid) .map(completedMissions.keySet(), MissionReference::getMission); } @Override public Map, Integer> getCompletedMissionsWithAmounts() { Map, Integer> completedMissions = new LinkedHashMap<>(); this.completedMissions.forEach((mission, finishCount) -> { if (mission.isValid()) completedMissions.put(mission.getMission(), finishCount.get()); }); return completedMissions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(completedMissions); } /* * Other Methods */ @Override public int hashCode() { return uuid.hashCode(); } @Override public boolean equals(Object obj) { return obj instanceof SuperiorPlayer && (this == obj || uuid.equals(((SuperiorPlayer) obj).getUniqueId())); } @Override public String toString() { return "SSuperiorPlayer{" + "uuid=[" + uuid + "]," + "name=[" + name + "]" + "}"; } private void setPlayerRoleInternal(@Nullable PlayerRole playerRole) { PlayerRole newRole = playerRole == null ? SPlayerRole.guestRole() : playerRole; this.playerRole = new WeakReference<>(newRole); this.playerRoleId = newRole.getId(); } public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SSuperiorPlayer::onSettingsUpdate); } private static String removeTextureValueTimeStamp(@Nullable String textureValue) { // The texture value string is a json containing a timestamp value. // However, when we compare texture values, we want to emit the timestamp value. // This value is found at index 35->41 (6 chars in length). return textureValue == null || textureValue.length() <= 42 ? null : textureValue.substring(0, 35) + textureValue.substring(42); } private static boolean isPvPWorldInternal(String worldName) { if (pvpWorldsCache == null) pvpWorldsCache = new PvPWorldsCache(plugin.getSettings().getPvPWorlds()); return pvpWorldsCache.isPvPWorld(worldName); } private static void onSettingsUpdate() { pvpWorldsCache = null; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java ================================================ package com.bgsoftware.superiorskyblock.player; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.HitActionResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.database.bridge.EmptyDatabaseBridge; import com.bgsoftware.superiorskyblock.core.persistence.EmptyPersistentDataContainer; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; public class SuperiorNPCPlayer implements SuperiorPlayer, ObjectsPool.Releasable { private static final ObjectsPool POOL = new ObjectsPool<>(SuperiorNPCPlayer::new); public static SuperiorNPCPlayer obtain(Player npc) { return POOL.obtain().initialize(npc); } private Player npc; private SuperiorNPCPlayer() { } private SuperiorNPCPlayer initialize(Player npc) { this.npc = npc; return this; } @Override public void release() { this.npc = null; } @Override public UUID getUniqueId() { return npc.getUniqueId(); } @Override public String getName() { return "NPC-Citizens"; } @Override public PlayerCache getCache() { throw new UnsupportedOperationException(); } @Override public String getTextureValue() { return ""; } @Override public void setTextureValue(String textureValue) { // Do nothing. } @Override public void updateLastTimeStatus() { // Do nothing. } @Override public void setLastTimeStatus(long lastTimeStatus) { // Do nothing. } @Override public long getLastTimeStatus() { return System.currentTimeMillis() / 1000; } @Override public void updateName() { // Do nothing. } @Override public void setName(String name) { // Do nothing. } @Override public Player asPlayer() { return null; } @Override public OfflinePlayer asOfflinePlayer() { return null; } @Override public boolean isOnline() { return false; } @Override public void runIfOnline(Consumer toRun) { // Do nothing. } @Override public boolean hasFlyGamemode() { return false; } @Nullable @Override public MenuView getOpenedView() { return null; } @Override public boolean isAFK() { return false; } @Override public boolean isVanished() { return false; } @Override public boolean isShownAsOnline() { return false; } @Override public boolean hasPermission(String permission) { return false; } @Override public boolean hasPermissionWithoutOP(String permission) { return false; } @Override public boolean hasPermission(IslandPrivilege permission) { return false; } @Override public boolean hasBypassPermission(IslandPrivilege islandPrivilege) { return false; } @Override public HitActionResult canHit(SuperiorPlayer other) { return HitActionResult.NOT_ONLINE; } @Override public World getWorld() { return npc.getWorld(); } @Override public Location getLocation() { return npc.getLocation(); } @Override public Location getLocation(Location location) { return this.npc.getLocation(location); } @Override public void teleport(Location location) { // Do nothing. } @Override public void teleport(Location unused, @Nullable Consumer teleportResult) { if (teleportResult != null) teleportResult.accept(false); } @Override public void teleport(Island island) { // Do nothing. } @Override public void teleport(Island island, Dimension dimension) { // Do nothing. } @Override public void teleport(Island unused, Dimension unused2, @Nullable Consumer teleportResult) { if (teleportResult != null) teleportResult.accept(false); } @Override public void teleport(Island unused, @Nullable Consumer teleportResult) { if (teleportResult != null) teleportResult.accept(false); } @Override public boolean isInsideIsland() { return false; } @Override public SuperiorPlayer getIslandLeader() { return this; } @Override public void setIslandLeader(SuperiorPlayer superiorPlayer) { // Do nothing. } @Override public Island getIsland() { return null; } @Override public void setIsland(Island island) { // Do nothing. } @Override public boolean hasIsland() { return false; } @Override public void addInvite(Island island) { // Do nothing. } @Override public void removeInvite(Island island) { // Do nothing. } @Override public List getInvites() { return Collections.emptyList(); } @Override public void addCoop(Island island) { throw new UnsupportedOperationException("Cannot mark NPCs as coop players"); } @Override public void removeCoop(Island island) { throw new UnsupportedOperationException("Cannot mark NPCs as coop players"); } @Override public List getCoopIslands() { throw new UnsupportedOperationException("Cannot mark NPCs as coop players"); } @Override public PlayerRole getPlayerRole() { return SPlayerRole.guestRole(); } @Override public void setPlayerRole(PlayerRole playerRole) { // Do nothing. } @Override public int getDisbands() { return 0; } @Override public void setDisbands(int disbands) { // Do nothing. } @Override public boolean hasDisbands() { return false; } @Override public Locale getUserLocale() { return PlayerLocales.getDefaultLocale(); } @Override public void setUserLocale(Locale locale) { // Do nothing. } @Override public boolean hasWorldBorderEnabled() { return false; } @Override public void toggleWorldBorder() { // Do nothing. } @Override public void setWorldBorderEnabled(boolean enabled) { // Do nothing. } @Override public void updateWorldBorder(@Nullable Island island) { // Do nothing. } @Override public boolean hasBlocksStackerEnabled() { return false; } @Override public void toggleBlocksStacker() { // Do nothing. } @Override public void setBlocksStacker(boolean enabled) { // Do nothing. } @Override public boolean hasSchematicModeEnabled() { return false; } @Override public void toggleSchematicMode() { // Do nothing. } @Override public void setSchematicMode(boolean enabled) { // Do nothing. } @Override public boolean hasTeamChatEnabled() { return false; } @Override public void toggleTeamChat() { // Do nothing. } @Override public void setTeamChat(boolean enabled) { // Do nothing. } @Override public boolean hasBypassModeEnabled() { return false; } @Override public void toggleBypassMode() { // Do nothing. } @Override public void setBypassMode(boolean enabled) { // Do nothing. } @Override public boolean hasToggledPanel() { return false; } @Override public void setToggledPanel(boolean toggledPanel) { // Do nothing. } @Override public boolean hasIslandFlyEnabled() { return false; } @Override public void toggleIslandFly() { // Do nothing. } @Override public void setIslandFly(boolean enabled) { // Do nothing. } @Override public boolean hasAdminSpyEnabled() { return false; } @Override public void toggleAdminSpy() { // Do nothing. } @Override public void setAdminSpy(boolean enabled) { // Do nothing. } @Override public BorderColor getBorderColor() { return BorderColor.BLUE; } @Override public void setBorderColor(BorderColor borderColor) { // Do nothing. } @Override public BlockPosition getSchematicPos1() { return null; } @Override public void setSchematicPos1(Block block) { // Do nothing. } @Override public BlockPosition getSchematicPos2() { return null; } @Override public void setSchematicPos2(Block block) { // Do nothing. } @Nullable @Override public BukkitTask getTeleportTask() { return null; } @Override public void setTeleportTask(@Nullable BukkitTask teleportTask) { // Do nothing. } @Override public boolean isImmunedToPvP() { return false; } @Override public void setImmunedToPvP(boolean immunedToPvP) { // Do nothing. } @Override public boolean isLeavingFlag() { return false; } @Override public void setLeavingFlag(boolean leavingFlag) { // Do nothing. } @Override public boolean isImmunedToPortals() { return false; } @Override public void setImmunedToPortals(boolean immuneToPortals) { // Do nothing. } @Override @Deprecated public PlayerStatus getPlayerStatus() { return PlayerStatus.NONE; } @Override public void setPlayerStatus(PlayerStatus playerStatus) { // Do nothing. } @Override public void removePlayerStatus(PlayerStatus playerStatus) { // Do nothing. } @Override public boolean hasPlayerStatus(PlayerStatus playerStatus) { return false; } @Override public void merge(SuperiorPlayer other) { // Do nothing. } @Override public DatabaseBridge getDatabaseBridge() { return EmptyDatabaseBridge.getInstance(); } @Override public PersistentDataContainer getPersistentDataContainer() { return EmptyPersistentDataContainer.getInstance(); } @Override public boolean isPersistentDataContainerEmpty() { return true; } @Override public void savePersistentDataContainer() { // Do nothing. } @Override public void completeMission(Mission mission) { // Do nothing. } @Override public void resetMission(Mission mission) { // Do nothing. } @Override public boolean hasCompletedMission(Mission mission) { return false; } @Override public boolean canCompleteMissionAgain(Mission mission) { return false; } @Override public int getAmountMissionCompleted(Mission mission) { return 0; } @Override public void setAmountMissionCompleted(Mission mission, int finishCount) { // Do nothing. } @Override public List> getCompletedMissions() { return Collections.emptyList(); } @Override public Map, Integer> getCompletedMissionsWithAmounts() { return Collections.emptyMap(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java ================================================ package com.bgsoftware.superiorskyblock.player.algorithm; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.entity.Player; import java.util.concurrent.CompletableFuture; public class DefaultPlayerTeleportAlgorithm implements PlayerTeleportAlgorithm { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final DefaultPlayerTeleportAlgorithm INSTANCE = new DefaultPlayerTeleportAlgorithm(); private DefaultPlayerTeleportAlgorithm() { } public static DefaultPlayerTeleportAlgorithm getInstance() { return INSTANCE; } @Override public CompletableFuture teleport(Player player, Location location) { CompletableFuture completableFuture = new CompletableFuture<>(); EntityTeleports.teleport(player, location, completableFuture::complete); return completableFuture; } @Override public CompletableFuture teleport(Player player, Island island) { return this.teleport(player, island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); } @Override public CompletableFuture teleport(Player player, Island island, Dimension dimension) { CompletableFuture result = new CompletableFuture<>(); IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(result::completeExceptionally).ifLeft(world -> teleportInternal(player, island, dimension, result)); }); return result; } public void teleportInternal(Player player, Island island, Dimension dimension, CompletableFuture result) { Location homeLocation = island.getIslandHome(dimension); Preconditions.checkNotNull(homeLocation, "Cannot find a suitable home location for island " + island.getUniqueId()); Log.debug(Debug.TELEPORT_PLAYER, player.getName(), island.getOwner().getName(), dimension); EntityTeleports.findIslandSafeLocation(island, dimension).whenComplete((safeSpot, error) -> { if (error != null) { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Location", null); result.completeExceptionally(error); } else if (safeSpot == null) { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Location", null); result.complete(false); } else { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Location", safeSpot); teleport(player, safeSpot).whenComplete((teleport, teleportError) -> { if (teleportError != null) { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Result", false); result.completeExceptionally(teleportError); } else { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Result", true); result.complete(teleport); } }); } }); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/builder/SuperiorPlayerBuilderImpl.java ================================================ package com.bgsoftware.superiorskyblock.player.builder; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.mission.MissionReference; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.google.common.base.Preconditions; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.UUID; public class SuperiorPlayerBuilderImpl implements SuperiorPlayer.Builder { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public UUID uuid = null; public String name = "null"; public PlayerRole playerRole = SPlayerRole.guestRole(); public int disbands = plugin.getSettings().getDisbandCount(); public Locale locale = PlayerLocales.getDefaultLocale(); public String textureValue = ""; public long lastTimeUpdated = -1; public boolean toggledPanel = plugin.getSettings().isDefaultToggledPanel(); public boolean islandFly = plugin.getSettings().isDefaultIslandFly(); public BorderColor borderColor = BorderColor.safeValue(plugin.getSettings().getDefaultBorderColor(), BorderColor.BLUE); public boolean worldBorderEnabled = plugin.getSettings().isDefaultWorldBorder(); public Map completedMissions = new LinkedHashMap<>(); public byte[] persistentData = new byte[0]; public SuperiorPlayerBuilderImpl() { } @Override public SuperiorPlayer.Builder setUniqueId(UUID uuid) { Preconditions.checkNotNull(uuid, "uuid parameter cannot be null."); Preconditions.checkState(plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(uuid) == null, "The provided uuid is not unique."); this.uuid = uuid; return this; } @Override public UUID getUniqueId() { return this.uuid; } @Override public SuperiorPlayer.Builder setName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); this.name = name; return this; } @Override public String getName() { return this.name; } @Override public SuperiorPlayer.Builder setPlayerRole(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); this.playerRole = playerRole; return this; } @Override public PlayerRole getPlayerRole() { return this.playerRole; } @Override public SuperiorPlayer.Builder setDisbands(int disbands) { this.disbands = disbands; return this; } @Override public int getDisbands() { return this.disbands; } @Override public SuperiorPlayer.Builder setLocale(Locale locale) { Preconditions.checkNotNull(locale, "locale parameter cannot be null."); Preconditions.checkArgument(PlayerLocales.isValidLocale(locale), "Locale " + locale + " is not a valid locale."); this.locale = locale; return this; } @Override public Locale getLocale() { return this.locale; } @Override public SuperiorPlayer.Builder setTextureValue(String textureValue) { Preconditions.checkNotNull(textureValue, "textureValue parameter cannot be null."); this.textureValue = textureValue; return this; } @Override public String getTextureValue() { return this.textureValue; } @Override public SuperiorPlayer.Builder setLastTimeUpdated(long lastTimeUpdated) { this.lastTimeUpdated = lastTimeUpdated; return this; } @Override public long getLastTimeUpdated() { return this.lastTimeUpdated; } @Override public SuperiorPlayer.Builder setToggledPanel(boolean toggledPanel) { this.toggledPanel = toggledPanel; return this; } @Override public boolean hasToggledPanel() { return this.toggledPanel; } @Override public SuperiorPlayer.Builder setIslandFly(boolean islandFly) { this.islandFly = islandFly; return this; } @Override public boolean hasIslandFly() { return this.islandFly; } @Override public SuperiorPlayer.Builder setBorderColor(BorderColor borderColor) { Preconditions.checkNotNull(borderColor, "borderColor parameter cannot be null."); this.borderColor = borderColor; return this; } @Override public BorderColor getBorderColor() { return this.borderColor; } @Override public SuperiorPlayer.Builder setWorldBorderEnabled(boolean worldBorderEnabled) { this.worldBorderEnabled = worldBorderEnabled; return this; } @Override public boolean hasWorldBorderEnabled() { return this.worldBorderEnabled; } @Override public SuperiorPlayer.Builder setCompletedMission(Mission mission, int finishCount) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); this.completedMissions.put(new MissionReference(mission), new Counter(finishCount)); return this; } @Override public Map, Integer> getCompletedMissions() { Map, Integer> completedMissions = new LinkedHashMap<>(); this.completedMissions.forEach((mission, finishCount) -> { if (mission.isValid()) completedMissions.put(mission.getMission(), finishCount.get()); }); return completedMissions.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(completedMissions); } @Override public SuperiorPlayer.Builder setPersistentData(byte[] persistentData) { Preconditions.checkNotNull(persistentData, "persistentData parameter cannot be null."); this.persistentData = persistentData; return this; } @Override public byte[] getPersistentData() { return this.persistentData; } @Override public SuperiorPlayer build() { if (this.uuid == null) throw new IllegalStateException("Cannot create a player with invalid uuid."); return plugin.getFactory().createPlayer(this); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/cache/PlayerCacheImpl.java ================================================ package com.bgsoftware.superiorskyblock.player.cache; import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCacheKey; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.BaseCacheImpl; import java.util.function.Function; public class PlayerCacheImpl implements PlayerCache { private final BaseCacheImpl> cache = new BaseCacheImpl<>(PlayerCacheKey.values()); private final SuperiorPlayer superiorPlayer; public PlayerCacheImpl(SuperiorPlayer superiorPlayer) { this.superiorPlayer = superiorPlayer; } @Override public SuperiorPlayer getPlayer() { return this.superiorPlayer; } @Override public T store(PlayerCacheKey key, T value) { return this.cache.store(key, value); } @Override public T remove(PlayerCacheKey key) { return this.cache.remove(key); } @Override public T get(PlayerCacheKey key) { return this.cache.get(key); } @Override public T getOrDefault(PlayerCacheKey key, T def) { return this.cache.getOrDefault(key, def); } @Override public T computeIfAbsent(PlayerCacheKey key, Function, T> mappingFunction) { return this.cache.computeIfAbsent(key, unused -> mappingFunction.apply(key)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/chat/PlayerChat.java ================================================ package com.bgsoftware.superiorskyblock.player.chat; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import org.bukkit.entity.Player; import java.util.Map; import java.util.UUID; import java.util.function.Function; public class PlayerChat { private static final Map playerChatListeners = new ArrayMap<>(); private final Function chatConsumer; private PlayerChat(Function chatConsumer) { this.chatConsumer = chatConsumer; } public static PlayerChat getChatListener(Player player) { return playerChatListeners.get(player.getUniqueId()); } public static void listen(Player player, Function onChat) { playerChatListeners.put(player.getUniqueId(), new PlayerChat(onChat)); } public static void remove(Player player) { playerChatListeners.remove(player.getUniqueId()); } public boolean supply(String message) { return chatConsumer.apply(message); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/container/DefaultPlayersContainer.java ================================================ package com.bgsoftware.superiorskyblock.player.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class DefaultPlayersContainer implements PlayersContainer { private final Map players = new ConcurrentHashMap<>(); private final Map playersByNames = new ConcurrentHashMap<>(); @Nullable @Override public SuperiorPlayer getSuperiorPlayer(String name) { SuperiorPlayer superiorPlayer = this.playersByNames.get(name.toLowerCase(Locale.ENGLISH)); if (superiorPlayer == null) { superiorPlayer = players.values().stream() .filter(player -> player.getName().equalsIgnoreCase(name)) .findFirst().orElse(null); if (superiorPlayer != null) this.playersByNames.put(name.toLowerCase(Locale.ENGLISH), superiorPlayer); } return superiorPlayer; } @Nullable @Override public SuperiorPlayer getSuperiorPlayer(UUID uuid) { return this.players.get(uuid); } @Override public List getAllPlayers() { return new SequentialListBuilder().build(this.players.values()); } @Override public void addPlayer(SuperiorPlayer superiorPlayer) { this.players.put(superiorPlayer.getUniqueId(), superiorPlayer); String playerName = superiorPlayer.getName(); if (!playerName.equals("null")) this.playersByNames.put(playerName.toLowerCase(Locale.ENGLISH), superiorPlayer); } @Override public void removePlayer(SuperiorPlayer superiorPlayer) { this.players.remove(superiorPlayer.getUniqueId()); this.playersByNames.remove(superiorPlayer.getName().toLowerCase(Locale.ENGLISH)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java ================================================ package com.bgsoftware.superiorskyblock.player.inventory; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; import java.util.Collection; public class ClearActions { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public static final ClearAction EFFECTS = register(new ClearAction("EFFECTS") { @Override public void doClear(Player player) { for (PotionEffect potionEffect : player.getActivePotionEffects()) player.removePotionEffect(potionEffect.getType()); } }); public static final ClearAction ENDER_CHEST = register(new ClearAction("ENDER_CHEST") { @Override public void doClear(Player player) { player.getEnderChest().clear(); } }); public static final ClearAction EXPERIENCE = register(new ClearAction("EXPERIENCE") { @Override public void doClear(Player player) { player.setExp(0); player.setLevel(0); player.setTotalExperience(0); } }); public static final ClearAction HEALTH = register(new ClearAction("HEALTH") { @Override public void doClear(Player player) { player.setHealth(player.getMaxHealth()); } }); public static final ClearAction HUNGER = register(new ClearAction("HUNGER") { @Override public void doClear(Player player) { player.setFoodLevel(20); } }); public static final ClearAction INVENTORY = register(new ClearAction("INVENTORY") { @Override public void doClear(Player player) { player.getInventory().clear(); } }); private ClearActions() { } public static void registerActions() { // Do nothing, only trigger all the register calls } public static void runClearActions(SuperiorPlayer superiorPlayer, Collection clearActions, @Nullable Island islandToTeleport) { if (clearActions.isEmpty() && islandToTeleport == null) return; OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer(); OfflinePlayerData offlinePlayerData; Player onlinePlayer; if (offlinePlayer.isOnline()) { offlinePlayerData = null; onlinePlayer = offlinePlayer.getPlayer(); } else { offlinePlayerData = plugin.getNMSPlayers().createOfflinePlayerData(offlinePlayer); onlinePlayer = offlinePlayerData.getFakeOnlinePlayer(); } try { clearActions.forEach(clearAction -> clearAction.doClear(onlinePlayer)); if (offlinePlayerData != null) { if (islandToTeleport != null) offlinePlayerData.setLocation(islandToTeleport.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension())); offlinePlayerData.applyChanges(); } else if (islandToTeleport != null) { superiorPlayer.teleport(islandToTeleport); } } finally { if (offlinePlayerData != null) offlinePlayerData.release(); } } private static ClearAction register(ClearAction clearAction) { ClearAction.register(clearAction); return clearAction; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/permissions/PlayerPermissionsStore.java ================================================ package com.bgsoftware.superiorskyblock.player.permissions; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.entity.Player; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.StampedLock; public class PlayerPermissionsStore { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Map PERMISSIONS_STORE_MAP = new ConcurrentHashMap<>(); private final EnumerateMap bypassPermissionsStore = new EnumerateMap<>(IslandPrivilege.values()); private final Map customPermissionsStore = new ConcurrentHashMap<>(); private final StampedLock lock = new StampedLock(); private final AtomicBoolean dirty = new AtomicBoolean(true); @Nullable public static PlayerPermissionsStore getPermissionsStore(UUID uuid) { return PERMISSIONS_STORE_MAP.get(uuid); } public PlayerPermissionsStore(SuperiorPlayer superiorPlayer) { PERMISSIONS_STORE_MAP.put(superiorPlayer.getUniqueId(), this); } public void markDirty() { this.dirty.set(true); } public void refreshCache(Player player) { // We want to refresh cache for common permissions hasBypassPermission(player, IslandPrivileges.BUILD); hasBypassPermission(player, IslandPrivileges.BREAK); hasCustomPermission(player, "superior.admin.bypass.*"); } public PermissionResult hasBypassPermission(@Nullable Player player, IslandPrivilege islandPrivilege) { if (this.dirty.get()) { checkDirty(); } long stamp = this.lock.readLock(); Boolean value; try { value = this.bypassPermissionsStore.get(islandPrivilege); } finally { this.lock.unlockRead(stamp); } if (value == null) { if (player == null) return PermissionResult.NOT_ONLINE; value = checkPermission(player, "superior.admin.bypass." + islandPrivilege.getName()); stamp = this.lock.writeLock(); try { this.bypassPermissionsStore.put(islandPrivilege, value); } finally { this.lock.unlockWrite(stamp); } } return value ? PermissionResult.PRIVILEGED : PermissionResult.RESTRICTED; } public PermissionResult hasCustomPermission(@Nullable Player player, String permission) { long stamp = this.lock.tryOptimisticRead(); Boolean value = this.customPermissionsStore.get(permission); boolean isDirty = this.dirty.get(); if (!this.lock.validate(stamp) || isDirty) { if (isDirty) { checkDirty(); } stamp = this.lock.readLock(); try { value = this.customPermissionsStore.get(permission); } finally { this.lock.unlockRead(stamp); } } if (value == null) { if (player == null) return PermissionResult.NOT_ONLINE; value = checkPermission(player, permission); stamp = this.lock.writeLock(); try { this.customPermissionsStore.put(permission, value); } finally { this.lock.unlockWrite(stamp); } } return value ? PermissionResult.PRIVILEGED : PermissionResult.RESTRICTED; } private void checkDirty() { if (dirty.compareAndSet(true, false)) { long stamp = this.lock.writeLock(); try { this.bypassPermissionsStore.clear(); this.customPermissionsStore.clear(); } finally { this.lock.unlockWrite(stamp); } } } private static boolean checkPermission(Player player, String permission) { return plugin.getProviders().getPermissionsProvider().hasPermission(player, permission); } public enum PermissionResult { PRIVILEGED, RESTRICTED, NOT_ONLINE } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/player/respawn/RespawnActions.java ================================================ package com.bgsoftware.superiorskyblock.player.respawn; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerRespawnEvent; public class RespawnActions { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); public static final RespawnAction BED_TELEPORT = register(new RespawnAction("BED_TELEPORT") { @Override public boolean canPerform(PlayerRespawnEvent event) { Player player = event.getPlayer(); return player.getBedSpawnLocation() != null; } @Override public void perform(PlayerRespawnEvent event) { event.setRespawnLocation(event.getPlayer().getBedSpawnLocation()); } }); public static final RespawnAction ISLAND_TELEPORT = register(new RespawnAction("ISLAND_TELEPORT") { @Override public boolean canPerform(PlayerRespawnEvent event) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getPlayer()); return superiorPlayer.getIsland() != null; } @Override public void perform(PlayerRespawnEvent event) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getPlayer()); assert superiorPlayer.getIsland() != null; superiorPlayer.teleport(superiorPlayer.getIsland(), result -> onTeleportCallback(superiorPlayer, result)); } }); public static final RespawnAction SPAWN_TELEPORT = register(new RespawnAction("SPAWN_TELEPORT") { @Override public boolean canPerform(PlayerRespawnEvent event) { return true; } @Override public void perform(PlayerRespawnEvent event) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getPlayer()); superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(), result -> onTeleportCallback(superiorPlayer, result)); } }); public static final RespawnAction VANILLA = register(new RespawnAction("VANILLA") { @Override public boolean canPerform(PlayerRespawnEvent event) { return true; } @Override public void perform(PlayerRespawnEvent event) { // Do nothing, let vanilla do its thing. } }); private RespawnActions() { } public static void registerActions() { // Do nothing, only trigger all the register calls } private static RespawnAction register(RespawnAction respawnAction) { RespawnAction.register(respawnAction); return respawnAction; } private static void onTeleportCallback(SuperiorPlayer superiorPlayer, boolean result) { if (result) { BukkitExecutor.sync(() -> { if (superiorPlayer.isOnline()) superiorPlayer.updateWorldBorder(superiorPlayer.getIsland()); }, 2L); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/IService.java ================================================ package com.bgsoftware.superiorskyblock.service; public interface IService { Class getAPIClass(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/ServicesHandler.java ================================================ package com.bgsoftware.superiorskyblock.service; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarsServiceImpl; import com.bgsoftware.superiorskyblock.service.dragon.DragonBattleServiceImpl; import com.bgsoftware.superiorskyblock.service.hologram.HologramsServiceImpl; import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; import com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl; import com.bgsoftware.superiorskyblock.service.portals.PortalsManagerServiceImpl; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; import com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksInteractionServiceImpl; import com.bgsoftware.superiorskyblock.service.world.WorldRecordServiceImpl; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.plugin.ServicePriority; import java.util.IdentityHashMap; import java.util.Map; public class ServicesHandler { private final Map, IService> services = new IdentityHashMap<>(); private final SuperiorSkyblockPlugin plugin; public ServicesHandler(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } public T getService(Class serviceClass) { Object service = services.get(serviceClass); if (service == null) throw new RuntimeException("Tried to get service of invalid class: " + serviceClass); return serviceClass.cast(service); } public void loadDefaultServices(SuperiorSkyblockPlugin plugin) { registerService(new PlaceholdersServiceImpl()); registerService(new HologramsServiceImpl(plugin)); registerService(new DragonBattleServiceImpl(plugin)); registerService(new BossBarsServiceImpl(plugin)); registerService(new MessagesServiceImpl()); registerService(new PortalsManagerServiceImpl(plugin)); registerService(new RegionManagerServiceImpl(plugin)); registerService(new StackedBlocksInteractionServiceImpl(plugin)); registerService(new WorldRecordServiceImpl(plugin)); } private void registerService(T serviceImpl) { Class apiClass = serviceImpl.getAPIClass(); Preconditions.checkArgument(!services.containsKey(apiClass), "Service for class " + apiClass + " already exists."); services.put(apiClass, serviceImpl); Bukkit.getServicesManager().register(apiClass, serviceImpl, plugin, ServicePriority.Normal); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/bossbar/BossBarTask.java ================================================ package com.bgsoftware.superiorskyblock.service.bossbar; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.UUID; public class BossBarTask extends BukkitRunnable { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final BossBarTask EMPTY_TASK = new BossBarTask(EmptyBossBar.getInstance(), 0); private static final Map> PLAYERS_RUNNING_TASKS = new ArrayMap<>(); private final BossBar bossBar; private final double progressToRemovePerTick; private boolean reachedEndTask = false; public static BossBarTask create(BossBar bossBar, double ticksToRun) { return ticksToRun <= 0 ? EMPTY_TASK : new BossBarTask(bossBar, ticksToRun); } private BossBarTask(BossBar bossBar, double ticksToRun) { this.bossBar = bossBar; this.progressToRemovePerTick = this.bossBar.getProgress() / ticksToRun; if (progressToRemovePerTick > 0) { runTaskTimer(plugin, 1L, 1L); } } @Override public void run() { if (reachedEndTask) { cancel(); } else { this.bossBar.setProgress(Math.max(0D, this.bossBar.getProgress() - progressToRemovePerTick)); reachedEndTask = this.bossBar.getProgress() == 0D; } } @Override public synchronized void cancel() throws IllegalStateException { this.bossBar.removeAll(); super.cancel(); } public void registerTask(Player player) { Queue bossBarTasks = PLAYERS_RUNNING_TASKS.computeIfAbsent(player.getUniqueId(), s -> new LinkedList<>()); if (bossBarTasks.size() >= plugin.getSettings().getBossbarLimit()) { BossBarTask lastRunningTask = bossBarTasks.poll(); if (lastRunningTask != null) lastRunningTask.cancel(); } bossBarTasks.add(this); } public void unregisterTask(Player player) { Queue bossBarTasks = PLAYERS_RUNNING_TASKS.get(player.getUniqueId()); if (bossBarTasks == null) return; bossBarTasks.remove(this); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/bossbar/BossBarsServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.bossbar; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBarsService; import com.bgsoftware.superiorskyblock.service.IService; import org.bukkit.entity.Player; public class BossBarsServiceImpl implements BossBarsService, IService { private final SuperiorSkyblockPlugin plugin; public BossBarsServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Class getAPIClass() { return BossBarsService.class; } @Override public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { return plugin.getNMSPlayers().createBossBar(player, message, color, ticksToRun); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/bossbar/EmptyBossBar.java ================================================ package com.bgsoftware.superiorskyblock.service.bossbar; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import org.bukkit.entity.Player; public class EmptyBossBar implements BossBar { private static final EmptyBossBar INSTANCE = new EmptyBossBar(); public static EmptyBossBar getInstance() { return INSTANCE; } private EmptyBossBar() { } @Override public void addPlayer(Player player) { } @Override public void removeAll() { } @Override public void setProgress(double progress) { } @Override public double getProgress() { return 0; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleResetResult; import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.service.IService; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.EnderDragon; public class DragonBattleServiceImpl implements DragonBattleService, IService { private final SuperiorSkyblockPlugin plugin; public DragonBattleServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Class getAPIClass() { return DragonBattleService.class; } @Override public void prepareEndWorld(World bukkitWorld) { Preconditions.checkNotNull(bukkitWorld, "world parameter cannot be null"); Preconditions.checkArgument(bukkitWorld.getEnvironment() == World.Environment.THE_END, "world must be the_end environment"); plugin.getNMSDragonFight().prepareEndWorld(bukkitWorld); } @Nullable @Override public EnderDragon getEnderDragon(Island island, Dimension dimension) { Preconditions.checkNotNull(island, "island parameter cannot be null"); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); Preconditions.checkArgument(dimension.getEnvironment() == World.Environment.THE_END, "dimension must be the_end environment"); return plugin.getNMSDragonFight().getEnderDragon(island, dimension); } @Override public void stopEnderDragonBattle(Island island, Dimension dimension) { Preconditions.checkNotNull(island, "island parameter cannot be null"); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); Preconditions.checkArgument(dimension.getEnvironment() == World.Environment.THE_END, "dimension must be the_end environment"); plugin.getNMSDragonFight().removeDragonBattle(island, dimension); } @Override public DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension dimension) { Preconditions.checkNotNull(island, "island parameter cannot be null"); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); Preconditions.checkArgument(dimension.getEnvironment() == World.Environment.THE_END, "dimension must be the_end environment"); SettingsManager.Worlds.End dimensionConfig = (SettingsManager.Worlds.End) plugin.getSettings().getWorlds().getDimensionConfig(dimension); if (dimensionConfig == null || !dimensionConfig.isEnabled() || !dimensionConfig.isDragonFight()) return DragonBattleResetResult.DRAGON_BATTLES_DISABLED; if (!island.isDimensionEnabled(dimension)) return DragonBattleResetResult.WORLD_NOT_UNLOCKED; if (!island.wasSchematicGenerated(dimension)) return DragonBattleResetResult.WORLD_NOT_GENERATED; stopEnderDragonBattle(island, dimension); IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { Location islandCenter = island.getCenter(dimension); plugin.getNMSDragonFight().startDragonBattle(island, dimensionConfig.getPortalOffset().applyToLocation(islandCenter)); }); }); return DragonBattleResetResult.SUCCESS; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/hologram/HologramsServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.hologram; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService; import com.bgsoftware.superiorskyblock.service.IService; import org.bukkit.Location; import org.bukkit.entity.Entity; public class HologramsServiceImpl implements HologramsService, IService { private final SuperiorSkyblockPlugin plugin; public HologramsServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Class getAPIClass() { return HologramsService.class; } @Override public Hologram createHologram(Location location) { return plugin.getNMSHolograms().createHologram(location); } @Override public boolean isHologram(Entity entity) { return plugin.getNMSHolograms().isHologram(entity); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.message; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.messages.component.MultipleComponents; import com.bgsoftware.superiorskyblock.core.messages.component.impl.ActionBarComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.BossBarComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.ComplexMessageComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.RawMessageComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.SoundComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.TitleComponent; import com.bgsoftware.superiorskyblock.service.IService; import com.google.common.base.Preconditions; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Sound; import org.bukkit.configuration.file.YamlConfiguration; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Optional; public class MessagesServiceImpl implements MessagesService, IService { private final List customComponentParsers = new LinkedList<>(); public MessagesServiceImpl() { } @Override public Class getAPIClass() { return MessagesService.class; } @Nullable @Override public IMessageComponent parseComponent(YamlConfiguration config, String path) { if (config.isConfigurationSection(path)) { return MultipleComponents.parseSection(config.getConfigurationSection(path), this.customComponentParsers); } else { for (CustomComponentParser parser : this.customComponentParsers) { Optional res = parser.parse(config, path); if (res.isPresent()) return res.get(); } return RawMessageComponent.of(Formatters.COLOR_FORMATTER.format(config.getString(path, ""))); } } @Nullable @Override public IMessageComponent getComponent(String messageName, Locale locale) { Message message = EnumHelper.getEnum(Message.class, messageName.toUpperCase(Locale.ENGLISH)); return message == null || message.isCustom() ? null : message.getComponent(locale); } @Override public Builder newBuilder() { return new BuilderImpl(); } public void registerCustomComponentParser(CustomComponentParser parser) { this.customComponentParsers.add(parser); } public List getCustomComponentParsers() { return customComponentParsers; } public interface CustomComponentParser { Optional parse(YamlConfiguration config, String path); Optional parse(String raw); } private static class BuilderImpl implements Builder { private final List messageComponents = new LinkedList<>(); @Override public boolean addActionBar(@Nullable String message) { return addMessageComponent(ActionBarComponent.of(message)); } @Override public boolean addBossBar(@Nullable String message, BossBar.Color color, int ticks) { return addMessageComponent(BossBarComponent.of(message, color, ticks)); } @Override public boolean addComplexMessage(@Nullable TextComponent textComponent) { return addComplexMessage(new BaseComponent[]{textComponent}); } @Override public boolean addComplexMessage(@Nullable BaseComponent[] baseComponents) { return addMessageComponent(ComplexMessageComponent.of(baseComponents)); } @Override public boolean addRawMessage(@Nullable String message) { return addMessageComponent(RawMessageComponent.of(message)); } @Override public boolean addSound(Sound sound, float volume, float pitch) { return addMessageComponent(SoundComponent.of(new GameSoundImpl(sound, volume, pitch))); } @Override public boolean addTitle(@Nullable String titleMessage, @Nullable String subtitleMessage, int fadeIn, int duration, int fadeOut) { return addMessageComponent(TitleComponent.of(titleMessage, subtitleMessage, fadeIn, duration, fadeOut)); } @Override public boolean addMessageComponent(IMessageComponent messageComponent) { Preconditions.checkNotNull(messageComponent, "Cannot add null message components."); if (messageComponent.getType() != IMessageComponent.Type.EMPTY) { messageComponents.add(messageComponent); return true; } return false; } @Override public IMessageComponent build() { return MultipleComponents.of(messageComponents); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.placeholders; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.service.placeholders.IslandPlaceholderParser; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlayerPlaceholderParser; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import com.bgsoftware.superiorskyblock.external.placeholders.PlaceholdersProvider; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.service.IService; import com.google.common.collect.ImmutableMap; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.time.Duration; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; public class PlaceholdersServiceImpl implements PlaceholdersService, IService { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Pattern ISLAND_PLACEHOLDER_PATTERN = Pattern.compile("island_(.+)"); private static final Pattern PLAYER_PLACEHOLDER_PATTERN = Pattern.compile("player_(.+)"); private static final Pattern BLOCK_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_block_count_(.+)"); private static final Pattern BLOCK_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("island_block_level_(.+)"); private static final Pattern BLOCK_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_block_limit_(.+)"); private static final Pattern BLOCK_TOTAL_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("island_block_total_level_(.+)"); private static final Pattern BLOCK_TOTAL_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("island_block_total_worth_(.+)"); private static final Pattern BLOCK_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("island_block_worth_(.+)"); private static final Pattern COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_count_(.+)"); private static final Pattern DATA_PLACEHOLDER_PATTERN = Pattern.compile("island_data_(.+)"); private static final Pattern EFFECT_PLACEHOLDER_PATTERN = Pattern.compile("island_effect_(.+)"); private static final Pattern ENTITY_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_count_(.+)"); private static final Pattern ENTITY_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_limit_(.+)"); private static final Pattern FLAG_PLACEHOLDER_PATTERN = Pattern.compile("flag_(.+)"); private static final Pattern GENERATOR_AMOUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_generator_amount_(.+)"); private static final Pattern GENERATOR_PERCENTAGE_PLACEHOLDER_PATTERN = Pattern.compile("island_generator_percentage_(.+)"); private static final Pattern WORLD_UNLOCKED_PLACEHOLDER_PATTERN = Pattern.compile("island_world_unlocked_(.+)"); private static final Pattern WORLD_ENABLED_PLACEHOLDER_PATTERN = Pattern.compile("island_world_enabled_(.+)"); private static final Pattern WORLD_GENERATED_PLACEHOLDER_PATTERN = Pattern.compile("island_world_generated_(.+)"); private static final Pattern MEMBER_PLACEHOLDER_PATTERN = Pattern.compile("member_(.+)"); private static final Pattern MISSIONS_COMPLETED_PATTERN = Pattern.compile("missions_completed_(.+)"); private static final Pattern MISSION_STATUS_PATTERN = Pattern.compile("mission_status_(.+)"); private static final Pattern PERMISSION_PLACEHOLDER_PATTERN = Pattern.compile("island_permission_(.+)"); private static final Pattern PERMISSION_ROLE_PLACEHOLDER_PATTERN = Pattern.compile("island_permission_role_(.+)"); private static final Pattern ROLE_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_role_count_(.+)"); private static final Pattern ROLE_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_role_limit_(.+)"); private static final Pattern UPGRADE_PLACEHOLDER_PATTERN = Pattern.compile("island_upgrade_(.+)"); private static final Pattern TOP_PLACEHOLDER_PATTERN = Pattern.compile("island_top_(.+)"); private static final Pattern TOP_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("worth_(.+)"); private static final Pattern TOP_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("level_(.+)"); private static final Pattern TOP_RATING_PLACEHOLDER_PATTERN = Pattern.compile("rating_(.+)"); private static final Pattern TOP_PLAYERS_PLACEHOLDER_PATTERN = Pattern.compile("players_(.+)"); private static final Pattern TOP_VALUE_FORMAT_PLACEHOLDER_PATTERN = Pattern.compile("value_format_(.+)"); private static final Pattern TOP_VALUE_RAW_PLACEHOLDER_PATTERN = Pattern.compile("value_raw_(.+)"); private static final Pattern TOP_VALUE_PLACEHOLDER_PATTERN = Pattern.compile("value_(.+)"); private static final Pattern TOP_LEADER_PLACEHOLDER_PATTERN = Pattern.compile("leader_(.+)"); private static final Pattern TOP_CUSTOM_PLACEHOLDER_PATTERN = Pattern.compile("(\\d+)_(.+)"); private static final Pattern VISITOR_LAST_JOIN_PLACEHOLDER_PATTERN = Pattern.compile("visitor_last_join_(.+)"); private static final Map PLAYER_PARSES = new ImmutableMap.Builder() .put("blocks_stacker", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasBlocksStackerEnabled(), superiorPlayer.getUserLocale())) .put("border_color", superiorPlayer -> Formatters.BORDER_COLOR_FORMATTER.format(superiorPlayer.getBorderColor(), superiorPlayer.getUserLocale())) .put("bypass", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasBypassModeEnabled(), superiorPlayer.getUserLocale())) .put("chat_spy", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasAdminSpyEnabled(), superiorPlayer.getUserLocale())) .put("disbands", superiorPlayer -> superiorPlayer.getDisbands() + "") .put("fly", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasIslandFlyEnabled(), superiorPlayer.getUserLocale())) .put("locale", superiorPlayer -> Formatters.LOCALE_FORMATTER.format(superiorPlayer.getUserLocale())) .put("missions_completed", superiorPlayer -> superiorPlayer.getCompletedMissions().size() + "") .put("panel", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasToggledPanel(), superiorPlayer.getUserLocale())) .put("role", superiorPlayer -> superiorPlayer.getPlayerRole().toString()) .put("role_display", superiorPlayer -> superiorPlayer.getPlayerRole().getDisplayName()) .put("schematics", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasSchematicModeEnabled(), superiorPlayer.getUserLocale())) .put("team_chat", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasTeamChatEnabled(), superiorPlayer.getUserLocale())) .put("texture", SuperiorPlayer::getTextureValue) .put("world_border", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasWorldBorderEnabled(), superiorPlayer.getUserLocale())) .build(); @SuppressWarnings("ConstantConditions") private static final Map ISLAND_PARSES = new ImmutableMap.Builder() // Island Placeholders .put("bank", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance())) .put("bank_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandBank().getBalance(), superiorPlayer.getUserLocale())) .put("bank_int", (island, superiorPlayer) -> island.getIslandBank().getBalance().toBigInteger().toString()) .put("bank_raw", (island, superiorPlayer) -> island.getIslandBank().getBalance().toString()) .put("bank_limit", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getBankLimit())) .put("bank_limit_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimit(), superiorPlayer.getUserLocale())) .put("bank_limit_int", (island, superiorPlayer) -> island.getBankLimit().toBigInteger().toString()) .put("bank_limit_raw", (island, superiorPlayer) -> island.getBankLimit().toString()) .put("bank_last_interest", (island, superiorPlayer) -> Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getLastInterestTime()), superiorPlayer.getUserLocale())) .put("bank_next_interest", (island, superiorPlayer) -> Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getNextInterest()), superiorPlayer.getUserLocale())) .put("bans_count", (island, superiorPlayer) -> island.getBannedPlayers().size() + "") .put("bans_list", (island, superiorPlayer) -> { StringBuilder teamBuilder = new StringBuilder(); List players = island.getBannedPlayers(); if (players.isEmpty()) { return ""; } for (SuperiorPlayer player : players) { teamBuilder.append(", ").append(player.getName()); } return teamBuilder.substring(2); }) .put("biome", (island, superiorPlayer) -> Formatters.CAPITALIZED_FORMATTER.format(island.getBiome().name())) .put("bonus_level", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getBonusLevel())) .put("bonus_level_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getBonusLevel(), superiorPlayer.getUserLocale())) .put("bonus_level_int", (island, superiorPlayer) -> island.getBonusLevel().toBigInteger().toString()) .put("bonus_level_raw", (island, superiorPlayer) -> island.getBonusLevel().toString()) .put("bonus_worth", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getBonusWorth())) .put("bonus_worth_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getBonusWorth(), superiorPlayer.getUserLocale())) .put("bonus_worth_int", (island, superiorPlayer) -> island.getBonusWorth().toBigInteger().toString()) .put("bonus_worth_raw", (island, superiorPlayer) -> island.getBonusWorth().toString()) .put("center", (island, superiorPlayer) -> Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), getDefaultWorldInfo(island))) .put("center_x", (island, superiorPlayer) -> island.getCenterPosition().getX() + "") .put("center_y", (island, superiorPlayer) -> island.getCenterPosition().getY() + "") .put("center_z", (island, superiorPlayer) -> island.getCenterPosition().getZ() + "") .put("chest_size", (island, superiorPlayer) -> island.getChestSize() + "") .put("coop_limit", (island, superiorPlayer) -> island.getCoopLimit() + "") .put("coop_list", (island, superiorPlayer) -> { StringBuilder teamBuilder = new StringBuilder(); List players = island.getCoopPlayers(); if (players.isEmpty()) { return ""; } for (SuperiorPlayer player : players) { teamBuilder.append(", ").append(player.getName()); } return teamBuilder.substring(2); }) .put("coop_size", (island, superiorPlayer) -> island.getCoopPlayers().size() + "") .put("creation_time", (island, superiorPlayer) -> island.getCreationTimeDate()) .put("crops_multiplier", (island, superiorPlayer) -> island.getCropGrowthMultiplier() + "") .put("description", (island, superiorPlayer) -> island.getDescription()) .put("discord", (island, superiorPlayer) -> island.hasPermission(superiorPlayer, IslandPrivileges.DISCORD_SHOW) ? island.getDiscord() : "None") .put("discord_all", (island, superiorPlayer) -> island.getDiscord()) .put("drops_multiplier", (island, superiorPlayer) -> island.getMobDropsMultiplier() + "") .put("exists", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island != null, superiorPlayer.getUserLocale())) .put("home", (island, superiorPlayer) -> { WorldInfo worldInfo = getDefaultWorldInfo(island); return Formatters.LOCATION_FORMATTER.format(island.getIslandHomePosition(worldInfo.getDimension()).toLocation(worldInfo)); }) .put("home_x", (island, superiorPlayer) -> island.getIslandHomePosition(getDefaultWorldDimension()).getX() + "") .put("home_y", (island, superiorPlayer) -> island.getIslandHomePosition(getDefaultWorldDimension()).getY() + "") .put("home_z", (island, superiorPlayer) -> island.getIslandHomePosition(getDefaultWorldDimension()).getZ() + "") .put("is_coop", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isCoop(superiorPlayer), superiorPlayer.getUserLocale())) .put("is_leader", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.getOwner().equals(superiorPlayer), superiorPlayer.getUserLocale())) .put("is_member", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isMember(superiorPlayer), superiorPlayer.getUserLocale())) .put("is_visitor", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isVisitor(superiorPlayer, true), superiorPlayer.getUserLocale())) .put("last_time_updated", (island, superiorPlayer) -> Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getLastTimeUpdate()), superiorPlayer.getUserLocale())) .put("leader", (island, superiorPlayer) -> island.getOwner().getName()) .put("level", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getIslandLevel())) .put("level_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandLevel(), superiorPlayer.getUserLocale())) .put("level_int", (island, superiorPlayer) -> island.getIslandLevel().toBigInteger().toString()) .put("level_raw", (island, superiorPlayer) -> island.getIslandLevel().toString()) .put("locked", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isLocked(), superiorPlayer.getUserLocale())) .put("missions_completed", (island, superiorPlayer) -> island.getCompletedMissions().size() + "") .put("name", (island, superiorPlayer) -> island.getName()) .put("name_formatted", (island, superiorPlayer) -> island.getFormattedName()) .put("name_leader", (island, superiorPlayer) -> island.getName().isEmpty() ? island.getOwner().getName() : island.getName()) .put("name_stripped", (island, superiorPlayer) -> island.getStrippedName()) .put("paypal", (island, superiorPlayer) -> island.hasPermission(superiorPlayer, IslandPrivileges.PAYPAL_SHOW) ? island.getPaypal() : "None") .put("paypal_all", (island, superiorPlayer) -> island.getPaypal()) .put("players_count", (island, superiorPlayer) -> island.getAllPlayersInside().size() + "") .put("players_list", (island, superiorPlayer) -> { StringBuilder teamBuilder = new StringBuilder(); List players = island.getAllPlayersInside(); if (players.isEmpty()) { return ""; } for (SuperiorPlayer player : players) { teamBuilder.append(", ").append(player.getName()); } return teamBuilder.substring(2); }) .put("radius", (island, superiorPlayer) -> island.getIslandSize() + "") .put("rating", (island, superiorPlayer) -> island.getTotalRating() + "") .put("rating_amount", (island, superiorPlayer) -> island.getRatingAmount() + "") .put("rating_stars", (island, superiorPlayer) -> Formatters.RATING_FORMATTER.format(island.getTotalRating(), superiorPlayer.getUserLocale())) .put("raw_bank_limit", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getBankLimitRaw())) .put("raw_bank_limit_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimitRaw(), superiorPlayer.getUserLocale())) .put("raw_bank_limit_int", (island, superiorPlayer) -> island.getBankLimitRaw().toBigInteger().toString()) .put("raw_bank_limit_raw", (island, superiorPlayer) -> island.getBankLimitRaw().toString()) .put("raw_coop_limit", (island, superiorPlayer) -> island.getCoopLimitRaw() + "") .put("raw_crops_multiplier", (island, superiorPlayer) -> island.getCropGrowthRaw() + "") .put("raw_drops_multiplier", (island, superiorPlayer) -> island.getMobDropsRaw() + "") .put("raw_level", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getRawLevel())) .put("raw_level_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getRawLevel(), superiorPlayer.getUserLocale())) .put("raw_level_int", (island, superiorPlayer) -> island.getRawLevel().toBigInteger().toString()) .put("raw_level_raw", (island, superiorPlayer) -> island.getRawLevel().toString()) .put("raw_radius", (island, superiorPlayer) -> island.getIslandSizeRaw() + "") .put("raw_spawners_multiplier", (island, superiorPlayer) -> island.getSpawnerRatesRaw() + "") .put("raw_team_limit", (island, superiorPlayer) -> island.getTeamLimitRaw() + "") .put("raw_warps_limit", (island, superiorPlayer) -> island.getWarpsLimitRaw() + "") .put("raw_worth", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getRawWorth())) .put("raw_worth_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getRawWorth(), superiorPlayer.getUserLocale())) .put("raw_worth_int", (island, superiorPlayer) -> island.getRawWorth().toBigInteger().toString()) .put("raw_worth_raw", (island, superiorPlayer) -> island.getRawWorth().toString()) .put("schematic", (island, superiorPlayer) -> island.getSchematicName()) .put("size", (island, superiorPlayer) -> { int size = island.getIslandSize() * 2 + 1; return size + " x " + size; }) .put("size_format", (island, superiorPlayer) -> { int size = island.getIslandSize() * 2 + 1; int rounded = 5 * (Math.round(size / 5.0F)); if (Math.abs(size - rounded) == 1) size = rounded; return size + " x " + size; }) .put("spawners_multiplier", (island, superiorPlayer) -> island.getSpawnerRatesMultiplier() + "") .put("team_limit", (island, superiorPlayer) -> island.getTeamLimit() + "") .put("team_list", (island, superiorPlayer) -> { StringBuilder teamBuilder = new StringBuilder(); List players = island.getIslandMembers(true); if (players.isEmpty()) { return ""; } for (SuperiorPlayer player : players) { teamBuilder.append(", ").append(player.getName()); } return teamBuilder.substring(2); }) .put("team_size", (island, superiorPlayer) -> island.getIslandMembers(true).size() + "") .put("team_size_online", (island, superiorPlayer) -> island.getIslandMembers(true).stream().filter(SuperiorPlayer::isShownAsOnline).count() + "") .put("unique_visitors_count", (island, superiorPlayer) -> island.getUniqueVisitors().size() + "") .put("unique_visitors_list", (island, superiorPlayer) -> { StringBuilder teamBuilder = new StringBuilder(); List players = island.getUniqueVisitors(); if (players.isEmpty()) { return ""; } for (SuperiorPlayer player : players) { teamBuilder.append(", ").append(player.getName()); } return teamBuilder.substring(2); }) .put("uuid", (island, superiorPlayer) -> island.getUniqueId() + "") .put("visitors_count", (island, superiorPlayer) -> island.getIslandVisitors(false).size() + "") .put("visitors_list", (island, superiorPlayer) -> { StringBuilder teamBuilder = new StringBuilder(); List players = island.getIslandVisitors(); if (players.isEmpty()) { return ""; } for (SuperiorPlayer player : players) { teamBuilder.append(", ").append(player.getName()); } return teamBuilder.substring(2); }) .put("visitors_location", (island, superiorPlayer) -> { WorldInfo worldInfo = getDefaultWorldInfo(island); return Formatters.LOCATION_FORMATTER.format(island.getVisitorsPosition(null /*unused*/).toLocation(worldInfo)); }) .put("visitors_location_x", (island, superiorPlayer) -> island.getVisitorsPosition(getDefaultWorldDimension()).getX() + "") .put("visitors_location_y", (island, superiorPlayer) -> island.getVisitorsPosition(getDefaultWorldDimension()).getY() + "") .put("visitors_location_z", (island, superiorPlayer) -> island.getVisitorsPosition(getDefaultWorldDimension()).getZ() + "") .put("warps", (island, superiorPlayer) -> island.getIslandWarps().size() + "") .put("warps_limit", (island, superiorPlayer) -> island.getWarpsLimit() + "") .put("world", (island, superiorPlayer) -> getDefaultWorldInfo(island).getName()) .put("worth", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getWorth())) .put("worth_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), superiorPlayer.getUserLocale())) .put("worth_int", (island, superiorPlayer) -> island.getWorth().toBigInteger().toString()) .put("worth_raw", (island, superiorPlayer) -> island.getWorth().toString()) // Renamed Island Placeholders .put("hoppers_limit", (island, superiorPlayer) -> island.getBlockLimit(ConstantKeys.HOPPER) + "") .put("x", (island, superiorPlayer) -> island.getCenterPosition().getX() + "") .put("y", (island, superiorPlayer) -> island.getCenterPosition().getY() + "") .put("z", (island, superiorPlayer) -> island.getCenterPosition().getZ() + "") // Global Placeholders .put("total_count", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getIslands().size())) .put("total_count_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getIslands().size(), superiorPlayer.getUserLocale())) .put("total_count_raw", (island, superiorPlayer) -> plugin.getGrid().getIslands().size() + "") .put("total_level", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getTotalLevel())) .put("total_level_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getTotalLevel(), superiorPlayer.getUserLocale())) .put("total_level_int", (island, superiorPlayer) -> plugin.getGrid().getTotalLevel().toBigInteger().toString()) .put("total_level_raw", (island, superiorPlayer) -> plugin.getGrid().getTotalLevel().toString()) .put("total_worth", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getTotalWorth())) .put("total_worth_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getTotalWorth(), superiorPlayer.getUserLocale())) .put("total_worth_int", (island, superiorPlayer) -> plugin.getGrid().getTotalWorth().toBigInteger().toString()) .put("total_worth_raw", (island, superiorPlayer) -> plugin.getGrid().getTotalWorth().toString()) .build(); private static final Map> TOP_VALUE_FORMAT_FUNCTIONS = new ImmutableMap.Builder>() .put(SortingTypes.BY_WORTH, (targetIsland, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(targetIsland.getWorth(), superiorPlayer.getUserLocale())) .put(SortingTypes.BY_LEVEL, (targetIsland, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(targetIsland.getIslandLevel(), superiorPlayer.getUserLocale())) .put(SortingTypes.BY_RATING, (targetIsland, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(targetIsland.getTotalRating())) .put(SortingTypes.BY_PLAYERS, (targetIsland, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(targetIsland.getAllPlayersInside().size())) .build(); private static final Map> TOP_VALUE_RAW_FUNCTIONS = new ImmutableMap.Builder>() .put(SortingTypes.BY_WORTH, targetIsland -> targetIsland.getWorth().toString()) .put(SortingTypes.BY_LEVEL, targetIsland -> targetIsland.getIslandLevel().toString()) .put(SortingTypes.BY_RATING, targetIsland -> targetIsland.getTotalRating() + "") .put(SortingTypes.BY_PLAYERS, targetIsland -> targetIsland.getAllPlayersInside().size() + "") .build(); private static final Map> TOP_VALUE_FUNCTIONS = new ImmutableMap.Builder>() .put(SortingTypes.BY_WORTH, targetIsland -> Formatters.NUMBER_FORMATTER.format(targetIsland.getWorth())) .put(SortingTypes.BY_LEVEL, targetIsland -> Formatters.NUMBER_FORMATTER.format(targetIsland.getIslandLevel())) .put(SortingTypes.BY_RATING, targetIsland -> Formatters.NUMBER_FORMATTER.format(targetIsland.getTotalRating())) .put(SortingTypes.BY_PLAYERS, targetIsland -> Formatters.NUMBER_FORMATTER.format(targetIsland.getAllPlayersInside().size())) .build(); private final Map CUSTOM_ISLAND_PARSERS = new HashMap<>(); private final Map CUSTOM_PLAYER_PARSERS = new HashMap<>(); private final List placeholdersProviders = new LinkedList<>(); public PlaceholdersServiceImpl() { } @Override public Class getAPIClass() { return PlaceholdersService.class; } public void register(List placeholdersProviders) { this.placeholdersProviders.addAll(placeholdersProviders); } public String parsePlaceholders(@Nullable OfflinePlayer offlinePlayer, String str) { for (PlaceholdersProvider placeholdersProvider : placeholdersProviders) str = placeholdersProvider.parsePlaceholders(offlinePlayer, str); return str; } public String handlePluginPlaceholder(@Nullable OfflinePlayer offlinePlayer, String placeholder) { SuperiorPlayer superiorPlayer = offlinePlayer == null ? null : plugin.getPlayers().getSuperiorPlayer(offlinePlayer.getUniqueId()); Optional placeholderResult = Optional.empty(); Matcher matcher; if (superiorPlayer != null) { PlayerPlaceholderParser customPlayerParser = CUSTOM_PLAYER_PARSERS.get(placeholder); if (customPlayerParser != null) { placeholderResult = Optional.ofNullable(customPlayerParser.apply(superiorPlayer)); } else { boolean isLocationPlaceholder = placeholder.startsWith("location_"); IslandPlaceholderParser customIslandParser = CUSTOM_ISLAND_PARSERS.get( isLocationPlaceholder ? placeholder.substring(9) : placeholder); if (customIslandParser != null) { Island island; if (isLocationPlaceholder) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle())); } } else { island = superiorPlayer.getIsland(); } placeholderResult = Optional.ofNullable(customIslandParser.apply(island, superiorPlayer)); } } } if (!placeholderResult.isPresent()) { if ((matcher = PLAYER_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String subPlaceholder = matcher.group(1).toLowerCase(Locale.ENGLISH); placeholderResult = parsePlaceholdersForPlayer(superiorPlayer, subPlaceholder); } else if ((matcher = ISLAND_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String subPlaceholder = matcher.group(1).toLowerCase(Locale.ENGLISH); Island island; boolean isLocationPlaceholder = false; if (superiorPlayer == null) { island = null; } else if (subPlaceholder.startsWith("location_")) { isLocationPlaceholder = true; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle())); } } else { island = superiorPlayer.getIsland(); } placeholderResult = parsePlaceholdersForIsland(island, superiorPlayer, isLocationPlaceholder ? placeholder.substring(9) : placeholder, isLocationPlaceholder ? subPlaceholder.substring(9) : subPlaceholder); } } if (placeholderResult.isPresent()) return placeholderResult.get(); String defaultPlaceholderValue = plugin.getSettings().getDefaultPlaceholders().get(placeholder); if (defaultPlaceholderValue != null) return defaultPlaceholderValue; // We try to look for prefixes of placeholders for (Map.Entry entry : plugin.getSettings().getDefaultPlaceholders().entrySet()) { if (placeholder.startsWith(entry.getKey())) { return entry.getValue(); } } return ""; } @Override public void registerPlaceholder(String placeholderName, PlayerPlaceholderParser placeholderFunction) { CUSTOM_PLAYER_PARSERS.put(placeholderName, placeholderFunction); } @Override public void registerPlaceholder(String placeholderName, IslandPlaceholderParser placeholderFunction) { CUSTOM_ISLAND_PARSERS.put(placeholderName, placeholderFunction); } private static Optional parsePlaceholdersForPlayer(@Nullable SuperiorPlayer superiorPlayer, String subPlaceholder) { Matcher matcher; if (superiorPlayer != null) { if ((matcher = MISSIONS_COMPLETED_PATTERN.matcher(subPlaceholder)).matches()) { String categoryName = matcher.group(1); return Optional.of(superiorPlayer.getCompletedMissions().stream().filter(mission -> mission.getMissionCategory().getName().equalsIgnoreCase(categoryName)).count() + ""); } } return Optional.ofNullable(PLAYER_PARSES.get(subPlaceholder)) .map(placeholderParser -> placeholderParser.apply(superiorPlayer)); } private static Optional parsePlaceholdersForIsland(@Nullable Island island, @Nullable SuperiorPlayer superiorPlayer, String placeholder, String subPlaceholder) { Matcher matcher; if (island != null) { if ((matcher = GENERATOR_AMOUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { return handleGeneratorAmountsPlaceholder(island, matcher.group(1)); } if ((matcher = GENERATOR_PERCENTAGE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { return handleGeneratorPercentagesPlaceholder(island, matcher.group(1)); } if ((matcher = WORLD_UNLOCKED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { boolean unlockedWorld = island.getUnlockedWorlds().contains(Dimension.getByName(matcher.group(1))); return Optional.of(Formatters.BOOLEAN_FORMATTER.format(unlockedWorld, superiorPlayer.getUserLocale())); } if ((matcher = WORLD_ENABLED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { boolean enabledWorld = island.isDimensionEnabled(Dimension.getByName(matcher.group(1))); return Optional.of(Formatters.BOOLEAN_FORMATTER.format(enabledWorld, superiorPlayer.getUserLocale())); } if ((matcher = WORLD_GENERATED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { boolean generatedWorld = island.getGeneratedSchematics().contains(Dimension.getByName(matcher.group(1))); return Optional.of(Formatters.BOOLEAN_FORMATTER.format(generatedWorld, superiorPlayer.getUserLocale())); } if ((matcher = MISSIONS_COMPLETED_PATTERN.matcher(subPlaceholder)).matches()) { String categoryName = matcher.group(1); return Optional.of(island.getCompletedMissions().stream().filter(mission -> mission.getMissionCategory().getName().equalsIgnoreCase(categoryName)).count() + ""); } if ((matcher = MISSION_STATUS_PATTERN.matcher(subPlaceholder)).matches()) { String missionName = matcher.group(1); Mission mission = plugin.getMissions().getMission(missionName); if (mission == null || (!mission.getIslandMission() && superiorPlayer == null)) return Optional.empty(); boolean completedMission = mission.getIslandMission() ? island.hasCompletedMission(mission) : superiorPlayer.hasCompletedMission(mission); return Optional.of(Formatters.BOOLEAN_FORMATTER.format(completedMission, superiorPlayer.getUserLocale())); } if ((matcher = PERMISSION_ROLE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { return handlePermissionRolesPlaceholder(island, matcher.group(1)); } if (superiorPlayer != null) { if ((matcher = BLOCK_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches() || (matcher = COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); return Optional.of(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)) + ""); } else if ((matcher = BLOCK_LEVEL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); return Optional.of(blockValue.getLevel() + ""); } else if ((matcher = BLOCK_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); return Optional.of(island.getBlockLimit(Keys.ofMaterialAndData(keyName)) + ""); } else if ((matcher = BLOCK_TOTAL_LEVEL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); BigDecimal amount = new BigDecimal(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName))); return Optional.of(blockValue.getLevel().multiply(amount) + ""); } else if ((matcher = BLOCK_TOTAL_WORTH_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); BigDecimal amount = new BigDecimal(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName))); return Optional.of(blockValue.getWorth().multiply(amount) + ""); } else if ((matcher = BLOCK_WORTH_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); return Optional.of(blockValue.getWorth() + ""); } else if ((matcher = DATA_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); Object data = island.getPersistentDataContainer().get(keyName); if (data == null) { return Optional.empty(); } return Optional.of(data.toString()); } else if ((matcher = EFFECT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String effectName = matcher.group(1); PotionEffectType potionEffectType = PotionEffectType.getByName(effectName); if (potionEffectType == null) { return Optional.empty(); } return Optional.of(island.getPotionEffectLevel(potionEffectType) + ""); } else if ((matcher = ENTITY_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); return Optional.of(island.getEntitiesTracker().getEntityCount(Keys.ofEntityType(keyName)) + ""); } else if ((matcher = ENTITY_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); return Optional.of(island.getEntityLimit(Keys.ofEntityType(keyName)) + ""); } else if ((matcher = FLAG_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { return handleFlagsPlaceholder(island, superiorPlayer, matcher.group(1)); } else if ((matcher = MEMBER_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { return handleMembersPlaceholder(island, matcher.group(1)); } else if ((matcher = PERMISSION_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { return handlePermissionsPlaceholder(island, superiorPlayer, matcher.group(1)); } else if ((matcher = ROLE_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String roleName = matcher.group(1); PlayerRole playerRole; try { playerRole = SPlayerRole.of(roleName); } catch (IllegalArgumentException error) { return Optional.empty(); } return Optional.of(island.getIslandMembers(playerRole).size() + ""); } else if ((matcher = ROLE_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String roleName = matcher.group(1); PlayerRole playerRole; try { playerRole = SPlayerRole.of(roleName); } catch (IllegalArgumentException error) { return Optional.empty(); } return Optional.of(island.getRoleLimit(playerRole) + ""); } else if ((matcher = UPGRADE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String upgradeName = matcher.group(1); Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName); if (upgrade == null) { return Optional.empty(); } return Optional.of(island.getUpgradeLevel(upgrade).getLevel() + ""); } else if ((matcher = VISITOR_LAST_JOIN_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { String visitorName = matcher.group(1); return Optional.of(island.getUniqueVisitorsWithTimes().stream() .filter(uniqueVisitor -> uniqueVisitor.getKey().getName().equalsIgnoreCase(visitorName)) .findFirst() .map(Pair::getValue).map(value -> Formatters.DATE_FORMATTER.format(new Date(value))) .orElse("Haven't Joined")); } } } if ((matcher = TOP_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { return handleTopIslandsPlaceholder(island, superiorPlayer, matcher.group(1)); } else { try { return Optional.ofNullable(ISLAND_PARSES.get(subPlaceholder)) .map(placeholderParser -> placeholderParser.apply(island, superiorPlayer)); } catch (NullPointerException ignored) { // One of the island parses failed due to invalid island being sent. } } return Optional.empty(); } private static Optional handleFlagsPlaceholder(@NotNull Island island, @NotNull SuperiorPlayer superiorPlayer, String placeholder) { try { IslandFlag islandFlag = IslandFlag.getByName(placeholder); return Optional.of(Formatters.BOOLEAN_FORMATTER.format(island.hasSettingsEnabled(islandFlag), superiorPlayer.getUserLocale())); } catch (NullPointerException ex) { return Optional.empty(); } } private static Optional handleGeneratorAmountsPlaceholder(@Nullable Island island, String placeholder) { String[] placeholderSections = placeholder.split("_"); if (placeholderSections.length <= 1) return Optional.empty(); Dimension dimension; try { dimension = Dimension.getByName(placeholderSections[0]); } catch (NullPointerException error) { return Optional.empty(); } String keyName = String.join("_", placeholderSections).substring(placeholderSections[0].length() + 1); return Optional.of(island.getGeneratorAmount(Keys.ofMaterialAndData(keyName), dimension) + ""); } private static Optional handleGeneratorPercentagesPlaceholder(@Nullable Island island, String placeholder) { String[] placeholderSections = placeholder.split("_"); if (placeholderSections.length <= 1) return Optional.empty(); Dimension dimension; try { dimension = Dimension.getByName(placeholderSections[0]); } catch (NullPointerException error) { return Optional.empty(); } String keyName = String.join("_", placeholderSections).substring(placeholderSections[0].length() + 1); return Optional.of(IslandUtils.getGeneratorPercentageDecimal(island, Keys.ofMaterialAndData(keyName), dimension) + ""); } private static Optional handleMembersPlaceholder(@NotNull Island island, String placeholder) { List members = island.getIslandMembers(false); int targetMemberIndex = -1; try { targetMemberIndex = Integer.parseInt(placeholder) - 1; } catch (NumberFormatException ignored) { } if (targetMemberIndex < 0 || targetMemberIndex >= members.size()) return Optional.empty(); return Optional.of(members.get(targetMemberIndex).getName()); } private static Optional handlePermissionsPlaceholder(@NotNull Island island, @NotNull SuperiorPlayer superiorPlayer, String placeholder) { try { IslandPrivilege islandPrivilege = IslandPrivilege.getByName(placeholder); return Optional.of(Formatters.BOOLEAN_FORMATTER.format(island.hasPermission(superiorPlayer, islandPrivilege), superiorPlayer.getUserLocale())); } catch (NullPointerException ex) { return Optional.empty(); } } private static Optional handlePermissionRolesPlaceholder(@NotNull Island island, String placeholder) { try { IslandPrivilege islandPrivilege = IslandPrivilege.getByName(placeholder); return Optional.of(island.getRequiredPlayerRole(islandPrivilege).getDisplayName()); } catch (NullPointerException ex) { return Optional.empty(); } } private static Optional handleTopIslandsPlaceholder(@Nullable Island island, @Nullable SuperiorPlayer superiorPlayer, String subPlaceholder) { Matcher matcher; SortingType sortingType; if ((matcher = TOP_WORTH_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { sortingType = SortingTypes.BY_WORTH; } else if ((matcher = TOP_LEVEL_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { sortingType = SortingTypes.BY_LEVEL; } else if ((matcher = TOP_RATING_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { sortingType = SortingTypes.BY_RATING; } else if ((matcher = TOP_PLAYERS_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { sortingType = SortingTypes.BY_PLAYERS; } else { String sortingTypeName = subPlaceholder.split("_")[0]; sortingType = SortingType.getByName(sortingTypeName); } if (sortingType == null) return Optional.empty(); String placeholderValue = matcher.group(1); if (placeholderValue.equals("position")) return island == null ? Optional.empty() : Optional.of((plugin.getGrid().getIslandPosition(island, sortingType) + 1) + ""); Function getValueFunction; if ((matcher = TOP_VALUE_FORMAT_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) { getValueFunction = Optional.ofNullable(TOP_VALUE_FORMAT_FUNCTIONS.get(sortingType)).map(function -> (Function) targetIsland -> function.apply(targetIsland, superiorPlayer)).orElse(null); } else if ((matcher = TOP_VALUE_RAW_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) { getValueFunction = TOP_VALUE_RAW_FUNCTIONS.get(sortingType); } else if ((matcher = TOP_VALUE_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) { getValueFunction = TOP_VALUE_FUNCTIONS.get(sortingType); } else if ((matcher = TOP_LEADER_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) { getValueFunction = targetIsland -> targetIsland.getOwner().getName(); } else if ((matcher = TOP_CUSTOM_PLACEHOLDER_PATTERN.matcher(placeholderValue)).matches()) { String customPlaceholder = matcher.group(2); getValueFunction = targetIsland -> parsePlaceholdersForIsland(targetIsland, superiorPlayer, "superior_island_" + customPlaceholder, customPlaceholder).orElse(null); } else { getValueFunction = targetIsland -> targetIsland.getName().isEmpty() ? targetIsland.getOwner().getName() : targetIsland.getName(); } if (getValueFunction == null) return Optional.empty(); int targetPosition; try { targetPosition = Integer.parseInt(matcher.matches() ? matcher.group(1) : placeholderValue); } catch (NumberFormatException error) { return Optional.empty(); } Island targetIsland = plugin.getGrid().getIsland(targetPosition - 1, sortingType); return Optional.ofNullable(targetIsland).map(getValueFunction); } private static WorldInfo getDefaultWorldInfo(Island island) { return plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); } private static Dimension getDefaultWorldDimension() { return plugin.getSettings().getWorlds().getDefaultWorldDimension(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.portals; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.service.portals.EntityPortalResult; import com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import java.math.BigDecimal; import java.util.Locale; import java.util.UUID; import java.util.concurrent.TimeUnit; public class PortalsManagerServiceImpl implements PortalsManagerService, IService { private final AutoRemovalCollection generatingSchematicsIslands = AutoRemovalCollection.newHashSet(20, TimeUnit.SECONDS); private final LazyReference dragonBattleService = new LazyReference() { @Override protected DragonBattleService create() { return plugin.getServices().getService(DragonBattleService.class); } }; private final SuperiorSkyblockPlugin plugin; public PortalsManagerServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Class getAPIClass() { return PortalsManagerService.class; } @Override public EntityPortalResult handlePlayerPortal(SuperiorPlayer superiorPlayer, Location portalLocation, PortalType portalType, Location destinationLocation, boolean checkImmunedPortalsStatus) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); Preconditions.checkNotNull(destinationLocation, "destinationLocation cannot be null."); Preconditions.checkArgument(!(superiorPlayer instanceof SuperiorNPCPlayer), "superiorPlayer cannot be an NPC."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); if (destinationDimension == null) return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, null); } @Override public EntityPortalResult handleEntityPortal(Entity entity, Location portalLocation, PortalType portalType, Location destinationLocation) { Preconditions.checkNotNull(entity, "entity cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); Preconditions.checkNotNull(destinationLocation, "destinationLocation cannot be null."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); if (destinationDimension == null) return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, null); } @Override public EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island, Location portalLocation, PortalType portalType, boolean checkImmunedPortalsStatus) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null."); Preconditions.checkNotNull(island, "island cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); Preconditions.checkArgument(!(superiorPlayer instanceof SuperiorNPCPlayer), "superiorPlayer cannot be an NPC."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(portalLocation.getWorld()); if (portalDimension == null) return EntityPortalResult.PORTAL_NOT_IN_ISLAND; Dimension destinationDimension = getDestinationDimension(portalDimension, portalType); if (destinationDimension == null) return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, island); } @Override public EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island, Location portalLocation, PortalType portalType, Location destinationLocation, boolean checkImmunedPortalsStatus) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null."); Preconditions.checkNotNull(island, "island cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); Preconditions.checkNotNull(destinationLocation, "destinationLocation cannot be null."); Preconditions.checkArgument(!(superiorPlayer instanceof SuperiorNPCPlayer), "superiorPlayer cannot be an NPC."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); Preconditions.checkArgument(island.isInside(destinationLocation), "destinationLocation is not inside the island."); Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); if (destinationDimension == null) return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, island); } @Override public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, PortalType portalType) { Preconditions.checkNotNull(entity, "entity cannot be null."); Preconditions.checkNotNull(island, "island cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); Preconditions.checkArgument(!(entity instanceof HumanEntity), "entity cannot be a Player."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(portalLocation.getWorld()); if (portalDimension == null) return EntityPortalResult.PORTAL_NOT_IN_ISLAND; Dimension destinationDimension = getDestinationDimension(portalDimension, portalType); if (destinationDimension == null) return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, island); } @Override public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, PortalType portalType, Location destinationLocation) { Preconditions.checkNotNull(entity, "entity cannot be null."); Preconditions.checkNotNull(island, "island cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); Preconditions.checkNotNull(destinationLocation, "destinationLocation cannot be null."); Preconditions.checkArgument(!(entity instanceof HumanEntity), "entity cannot be a Player."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); Preconditions.checkArgument(island.isInside(destinationLocation), "destinationLocation is not inside the island."); Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); if (destinationDimension == null) return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, island); } private EntityPortalResult handlePlayerPortalInternal(SuperiorPlayer superiorPlayer, Location portalLocation, PortalType portalType, Dimension destinationDimension, boolean checkImmunedPortalsStatus, @Nullable Island island) { if (island == null) { island = plugin.getGrid().getIslandAt(portalLocation); if (island == null) return EntityPortalResult.PORTAL_NOT_IN_ISLAND; } if (checkImmunedPortalsStatus && superiorPlayer.hasPlayerStatus(PlayerStatus.PORTALS_IMMUNED)) return EntityPortalResult.PLAYER_IMMUNED_TO_PORTAL; EntityPortalResult portalResult = simulateEntityPortalFromIsland(superiorPlayer.asPlayer(), island, portalType, destinationDimension); if (portalResult == EntityPortalResult.WORLD_NOT_UNLOCKED) { Message.WORLD_NOT_UNLOCKED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(destinationDimension.getName())); } else if (portalResult == EntityPortalResult.DESTINATION_WORLD_DISABLED) { Message.WORLD_NOT_ENABLED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(destinationDimension.getName())); } return portalResult; } private EntityPortalResult handleEntityPortalInternal(Entity entity, Location portalLocation, PortalType portalType, Dimension destinationDimension, @Nullable Island island) { if (island == null) { island = plugin.getGrid().getIslandAt(portalLocation); if (island == null) return EntityPortalResult.PORTAL_NOT_IN_ISLAND; } return simulateEntityPortalFromIsland(entity, island, portalType, destinationDimension); } private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island island, PortalType portalType, Dimension portalDestination) { { SettingsManager.Worlds.DimensionConfig destinationConfig = portalDestination == null ? null : plugin.getSettings().getWorlds().getDimensionConfig(portalDestination); if (portalDestination == null || destinationConfig == null || !destinationConfig.isEnabled()) { return EntityPortalResult.DESTINATION_WORLD_DISABLED; } } if (plugin.getGrid().getIslandsWorld(island, portalDestination) == null) { return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; } if (!island.isDimensionEnabled(portalDestination)) { return EntityPortalResult.WORLD_NOT_UNLOCKED; } try { // We want to prevent the players from being teleported in this time. if (generatingSchematicsIslands.contains(island.getUniqueId())) return EntityPortalResult.SCHEMATIC_GENERATING_COOLDOWN; String destinationDimensionName = portalDestination.getName().toLowerCase(Locale.ENGLISH); String islandSchematic = island.getSchematicName(); Schematic originalSchematic = plugin.getSchematics().getSchematic(islandSchematic.isEmpty() ? plugin.getSchematics().getDefaultSchematic(portalDestination) : islandSchematic + "_" + destinationDimensionName); boolean schematicGenerated = island.wasSchematicGenerated(portalDestination); SuperiorPlayer superiorPlayer = entity instanceof Player ? plugin.getPlayers().getSuperiorPlayer(entity) : null; Dimension destination; Schematic schematic; boolean ignoreInvalidSchematic; if (superiorPlayer != null) { PluginEvent event = PluginEventsFactory.callIslandEnterPortalEvent( island, superiorPlayer, portalType, portalDestination, schematicGenerated ? null : originalSchematic, schematicGenerated); if (event.isCancelled()) return EntityPortalResult.PORTAL_EVENT_CANCELLED; destination = event.getArgs().destination; schematic = event.getArgs().schematic; ignoreInvalidSchematic = event.getArgs().ignoreInvalidSchematic; } else { destination = portalDestination; schematic = schematicGenerated ? null : originalSchematic; ignoreInvalidSchematic = schematicGenerated; } if (schematic == null && !ignoreInvalidSchematic) { if (superiorPlayer != null) { String schematicName = islandSchematic + "_" + destinationDimensionName; Message.SCHEMATIC_NOT_ADDED.send(superiorPlayer, destinationDimensionName, schematicName); } return EntityPortalResult.INVALID_SCHEMATIC; } generatingSchematicsIslands.add(island.getUniqueId()); // If schematic was already generated, or no schematic should be generated, simply // teleport player to destination location. if (schematic == null || island.wasSchematicGenerated(destination)) { if (superiorPlayer != null) { superiorPlayer.teleport(island, destination, result -> { generatingSchematicsIslands.remove(island.getUniqueId()); }); } else { EntityTeleports.findIslandSafeLocation(island, destination).whenComplete((safeSpot, error) -> { generatingSchematicsIslands.remove(island.getUniqueId()); if (error == null && safeSpot != null) EntityTeleports.teleport(entity, safeSpot); }); } return EntityPortalResult.SUCCEED; } IslandWorlds.accessIslandWorldAsync(island, destination, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { Location centerLocation = island.getCenter(destination); Location schematicPlacementLocation = centerLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(); BigDecimal originalWorth = island.getRawWorth(); BigDecimal originalLevel = island.getRawLevel(); schematic.pasteSchematic(island, schematicPlacementLocation, () -> { generatingSchematicsIslands.remove(island.getUniqueId()); island.setSchematicGenerate(destination); SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(destination); if (destinationConfig != null && destinationConfig.isSchematicOffset()) { { BigDecimal schematicWorth = island.getRawWorth().subtract(originalWorth); PluginEvent event = PluginEventsFactory.callIslandChangeWorthBonusEvent( island, (SuperiorPlayer) null, IslandChangeWorthBonusEvent.Reason.SCHEMATIC, island.getBonusWorth().subtract(schematicWorth)); if (!event.isCancelled()) island.setBonusWorth(event.getArgs().worthBonus); } { BigDecimal schematicLevel = island.getRawLevel().subtract(originalLevel); PluginEvent event = PluginEventsFactory.callIslandChangeLevelBonusEvent( island, (SuperiorPlayer) null, IslandChangeLevelBonusEvent.Reason.SCHEMATIC, island.getBonusLevel().subtract(schematicLevel)); if (!event.isCancelled()) island.setBonusLevel(event.getArgs().levelBonus); } } Location homeLocation = schematic.adjustRotation(centerLocation); island.setIslandHome(homeLocation); if (destination.getEnvironment() == World.Environment.THE_END && superiorPlayer != null) { plugin.getNMSDragonFight().awardTheEndAchievement((Player) entity); this.dragonBattleService.get().resetEnderDragonBattle(island, destination); } if (superiorPlayer != null) { superiorPlayer.teleport(homeLocation); } else { EntityTeleports.teleport(entity, homeLocation); } }, error -> { generatingSchematicsIslands.remove(island.getUniqueId()); error.printStackTrace(); if (superiorPlayer != null) Message.CREATE_WORLD_FAILURE.send(superiorPlayer); }); }); }); } catch (NullPointerException ignored) { } return EntityPortalResult.SUCCEED; } @Nullable private Dimension getDestinationDimension(Dimension dimension, PortalType portalType) { SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); if (dimensionConfig == null) return null; return dimensionConfig.getPortalDestination(portalType); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/region/ProtectionHelper.java ================================================ package com.bgsoftware.superiorskyblock.service.region; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandsHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.util.Locale; public class ProtectionHelper { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private ProtectionHelper() { } public static boolean shouldPreventInteraction(InteractionResult interactionResult, @Nullable SuperiorPlayer superiorPlayer, boolean sendMessages) { switch (interactionResult) { case ISLAND_RECALCULATE: if (sendMessages && superiorPlayer != null) Message.ISLAND_BEING_CALCULATED.send(superiorPlayer); return true; case MISSING_PRIVILEGE: if (sendMessages && superiorPlayer != null) sendProtectionMessage(superiorPlayer.asPlayer()); return true; case OUTSIDE_ISLAND: if (sendMessages && superiorPlayer != null) Message.BUILD_OUTSIDE_ISLAND.send(superiorPlayer); return true; case SUCCESS: return false; } throw new IllegalStateException("No handling for result " + interactionResult); } public static void sendProtectionMessage(CommandSender sender) { boolean isSpawnIsland; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Island island = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle())); isSpawnIsland = island != null && island.isSpawn(); } Locale locale = PlayerLocales.getLocale(sender); if (!isSpawnIsland) Message.ISLAND_PROTECTED.send(sender, locale); else Message.SPAWN_PROTECTED.send(sender, locale); SuperiorCommand bypassCommand = plugin.getCommands().getAdminCommand("bypass"); if (CommandsHelper.hasCommandAccess(bypassCommand, sender)) if (!isSpawnIsland) Message.ISLAND_PROTECTED_OPPED.send(sender, locale); else Message.SPAWN_PROTECTED_OPPED.send(sender, locale); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.region; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.MoveResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.BukkitItems; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.WeatherType; import org.bukkit.block.Block; import org.bukkit.entity.Animals; import org.bukkit.entity.Arrow; import org.bukkit.entity.Creeper; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.entity.Sheep; import org.bukkit.entity.Villager; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.event.block.Action; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitTask; import java.util.List; import java.util.Optional; public class RegionManagerServiceImpl implements RegionManagerService, IService { private static final Material FARMLAND = EnumHelper.getEnum(Material.class, "FARMLAND", "SOIL"); @Nullable private static final Material ROOTED_DIRT = EnumHelper.getEnum(Material.class, "ROOTED_DIRT"); @Nullable private static final Material TURTLE_EGG = EnumHelper.getEnum(Material.class, "TURTLE_EGG"); @Nullable private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, "SWEET_BERRY_BUSH"); @Nullable private static final Material CAVE_VINES = EnumHelper.getEnum(Material.class, "CAVE_VINES"); @Nullable private static final Material CAVE_VINES_PLANT = EnumHelper.getEnum(Material.class, "CAVE_VINES_PLANT"); @Nullable private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); @Nullable private static final Material TRIAL_KEY = EnumHelper.getEnum(Material.class, "TRIAL_KEY"); @Nullable private static final Material OMINOUS_TRIAL_KEY = EnumHelper.getEnum(Material.class, "OMINOUS_TRIAL_KEY"); @Nullable private static final EntityType LLAMA_TYPE = EnumHelper.getEnum(EntityType.class, "LLAMA"); @Nullable private static final EntityType HAPPY_GHAST_TYPE = EnumHelper.getEnum(EntityType.class, "HAPPY_GHAST"); @Nullable private static final EntityType PARROT_TYPE = EnumHelper.getEnum(EntityType.class, "PARROT"); @Nullable private static final Material GOLDEN_DANDELION_TYPE = EnumHelper.getEnum(Material.class, "GOLDEN_DANDELION"); private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; private final SuperiorSkyblockPlugin plugin; public RegionManagerServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, RegionManagerServiceImpl::onSettingsUpdate); } private static void onSettingsUpdate() { SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); WORLD_PERMISSIONS_CACHE = new EnumerateSet<>(IslandPrivilege.values()); plugin.getSettings().getWorldPermissions().forEach(islandPrivilageName -> { try { WORLD_PERMISSIONS_CACHE.add(IslandPrivilege.getByName(islandPrivilageName)); } catch (Throwable ignored) { } }); } @Override public Class getAPIClass() { return RegionManagerService.class; } @Override public InteractionResult handleBlockPlace(SuperiorPlayer superiorPlayer, Block block) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld())) return InteractionResult.SUCCESS; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.BUILD, 0, true, true); } } @Override public InteractionResult handleBlockBreak(SuperiorPlayer superiorPlayer, Block block) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld())) return InteractionResult.SUCCESS; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(blockLocation); Material blockType = block.getType(); IslandPrivilege islandPrivilege = blockType == Materials.SPAWNER.toBukkitType() ? IslandPrivileges.SPAWNER_BREAK : IslandPrivileges.BREAK; InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation, islandPrivilege, 0, true, true, island, false); if (interactionResult != InteractionResult.SUCCESS) return interactionResult; if (island == null) return InteractionResult.SUCCESS; if (plugin.getSettings().getValuableBlocks().contains(Keys.of(block))) return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.VALUABLE_BREAK, 0, false, false, island, false); } return InteractionResult.SUCCESS; } @Override public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Block block, Action action, @Nullable ItemStack usedItem) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld())) return InteractionResult.SUCCESS; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); Key blockKey = Keys.of(block); boolean isInteractableItem = BukkitItems.isInteractableItem(usedItem); int stackedBlockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); IslandPrivilege islandPrivilege = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(blockKey); if (!isInteractableItem && stackedBlockAmount <= 1 && islandPrivilege == null) return InteractionResult.SUCCESS; Material blockType = block.getType(); Material usedItemType = usedItem == null ? null : usedItem.getType(); EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : Materials.isMinecart(usedItemType) && Materials.isRail(blockType) ? EntityType.MINECART : Materials.isBoat(blockType) ? EntityType.BOAT : BukkitItems.getEntityType(usedItem); if (spawnType != EntityType.UNKNOWN) { List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(spawnType)); for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getSpawnPrivilege() != null) { InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation, entityCategory.getSpawnPrivilege(), 0, true, true); if (interactionResult != InteractionResult.SUCCESS) return interactionResult; } } return InteractionResult.SUCCESS; } if (usedItem != null && blockType == VAULT && usedItemType != TRIAL_KEY && usedItemType != OMINOUS_TRIAL_KEY) { return InteractionResult.SUCCESS; } else if (action == Action.PHYSICAL && blockType == FARMLAND || blockType == ROOTED_DIRT || (usedItem != null && Materials.isHoe(usedItemType))) { islandPrivilege = IslandPrivileges.BUILD; } else if (action == Action.PHYSICAL && blockType == TURTLE_EGG) { islandPrivilege = IslandPrivileges.BUILD; } else if (blockType == SWEET_BERRY_BUSH && action == Action.RIGHT_CLICK_BLOCK && Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) && ((org.bukkit.block.data.Ageable) plugin.getNMSWorld().getBlockData(block)).getAge() < 3) { islandPrivilege = IslandPrivileges.FERTILIZE; } else if ((blockType == CAVE_VINES || blockType == CAVE_VINES_PLANT) && action == Action.RIGHT_CLICK_BLOCK && Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) && !plugin.getNMSWorld().hasBerries(block)) { islandPrivilege = IslandPrivileges.FERTILIZE; } else if (stackedBlockAmount > 1) { islandPrivilege = IslandPrivileges.BREAK; } return handleInteractionInternal(superiorPlayer, blockLocation, islandPrivilege, 0, true, true); } } @Override public InteractionResult handleBlockFertilize(SuperiorPlayer superiorPlayer, Block block) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld())) return InteractionResult.SUCCESS; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.FERTILIZE, 0, true, true); } } @Override public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Entity entity, @Nullable ItemStack usedItem) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld())) return InteractionResult.SUCCESS; InteractionResult interactionResult; boolean closeInventory = false; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); EntityType entityType = entity.getType(); Material usedItemType = usedItem == null ? Material.AIR : usedItem.getType(); if (entity instanceof Villager || BukkitEntities.isHorse(entity) || BukkitEntities.isNautilus(entityType)) { closeInventory = true; } IslandPrivilege islandPrivilege = null; if (usedItem != null && entity instanceof Animals && (usedItemType == GOLDEN_DANDELION_TYPE || plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity))) { islandPrivilege = IslandPrivileges.ANIMAL_BREED; } else if (usedItemType == Material.NAME_TAG) { islandPrivilege = IslandPrivileges.NAME_ENTITY; } else if (usedItemType == Material.SADDLE || (entityType == LLAMA_TYPE && Materials.isCarpet(usedItemType)) || (entityType == HAPPY_GHAST_TYPE && Materials.isHarness(usedItemType)) || (usedItemType == Material.SHEARS && plugin.getNMSEntities().canShearSaddleFromEntity(entity))) { islandPrivilege = IslandPrivileges.SADDLE_ENTITY; } else if (usedItemType == Material.FLINT_AND_STEEL && entity instanceof Creeper) { islandPrivilege = IslandPrivileges.IGNITE_CREEPER; } else if (usedItem != null && entity instanceof PoweredMinecart && plugin.getNMSEntities().isMinecartFuel(usedItem, (PoweredMinecart) entity)) { islandPrivilege = IslandPrivileges.MINECART_OPEN; } else if (entity instanceof Sheep && Materials.isDye(usedItemType)) { islandPrivilege = IslandPrivileges.DYE_SHEEP; } if (islandPrivilege != null) { interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege, 0, true, true); } else { interactionResult = InteractionResult.SUCCESS; List entityCategories = BukkitEntities.getCategories(entity); if (entityType == PARROT_TYPE && usedItemType == Material.COOKIE) { for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getDamagePrivilege() != null) { interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, entityCategory.getDamagePrivilege(), 0, true, true); if (interactionResult != InteractionResult.SUCCESS) break; } } } else { for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getInteractPrivilege() != null) { interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, entityCategory.getInteractPrivilege(), 0, true, true); if (interactionResult != InteractionResult.SUCCESS) break; } } } } } if (closeInventory && interactionResult != InteractionResult.SUCCESS) { BukkitExecutor.sync(() -> { Player player = superiorPlayer.asPlayer(); if (player != null && player.isOnline()) { Inventory openInventory = player.getOpenInventory().getTopInventory(); if (openInventory != null && (openInventory.getType() == InventoryType.MERCHANT || openInventory.getType() == InventoryType.CHEST)) player.closeInventory(); } }, 1L); } return interactionResult; } @Override public InteractionResult handleEntityDamage(Entity damager, Entity entity) { Preconditions.checkNotNull(damager, "damager cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld())) return InteractionResult.SUCCESS; Optional damagerSource = BukkitEntities.getPlayerSource(damager).map(plugin.getPlayers()::getSuperiorPlayer); if (!damagerSource.isPresent()) return InteractionResult.SUCCESS; List entityCategories = BukkitEntities.getCategories(entity); if (!entityCategories.isEmpty()) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); InteractionResult interactionResult; for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getDamagePrivilege() != null) { interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, entityCategory.getDamagePrivilege(), 0, true, false); if (interactionResult != InteractionResult.SUCCESS) { if (damager instanceof Arrow && entity.getFireTicks() > 0) entity.setFireTicks(0); return interactionResult; } } } } } return InteractionResult.SUCCESS; } @Override public InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity vehicle) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(vehicle, "vehicle cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(vehicle.getWorld())) return InteractionResult.SUCCESS; List entityCategories = BukkitEntities.getCategories(vehicle); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = vehicle.getLocation(wrapper.getHandle()); if (!entityCategories.isEmpty()) { InteractionResult interactionResult; for (EntityCategory entityCategory : entityCategories) { if (entityCategory.getInteractPrivilege() != null) { interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, entityCategory.getInteractPrivilege(), 0, true, false); if (interactionResult != InteractionResult.SUCCESS) return interactionResult; } } } IslandPrivilege islandPrivilege = vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; return handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege, 0, true, false); } } @Override public InteractionResult handleEntityShear(SuperiorPlayer superiorPlayer, Entity entity) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld())) return InteractionResult.SUCCESS; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); return handleInteractionInternal(superiorPlayer, entityLocation, IslandPrivileges.ANIMAL_SHEAR, 0, true, false); } } @Override public InteractionResult handleEntityLeash(SuperiorPlayer superiorPlayer, Entity entity) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld())) return InteractionResult.SUCCESS; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); return handleInteractionInternal(superiorPlayer, entityLocation, IslandPrivileges.LEASH, 0, true, false); } } @Override public InteractionResult handlePlayerPickupItem(SuperiorPlayer superiorPlayer, Item item) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(item, "item cannot be null"); if (plugin.getNMSPlayers().wasThrownByPlayer(item, superiorPlayer)) return InteractionResult.SUCCESS; // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(item.getWorld())) return InteractionResult.SUCCESS; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location itemLocation = item.getLocation(wrapper.getHandle()); return handleInteractionInternal(superiorPlayer, itemLocation, IslandPrivileges.PICKUP_DROPS, MAX_PICKUP_DISTANCE, true, false); } } @Override public InteractionResult handlePlayerDropItem(SuperiorPlayer superiorPlayer, Item item) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(item, "item cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(item.getWorld())) return InteractionResult.SUCCESS; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location itemLocation = item.getLocation(wrapper.getHandle()); return handleInteractionInternal(superiorPlayer, itemLocation, IslandPrivileges.DROP_ITEMS, 0, true, false); } } @Override public InteractionResult handlePlayerEnderPearl(SuperiorPlayer superiorPlayer, Location destination) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(destination, "destination cannot be null"); Preconditions.checkArgument(destination.getWorld() != null, "destination's world cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(destination.getWorld())) return InteractionResult.SUCCESS; return handleInteractionInternal(superiorPlayer, destination, IslandPrivileges.ENDER_PEARL, 0, true, false); } @Override public InteractionResult handlePlayerConsumeChorusFruit(SuperiorPlayer superiorPlayer, Location location) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(location, "location cannot be null"); Preconditions.checkArgument(location.getWorld() != null, "location's world cannot be null"); if (IslandPrivileges.CHORUS_FRUIT == null) { // Chorus Fruit privilege does not exist, we will just return SUCCESS in this case. return InteractionResult.SUCCESS; } // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld())) return InteractionResult.SUCCESS; return handleInteractionInternal(superiorPlayer, location, IslandPrivileges.CHORUS_FRUIT, 0, true, true); } @Override public InteractionResult handlePlayerUseWindCharge(SuperiorPlayer superiorPlayer, Location location) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(location, "location cannot be null"); Preconditions.checkArgument(location.getWorld() != null, "location's world cannot be null"); if (IslandPrivileges.WIND_CHARGE == null) { // Wind Charge privilege does not exist, we will just return SUCCESS in this case. return InteractionResult.SUCCESS; } // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld())) return InteractionResult.SUCCESS; return handleInteractionInternal(superiorPlayer, location, IslandPrivileges.WIND_CHARGE, 0, true, true); } @Override public InteractionResult handleCustomInteraction(SuperiorPlayer superiorPlayer, Location location, IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(location, "location cannot be null"); Preconditions.checkNotNull(islandPrivilege, "islandPrivilege cannot be null"); // We do not care about spawn island when spawn protection is disabled, // and therefore only island worlds are relevant. if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld())) return InteractionResult.SUCCESS; return handleInteractionInternal(superiorPlayer, location, islandPrivilege, 0, true, false); } private InteractionResult handleInteractionInternal(SuperiorPlayer superiorPlayer, Location location, IslandPrivilege islandPrivilege, int extraRadius, boolean checkIslandBoundaries, boolean checkRecalculation) { return handleInteractionInternal(superiorPlayer, location, islandPrivilege, extraRadius, checkIslandBoundaries, checkRecalculation, null, true); } private InteractionResult handleInteractionInternal(SuperiorPlayer superiorPlayer, Location location, IslandPrivilege islandPrivilege, int extraRadius, boolean checkIslandBoundaries, boolean checkRecalculation, @Nullable Island island, boolean callIslandLookup) { if (superiorPlayer.hasBypassModeEnabled()) return InteractionResult.SUCCESS; if (callIslandLookup) { island = plugin.getGrid().getIslandAt(location); } if (checkIslandBoundaries && !WORLD_PERMISSIONS_CACHE.contains(islandPrivilege)) { if (island == null && plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld())) return InteractionResult.OUTSIDE_ISLAND; if (island != null && !island.isInsideRange(location, extraRadius)) return InteractionResult.OUTSIDE_ISLAND; } if (island != null) { if (!island.hasPermission(superiorPlayer, islandPrivilege)) return InteractionResult.MISSING_PRIVILEGE; if (checkRecalculation && island.isBeingRecalculated()) return InteractionResult.ISLAND_RECALCULATE; } return InteractionResult.SUCCESS; } @Override public MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Location to) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(from, "from cannot be null"); Preconditions.checkNotNull(to, "to cannot be null"); Island fromIsland = null; boolean lookupFromIsland = true; //Checking for out of distance from preview location. IslandPreview islandPreview = plugin.getGrid().getIslandPreview(superiorPlayer); if (islandPreview != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location islandPreviewLocation = islandPreview.getLocation(wrapper.getHandle()); if (!islandPreviewLocation.getWorld().equals(to.getWorld()) || islandPreviewLocation.distance(to) > plugin.getSettings().getIslandPreviews().getMaxDistance()) { islandPreview.handleEscape(); return MoveResult.ISLAND_PREVIEW_MOVED_TOO_FAR; } } } if (from.getBlockX() != to.getBlockX() || from.getBlockZ() != to.getBlockZ()) { // Handle moving while in teleport warmup. BukkitTask teleportTask = superiorPlayer.getTeleportTask(); if (teleportTask != null) { teleportTask.cancel(); superiorPlayer.setTeleportTask(null); Message.TELEPORT_WARMUP_CANCEL.send(superiorPlayer); } MoveResult moveResult; Island toIsland = plugin.getGrid().getIslandAt(to); if (toIsland != null) { moveResult = handlePlayerEnterIslandInternal(superiorPlayer, toIsland, from, to, IslandEnterEvent.EnterCause.PLAYER_MOVE); if (moveResult != MoveResult.SUCCESS) return moveResult; } lookupFromIsland = false; fromIsland = plugin.getGrid().getIslandAt(from); if (fromIsland != null) { moveResult = handlePlayerLeaveIslandInternal(superiorPlayer, fromIsland, from, to, IslandLeaveEvent.LeaveCause.PLAYER_MOVE); if (moveResult != MoveResult.SUCCESS) return moveResult; } } if (from.getBlockY() != to.getBlockY() && to.getBlockY() <= plugin.getNMSWorld().getMinHeight(to.getWorld()) - 5) { if (lookupFromIsland) { fromIsland = plugin.getGrid().getIslandAt(from); } if (fromIsland == null || (fromIsland.isVisitor(superiorPlayer, false) ? !plugin.getSettings().getVoidTeleport().isVisitors() : !plugin.getSettings().getVoidTeleport().isMembers())) return MoveResult.SUCCESS; Log.debug(Debug.VOID_TELEPORT, superiorPlayer.getName()); superiorPlayer.setPlayerStatus(PlayerStatus.VOID_TELEPORT); superiorPlayer.teleport(fromIsland, result -> { if (!result) { Message.TELEPORTED_FAILED.send(superiorPlayer); superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(), result2 -> { forgetVoidTeleportPlayerStatus(superiorPlayer); }); } else { forgetVoidTeleportPlayerStatus(superiorPlayer); } }); return MoveResult.VOID_TELEPORT; } return MoveResult.SUCCESS; } private void forgetVoidTeleportPlayerStatus(SuperiorPlayer superiorPlayer) { BukkitExecutor.sync(() -> { superiorPlayer.removePlayerStatus(PlayerStatus.VOID_TELEPORT); }, 40L); } @Override public MoveResult handlePlayerTeleport(SuperiorPlayer superiorPlayer, Location from, Location to) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(from, "from cannot be null"); Preconditions.checkArgument(from.getWorld() != null, "from world cannot be null"); Preconditions.checkNotNull(to, "to cannot be null"); Preconditions.checkArgument(to.getWorld() != null, "from world cannot be null"); Island toIsland = plugin.getGrid().getIslandAt(to); if (toIsland != null) { MoveResult enterMove = handlePlayerEnterIslandInternal(superiorPlayer, toIsland, from, to, IslandEnterEvent.EnterCause.PLAYER_TELEPORT); if (enterMove != MoveResult.SUCCESS) return enterMove; } Island fromIsland = plugin.getGrid().getIslandAt(from); if (fromIsland != null) { return handlePlayerLeaveIslandInternal(superiorPlayer, fromIsland, from, to, IslandLeaveEvent.LeaveCause.PLAYER_TELEPORT); } return MoveResult.SUCCESS; } @Override public MoveResult handlePlayerTeleportByPortal(SuperiorPlayer superiorPlayer, Location portalLocation, Location teleportLocation) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null"); Preconditions.checkNotNull(portalLocation.getWorld(), "portalLocation world cannot be null"); Preconditions.checkNotNull(teleportLocation, "teleportLocation cannot be null"); Preconditions.checkNotNull(teleportLocation.getWorld(), "teleportLocation world cannot be null"); Island island = plugin.getGrid().getIslandAt(teleportLocation); if (island != null) { return handlePlayerEnterIslandInternal(superiorPlayer, island, portalLocation, teleportLocation, IslandEnterEvent.EnterCause.PORTAL); } return MoveResult.SUCCESS; } @Override public MoveResult handlePlayerJoin(SuperiorPlayer superiorPlayer, Location location) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(location, "location cannot be null"); Preconditions.checkArgument(location.getWorld() != null, "location's world cannot be null"); Island island = plugin.getGrid().getIslandAt(location); return island == null ? MoveResult.SUCCESS : handlePlayerEnterIslandInternal(superiorPlayer, island, null, location, IslandEnterEvent.EnterCause.PLAYER_JOIN); } @Override public MoveResult handlePlayerQuit(SuperiorPlayer superiorPlayer, Location location) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Island island = plugin.getGrid().getIslandAt(location); if (island == null) return MoveResult.SUCCESS; island.setPlayerInside(superiorPlayer, false); return handlePlayerLeaveIslandInternal(superiorPlayer, island, location, null, IslandLeaveEvent.LeaveCause.PLAYER_QUIT); } private MoveResult handlePlayerEnterIslandInternal(SuperiorPlayer superiorPlayer, Island toIsland, @Nullable Location from, Location to, IslandEnterEvent.EnterCause enterCause) { // This can happen after the leave event is cancelled. if (superiorPlayer.hasPlayerStatus(PlayerStatus.LEAVING_ISLAND)) { superiorPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); return MoveResult.SUCCESS; } // Checking if the player is banned from the island. if (toIsland.isBanned(superiorPlayer) && !superiorPlayer.hasBypassModeEnabled() && !superiorPlayer.hasPermissionWithoutOP("superior.admin.ban.bypass")) { PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.BANNED_FROM_ISLAND); Message.BANNED_FROM_ISLAND.send(superiorPlayer); return MoveResult.BANNED_FROM_ISLAND; } // Checking if the player is locked to visitors. if (toIsland.isLocked() && !toIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) { PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LOCKED_ISLAND); Message.NO_CLOSE_BYPASS.send(superiorPlayer); return MoveResult.ISLAND_LOCKED; } Island fromIsland = from == null ? null : plugin.getGrid().getIslandAt(from); boolean equalIslands = toIsland.equals(fromIsland); boolean toInsideRange = toIsland.isInsideRange(to); boolean fromInsideRange = from != null && fromIsland != null && fromIsland.isInsideRange(from); boolean equalWorlds = from != null && to.getWorld().equals(from.getWorld()); if (toInsideRange && (!equalIslands || !fromInsideRange) && !PluginEventsFactory.callIslandEnterProtectedEvent(toIsland, superiorPlayer, enterCause)) { PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.ENTER_PROTECTED_EVENT_CANCELLED); return MoveResult.ENTER_EVENT_CANCELLED; } if (equalIslands) { if (!equalWorlds) { BukkitExecutor.sync(() -> plugin.getNMSWorld().setWorldBorder(superiorPlayer, toIsland), 1L); superiorPlayer.setPlayerStatus(PlayerStatus.PORTALS_IMMUNED); BukkitExecutor.sync(() -> { superiorPlayer.removePlayerStatus(PlayerStatus.PORTALS_IMMUNED); }, 100L); } return MoveResult.SUCCESS; } if (!PluginEventsFactory.callIslandEnterEvent(toIsland, superiorPlayer, enterCause)) { PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.ENTER_EVENT_CANCELLED); return MoveResult.ENTER_EVENT_CANCELLED; } toIsland.setPlayerInside(superiorPlayer, true); if (!toIsland.isMember(superiorPlayer) && toIsland.hasSettingsEnabled(IslandFlags.PVP)) { Message.ENTER_PVP_ISLAND.send(superiorPlayer); if (plugin.getSettings().isImmuneToPvPWhenTeleport()) { superiorPlayer.setPlayerStatus(PlayerStatus.PVP_IMMUNED); BukkitExecutor.sync(() -> { superiorPlayer.removePlayerStatus(PlayerStatus.PVP_IMMUNED); }, 200L); } } superiorPlayer.setPlayerStatus(PlayerStatus.PORTALS_IMMUNED); BukkitExecutor.sync(() -> { superiorPlayer.removePlayerStatus(PlayerStatus.PORTALS_IMMUNED); }, 100L); Player player = superiorPlayer.asPlayer(); if (player != null && (plugin.getSettings().getSpawn().isProtected() || !toIsland.isSpawn())) { BukkitExecutor.sync(() -> { // Update player time and player weather with a delay. // Fixes https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1260 if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_DAY)) { player.setPlayerTime(0, false); } else if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_MIDDLE_DAY)) { player.setPlayerTime(6000, false); } else if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_NIGHT)) { player.setPlayerTime(14000, false); } else if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_MIDDLE_NIGHT)) { player.setPlayerTime(18000, false); } if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_SHINY)) { player.setPlayerWeather(WeatherType.CLEAR); } else if (toIsland.hasSettingsEnabled(IslandFlags.ALWAYS_RAIN)) { player.setPlayerWeather(WeatherType.DOWNFALL); } }, 1L); } if (superiorPlayer.hasIslandFlyEnabled() && !superiorPlayer.hasFlyGamemode()) { BukkitExecutor.sync(() -> { if (player != null) toIsland.updateIslandFly(superiorPlayer); }, 5L); } BukkitExecutor.sync(() -> { toIsland.applyEffects(superiorPlayer); plugin.getNMSWorld().setWorldBorder(superiorPlayer, toIsland); }, 1L); return MoveResult.SUCCESS; } private MoveResult handlePlayerLeaveIslandInternal(SuperiorPlayer superiorPlayer, Island fromIsland, Location from, @Nullable Location to, IslandLeaveEvent.LeaveCause leaveCause) { Island toIsland = to == null ? null : plugin.getGrid().getIslandAt(to); boolean equalWorlds = to != null && from.getWorld().equals(to.getWorld()); boolean equalIslands = fromIsland.equals(toIsland); boolean fromInsideRange = fromIsland.isInsideRange(from); boolean toInsideRange = to != null && toIsland != null && toIsland.isInsideRange(to); //Checking for the stop leaving feature. if (plugin.getSettings().isStopLeaving() && fromInsideRange && !toInsideRange && !superiorPlayer.hasBypassModeEnabled() && !fromIsland.isSpawn() && equalWorlds) { PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_ISLAND_TO_OUTSIDE); superiorPlayer.setPlayerStatus(PlayerStatus.LEAVING_ISLAND); return MoveResult.LEAVE_ISLAND_TO_OUTSIDE; } // Handling the leave protected event if (fromInsideRange && (!equalIslands || !toInsideRange)) { if (!PluginEventsFactory.callIslandLeaveProtectedEvent(fromIsland, superiorPlayer, leaveCause, to)) { PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_PROTECTED_EVENT_CANCELLED); return MoveResult.ENTER_EVENT_CANCELLED; } } if (equalIslands) return MoveResult.SUCCESS; if (!PluginEventsFactory.callIslandLeaveEvent(fromIsland, superiorPlayer, leaveCause, to)) { PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_EVENT_CANCELLED); return MoveResult.ENTER_EVENT_CANCELLED; } fromIsland.setPlayerInside(superiorPlayer, false); Player player = superiorPlayer.asPlayer(); if (player != null) { player.resetPlayerTime(); player.resetPlayerWeather(); fromIsland.removeEffects(superiorPlayer); if (superiorPlayer.hasIslandFlyEnabled() && (toIsland == null || toIsland.isSpawn()) && !superiorPlayer.hasFlyGamemode()) { player.setAllowFlight(false); player.setFlying(false); Message.ISLAND_FLY_DISABLED.send(player); } } if (toIsland == null) plugin.getNMSWorld().setWorldBorder(superiorPlayer, null); return MoveResult.SUCCESS; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.stackedblocks; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.StackedBlocksInteractionService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; import com.google.common.base.Preconditions; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import java.math.BigInteger; public class StackedBlocksInteractionServiceImpl implements StackedBlocksInteractionService, IService { private static final KeyMap BLOCK_KEY_TRANSFORMER = createBlockKeyTransformer(); private final LazyReference regionManagerService = new LazyReference() { @Override protected RegionManagerService create() { return plugin.getServices().getService(RegionManagerService.class); } }; private final SuperiorSkyblockPlugin plugin; public StackedBlocksInteractionServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Class getAPIClass() { return StackedBlocksInteractionService.class; } @Override public InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, Block block, EquipmentSlot usedHand) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); Preconditions.checkNotNull(usedHand, "usedHand cannot be null"); if (!plugin.getSettings().getStackedBlocks().isEnabled()) return InteractionResult.STACKED_BLOCKS_DISABLED; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return InteractionResult.DISABLED_WORLD; Player onlinePlayer = superiorPlayer.asPlayer(); ItemStack handItem = onlinePlayer == null ? null : BukkitItems.getHandItem(onlinePlayer, PlayerHand.of(usedHand)); InteractionResult interactionResult = checkBlockStackInternal(superiorPlayer, block, handItem); if (interactionResult != InteractionResult.SUCCESS) return interactionResult; int amountToDeposit = onlinePlayer == null ? 1 : handItem == null ? 1 : onlinePlayer.isSneaking() ? handItem.getAmount() : 1; return handleBlockStackInternal(superiorPlayer, block, amountToDeposit, Either.left(usedHand)); } @Override public InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, Block block, int amountToDeposit, OnItemRemovalCallback itemRemovalCallback) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); Preconditions.checkNotNull(itemRemovalCallback, "itemRemovalCallback cannot be null"); if (!plugin.getSettings().getStackedBlocks().isEnabled()) return InteractionResult.STACKED_BLOCKS_DISABLED; // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return InteractionResult.DISABLED_WORLD; InteractionResult interactionResult = checkBlockStackInternal(superiorPlayer, block, null); if (interactionResult != InteractionResult.SUCCESS) return interactionResult; return handleBlockStackInternal(superiorPlayer, block, amountToDeposit, Either.right(itemRemovalCallback)); } @Override public InteractionResult checkStackedBlockInteraction(SuperiorPlayer superiorPlayer, Block block, ItemStack itemStack) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null"); Preconditions.checkNotNull(block, "block parameter cannot be null"); Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null"); // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return InteractionResult.DISABLED_WORLD; return checkBlockStackInternal(superiorPlayer, block, itemStack); } @Override public InteractionResult handleStackedBlockBreak(Block block, @Nullable SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(block, "block cannot be null"); // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return InteractionResult.DISABLED_WORLD; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); int blockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); if (blockAmount <= 1) return InteractionResult.NOT_STACKED_BLOCK; Island island = plugin.getGrid().getIslandAt(blockLocation); if (superiorPlayer != null && island != null) { com.bgsoftware.superiorskyblock.api.service.region.InteractionResult interactionResult = this.regionManagerService.get().handleBlockBreak(superiorPlayer, block); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) return InteractionResult.STACKED_BLOCK_PROTECTED; } Player onlinePlayer = superiorPlayer == null ? null : superiorPlayer.asPlayer(); int amountToBreak = Math.min(blockAmount, onlinePlayer != null && onlinePlayer.isSneaking() ? 64 : 1); int leftAmount = blockAmount - amountToBreak; if (!PluginEventsFactory.callBlockUnstackEvent(block, onlinePlayer, blockAmount, leftAmount)) return InteractionResult.EVENT_CANCELLED; if (!plugin.getStackedBlocks().setStackedBlock(block, leftAmount)) return InteractionResult.GLITCHED_STACKED_BLOCK; plugin.getNMSWorld().playBreakAnimation(block); if (superiorPlayer != null) { OfflinePlayer offlinePlayer = onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer; plugin.getProviders().notifyStackedBlocksListeners(offlinePlayer, block, IStackedBlocksListener.Action.BLOCK_BREAK); } if (island != null) island.handleBlockBreak(block, amountToBreak); ItemStack blockItem = ServerVersion.isLegacy() ? block.getState().getData().toItemStack(amountToBreak) : new ItemStack(block.getType(), amountToBreak); if (leftAmount <= 0) block.setType(Material.AIR); // Dropping the item if (onlinePlayer != null && plugin.getSettings().getStackedBlocks().isAutoCollect()) { BukkitItems.addItem(blockItem, onlinePlayer.getInventory(), blockLocation); } else { block.getWorld().dropItemNaturally(blockLocation.add(0, 0.5, 0), blockItem); } } return InteractionResult.SUCCESS; } private InteractionResult checkBlockStackInternal(SuperiorPlayer superiorPlayer, Block block, @Nullable ItemStack itemStack) { if (!superiorPlayer.hasBlocksStackerEnabled()) return InteractionResult.PLAYER_STACKED_BLOCKS_DISABLED; if (plugin.getSettings().getStackedBlocks().getDisabledWorlds().contains(block.getWorld().getName())) return InteractionResult.DISABLED_WORLD; Key blockKey = Keys.of(block); if (itemStack != null) { if (itemStack.hasItemMeta() && (itemStack.getItemMeta().hasDisplayName() || itemStack.getItemMeta().hasLore())) return InteractionResult.CUSTOMIZED_ITEM; Key itemKey = Keys.of(itemStack); if (!itemKey.equals(blockKey)) return InteractionResult.PLAYER_HOLDING_DIFFERENT_ITEM; } Material blockType = block.getType(); if (!superiorPlayer.hasPermission("superior.island.stacker.*") && !superiorPlayer.hasPermission("superior.island.stacker." + blockType)) return InteractionResult.PLAYER_MISSING_PERMISSION; Key newBlockKey = BLOCK_KEY_TRANSFORMER.getOrDefault(blockKey, blockKey); KeySet whitelist = (KeySet) plugin.getSettings().getStackedBlocks().getWhitelisted(); if (!whitelist.contains(newBlockKey)) return InteractionResult.STACKED_BLOCK_NOT_WHITELISTED; return InteractionResult.SUCCESS; } private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer, Block stackedBlock, int amountToDeposit, Either removalData) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return handleBlockStackInternal(superiorPlayer, stackedBlock, stackedBlock.getLocation(wrapper.getHandle()), amountToDeposit, removalData); } } private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer, Block stackedBlock, Location stackedBlockLocation, int amountToDeposit, Either removalData) { Player onlinePlayer = superiorPlayer.asPlayer(); int blockAmount = plugin.getStackedBlocks().getStackedBlockAmount(stackedBlockLocation); Key blockKey = plugin.getStackedBlocks().getStackedBlockKey(stackedBlockLocation); if (blockKey == null) blockKey = Keys.of(stackedBlock); int blockLimit = plugin.getSettings().getStackedBlocks().getLimits().getOrDefault(blockKey, Integer.MAX_VALUE); // We make sure the amountToDeposit does not exceed the block limit if (blockAmount + amountToDeposit > blockLimit) amountToDeposit = blockLimit - blockAmount; if (amountToDeposit <= 0) { // Inform GUI/caller that nothing was deposited so it can refund its previewed removal removalData.ifRight(cb -> cb.accept(0)); return InteractionResult.NOT_ENOUGH_BLOCKS; } Island island = plugin.getGrid().getIslandAt(stackedBlockLocation); if (island != null) { // We ensure we do not exceed island's block limit BigInteger amountToDepositBig = BigInteger.valueOf(amountToDeposit); // Checking for the specific block key BigInteger islandBlockLimit = BigInteger.valueOf(island.getExactBlockLimit(blockKey)); BigInteger islandBlockCount = island.getBlockCountAsBigInteger(blockKey); if (islandBlockLimit.compareTo(BigInteger.ZERO) >= 0 && islandBlockCount.add(amountToDepositBig).compareTo(islandBlockLimit) > 0) { amountToDeposit = islandBlockLimit.subtract(islandBlockCount).intValue(); } else { // Checking for the global block key Key globalKey = ((BaseKey) blockKey).toGlobalKey(); islandBlockLimit = BigInteger.valueOf(island.getExactBlockLimit(globalKey)); islandBlockCount = island.getBlockCountAsBigInteger(globalKey); if (islandBlockLimit.compareTo(BigInteger.ZERO) >= 0 && islandBlockCount.add(amountToDepositBig).compareTo(islandBlockLimit) > 0) { amountToDeposit = islandBlockLimit.subtract(islandBlockCount).intValue(); } } } if (amountToDeposit <= 0) { // Island/global limit reached ⇒ notify caller so it can refund removalData.ifRight(cb -> cb.accept(0)); return InteractionResult.NOT_ENOUGH_BLOCKS; } int newStackedBlockAmount = blockAmount + amountToDeposit; if (onlinePlayer != null && !PluginEventsFactory.callBlockStackEvent(stackedBlock, onlinePlayer, blockAmount, newStackedBlockAmount)) { // Event cancelled ⇒ nothing deposited, request refund removalData.ifRight(cb -> cb.accept(0)); return InteractionResult.EVENT_CANCELLED; } if (!plugin.getStackedBlocks().setStackedBlock(stackedBlockLocation, blockKey, newStackedBlockAmount)) { // Failed to persist/update ⇒ request refund removalData.ifRight(cb -> cb.accept(0)); return InteractionResult.GLITCHED_STACKED_BLOCK; } if (island != null) island.handleBlockPlace(blockKey, amountToDeposit); plugin.getProviders().notifyStackedBlocksListeners(onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer, stackedBlock, IStackedBlocksListener.Action.BLOCK_PLACE); final int finalAmountToDeposit = amountToDeposit; removalData.ifRight(itemRemovalCallback -> itemRemovalCallback.accept(finalAmountToDeposit)).ifLeft(usedHand -> { if (onlinePlayer != null && onlinePlayer.getGameMode() != GameMode.CREATIVE) { BukkitItems.removeHandItem(onlinePlayer, PlayerHand.of(usedHand), finalAmountToDeposit); } }); return InteractionResult.SUCCESS; } private static KeyMap createBlockKeyTransformer() { KeyMap blockKeyTransformer = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); Material GLOWING_REDSTONE_ORE = EnumHelper.getEnum(Material.class, "GLOWING_REDSTONE_ORE"); if (GLOWING_REDSTONE_ORE != null) blockKeyTransformer.put(Keys.of(GLOWING_REDSTONE_ORE), Keys.of(Material.REDSTONE_ORE)); return KeyMaps.unmodifiableKeyMap(blockKeyTransformer); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksServiceHelper.java ================================================ package com.bgsoftware.superiorskyblock.service.stackedblocks; import com.bgsoftware.superiorskyblock.api.service.stackedblocks.InteractionResult; public class StackedBlocksServiceHelper { private StackedBlocksServiceHelper() { } public static boolean shouldCancelOriginalEvent(InteractionResult result) { switch (result) { case STACKED_BLOCK_PROTECTED: case EVENT_CANCELLED: case SUCCESS: return true; default: return false; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java ================================================ package com.bgsoftware.superiorskyblock.service.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.service.world.RecordResult; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Minecart; import java.util.EnumMap; public class WorldRecordServiceImpl implements WorldRecordService, IService { @WorldRecordFlags private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; private static final BlockFace[] NEARBY_BLOCKS = new BlockFace[]{ BlockFace.UP, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.EAST }; private final SuperiorSkyblockPlugin plugin; public WorldRecordServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } @Override public Class getAPIClass() { return WorldRecordService.class; } @Override public RecordResult recordBlockPlace(Block block, int blockCount, @Nullable BlockState oldBlockState, @WorldRecordFlags int flags) { Preconditions.checkNotNull(block, "block cannot be null"); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return recordBlockPlace(Keys.of(block), block.getLocation(wrapper.getHandle()), blockCount, oldBlockState, flags); } } @Override public RecordResult recordBlockPlace(Key blockKey, Location blockLocation, int blockCount, @Nullable BlockState oldBlockState, @WorldRecordFlags int flags) { Preconditions.checkNotNull(blockKey, "blockKey cannot be null"); Preconditions.checkNotNull(blockLocation, "blockLocation cannot be null"); Preconditions.checkArgument(blockLocation.getWorld() != null, "blockLocation's world cannot be null"); Island island = plugin.getGrid().getIslandAt(blockLocation); if (island == null) return RecordResult.NOT_IN_ISLAND; recordBlockPlaceInternal(island, blockKey, blockLocation, blockCount, oldBlockState, flags); return RecordResult.SUCCESS; } @Override public RecordResult recordMultiBlocksPlace(KeyMap blockCounts, Location location, @WorldRecordFlags int flags) { Preconditions.checkNotNull(blockCounts, "blockCounts cannot be null"); Preconditions.checkNotNull(location, "location cannot be null"); Preconditions.checkArgument(location.getWorld() != null, "location's world cannot be null"); if (blockCounts.isEmpty()) return RecordResult.SUCCESS; Island island = plugin.getGrid().getIslandAt(location); if (island == null) return RecordResult.NOT_IN_ISLAND; boolean saveBlockCounts = (flags & WorldRecordFlags.SAVE_BLOCK_COUNT) != 0; boolean dirtyChunks = (flags & WorldRecordFlags.DIRTY_CHUNKS) != 0; int blockPlaceFlags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS | (saveBlockCounts ? IslandBlockFlags.SAVE_BLOCK_COUNTS : 0); island.handleBlocksPlace(blockCounts, blockPlaceFlags); if (dirtyChunks) { island.markChunkDirty(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, true); } return RecordResult.SUCCESS; } private void recordBlockPlaceInternal(Island island, Key blockKey, Location blockLocation, int blockCount, @Nullable BlockState oldBlockState, @WorldRecordFlags int flags) { boolean saveBlockCounts = (flags & WorldRecordFlags.SAVE_BLOCK_COUNT) != 0; boolean dirtyChunks = (flags & WorldRecordFlags.DIRTY_CHUNKS) != 0; if (oldBlockState != null && oldBlockState.getType() != Material.AIR) { Material blockStateType = oldBlockState.getType(); Key oldBlockKey; int oldBlockCount = 1; if (Materials.isLava(blockStateType)) { oldBlockKey = ConstantKeys.LAVA; } else if (Materials.isWater(blockStateType)) { oldBlockKey = ConstantKeys.WATER; } else { oldBlockKey = Keys.of(oldBlockState); oldBlockCount = plugin.getNMSWorld().getDefaultAmount(oldBlockState); } recordBlockBreakInternal(island, oldBlockKey, blockLocation, oldBlockCount, flags); } if (blockKey.equals(ConstantKeys.END_PORTAL_FRAME_WITH_EYE)) recordBlockBreakInternal(island, ConstantKeys.END_PORTAL_FRAME, blockLocation, 1, flags); if (plugin.getProviders().shouldListenToSpawnerChanges() || !(blockKey instanceof SpawnerKey)) { int blockPlaceFlags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS; if (saveBlockCounts) blockPlaceFlags |= IslandBlockFlags.SAVE_BLOCK_COUNTS; island.handleBlockPlace(blockKey, blockCount, blockPlaceFlags); } if (dirtyChunks) { island.markChunkDirty(blockLocation.getWorld(), blockLocation.getBlockX() >> 4, blockLocation.getBlockZ() >> 4, true); } } @Override public RecordResult recordBlockBreak(Block block, @WorldRecordFlags int flags) { Preconditions.checkNotNull(block, "block cannot be null"); return recordBlockBreak(block, plugin.getNMSWorld().getDefaultAmount(block), flags); } @Override public RecordResult recordBlockBreak(Block block, int blockCount, @WorldRecordFlags int flags) { Preconditions.checkNotNull(block, "block cannot be null"); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return recordBlockBreak(Keys.of(block), block.getLocation(wrapper.getHandle()), blockCount, flags); } } @Override public RecordResult recordBlockBreak(Key blockKey, Location blockLocation, int blockCount, @WorldRecordFlags int flags) { Preconditions.checkNotNull(blockKey, "blockKey cannot be null"); Preconditions.checkNotNull(blockLocation, "blockLocation cannot be null"); Preconditions.checkArgument(blockLocation.getWorld() != null, "blockLocation's world cannot be null"); Island island = plugin.getGrid().getIslandAt(blockLocation); if (island == null) return RecordResult.NOT_IN_ISLAND; recordBlockBreakInternal(island, blockKey, blockLocation, blockCount, flags); return RecordResult.SUCCESS; } @Override public RecordResult recordMultiBlocksBreak(KeyMap blockCounts, Location location, @WorldRecordFlags int flags) { Preconditions.checkNotNull(blockCounts, "blockCounts cannot be null"); Preconditions.checkNotNull(location, "location cannot be null"); Preconditions.checkArgument(location.getWorld() != null, "location's world cannot be null"); if (blockCounts.isEmpty()) return RecordResult.SUCCESS; Island island = plugin.getGrid().getIslandAt(location); if (island == null) return RecordResult.NOT_IN_ISLAND; boolean saveBlockCounts = (flags & WorldRecordFlags.SAVE_BLOCK_COUNT) != 0; boolean dirtyChunks = (flags & WorldRecordFlags.DIRTY_CHUNKS) != 0; int blockBreakFlags = IslandBlockFlags.UPDATE_LAST_TIME_STATUS | (saveBlockCounts ? IslandBlockFlags.SAVE_BLOCK_COUNTS : 0); island.handleBlocksBreak(blockCounts, blockBreakFlags); if (dirtyChunks && plugin.getNMSChunks().isChunkEmpty(location.getChunk())) { island.markChunkEmpty(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, true); } return RecordResult.SUCCESS; } private void recordBlockBreakInternal(Island island, Key blockKey, Location blockLocation, int blockCount, @WorldRecordFlags int flags) { boolean saveBlockCounts = (flags & WorldRecordFlags.SAVE_BLOCK_COUNT) != 0; boolean dirtyChunks = (flags & WorldRecordFlags.DIRTY_CHUNKS) != 0; boolean handleNearbyBlocks = (flags & WorldRecordFlags.HANDLE_NEARBY_BLOCKS) != 0; int handleBlockBreakFlag = IslandBlockFlags.UPDATE_LAST_TIME_STATUS | (saveBlockCounts ? IslandBlockFlags.SAVE_BLOCK_COUNTS : 0); if (plugin.getProviders().shouldListenToSpawnerChanges() || !(blockKey instanceof SpawnerKey)) island.handleBlockBreak(blockKey, blockCount, handleBlockBreakFlag); if (handleNearbyBlocks || dirtyChunks) { EnumMap nearbyBlocks = new EnumMap<>(BlockFace.class); Block block = blockLocation.getBlock(); if (handleNearbyBlocks) { for (BlockFace nearbyFace : NEARBY_BLOCKS) { Block nearbyBlock = block.getRelative(nearbyFace); Material blockType = nearbyBlock.getType(); if (blockType != Material.AIR && !blockType.isSolid()) { Key nearbyBlockKey = Keys.of(nearbyBlock); nearbyBlocks.put(nearbyFace, nearbyBlockKey); } } } BukkitExecutor.sync(() -> { if (dirtyChunks) { if (plugin.getNMSChunks().isChunkEmpty(block.getChunk())) { island.markChunkEmpty(block.getWorld(), block.getX() >> 4, block.getZ() >> 4, true); } } if (handleNearbyBlocks) { for (BlockFace nearbyFace : NEARBY_BLOCKS) { Key nearbyBlock = Keys.of(block.getRelative(nearbyFace)); Key oldNearbyBlock = nearbyBlocks.getOrDefault(nearbyFace, ConstantKeys.AIR); if (oldNearbyBlock != ConstantKeys.AIR && !nearbyBlock.equals(oldNearbyBlock)) { island.handleBlockBreak(oldNearbyBlock, 1, handleBlockBreakFlag); } } } }, 2L); } } @Override public RecordResult recordEntitySpawn(Entity entity) { Preconditions.checkNotNull(entity, "entity parameter cannot be null"); if (entity.isDead()) return RecordResult.ENTITY_CANNOT_BE_TRACKED; if (BukkitEntities.canBypassEntityLimit(entity)) return RecordResult.ENTITY_CANNOT_BE_TRACKED; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { return recordEntitySpawnInternal(entity.getType(), entity.getLocation(wrapper.getHandle())); } } @Override public RecordResult recordEntitySpawn(EntityType entityType, Location location) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null"); Preconditions.checkNotNull(location, "location parameter cannot be null"); Preconditions.checkArgument(location.getWorld() != null, "location's world parameter cannot be null"); return recordEntitySpawnInternal(entityType, location); } private RecordResult recordEntitySpawnInternal(EntityType entityType, Location location) { if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class) || !BukkitEntities.canHaveLimit(entityType)) return RecordResult.ENTITY_CANNOT_BE_TRACKED; Island island = plugin.getGrid().getIslandAt(location); if (island == null) return RecordResult.NOT_IN_ISLAND; island.getEntitiesTracker().trackEntity(Keys.of(entityType), 1); // TODO: elsewhere IslandsDatabaseBridge.saveEntityCounts(island); return RecordResult.SUCCESS; } @Override public RecordResult recordEntityDespawn(Entity entity) { Preconditions.checkNotNull(entity, "entity parameter cannot be null"); if (BukkitEntities.canBypassEntityLimit(entity)) return RecordResult.ENTITY_CANNOT_BE_TRACKED; RecordResult recordResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { recordResult = recordEntityDespawnInternal(entity.getType(), entity.getLocation(wrapper.getHandle())); } if (recordResult != RecordResult.SUCCESS) return recordResult; if (entity instanceof Minecart) { Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) entity); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { recordBlockBreak(blockKey, entity.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS); } } return RecordResult.SUCCESS; } @Override public RecordResult recordEntityDespawn(EntityType entityType, Location location) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null"); Preconditions.checkNotNull(location, "location parameter cannot be null"); Preconditions.checkArgument(location.getWorld() != null, "location's world parameter cannot be null"); return recordEntityDespawnInternal(entityType, location); } private RecordResult recordEntityDespawnInternal(EntityType entityType, Location location) { if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class) || !BukkitEntities.canHaveLimit(entityType)) return RecordResult.ENTITY_CANNOT_BE_TRACKED; Island island = plugin.getGrid().getIslandAt(location); if (island == null) return RecordResult.NOT_IN_ISLAND; island.getEntitiesTracker().untrackEntity(Keys.of(entityType), 1); // TODO: not here IslandsDatabaseBridge.saveEntityCounts(island); return RecordResult.SUCCESS; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java ================================================ package com.bgsoftware.superiorskyblock.tag; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; public class BigDecimalTag extends Tag { private BigDecimalTag(BigDecimal value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeInt(value.scale()); os.writeInt(value.precision()); byte[] data = value.toBigIntegerExact().toByteArray(); os.writeInt(data.length); os.write(data); } public static BigDecimalTag of(BigDecimal value) { return new BigDecimalTag(value); } public static BigDecimalTag fromStream(DataInputStream is) throws IOException { int scale = is.readInt(); int precision = is.readInt(); byte[] data = new byte[is.readInt()]; is.readFully(data); return BigDecimalTag.of(new BigDecimal(new BigInteger(data), scale, new MathContext(precision))); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Locale; /** * The TAG_Byte_Array tag. * * @author Graham Edgecombe */ public class ByteArrayTag extends Tag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagByteArray", "ByteArrayTag"}, byte[].class); private static final ByteArrayTag EMPTY = new ByteArrayTag(new byte[0]); private ByteArrayTag(byte[] value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeInt(value.length); os.write(value); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } @Override public String toString() { StringBuilder hex = new StringBuilder(); for (byte b : value) { String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ENGLISH); if (hexDigits.length() == 1) { hex.append("0"); } hex.append(hexDigits).append(" "); } return "TAG_Byte_Array: " + hex; } public static ByteArrayTag of(byte[] value) { return value.length == 0 ? EMPTY : new ByteArrayTag(value); } public static ByteArrayTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to ByteArrayTag!"); try { byte[] value = plugin.getNMSTags().getNBTByteArrayValue(tag); return ByteArrayTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag byte-array from NMS:"); return null; } } public static ByteArrayTag fromStream(DataInputStream is) throws IOException { int length = is.readInt(); byte[] bytes = new byte[length]; is.readFully(bytes); return ByteArrayTag.of(bytes); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * The TAG_Byte tag. * * @author Graham Edgecombe */ public class ByteTag extends NumberTag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagByte", "ByteTag"}, byte.class); private static final ByteTag[] CACHE = new ByteTag[256]; private ByteTag(byte value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeByte(value); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } public static ByteTag of(byte value) { int index = value - Byte.MIN_VALUE; ByteTag tag = CACHE[index]; if (tag == null) tag = CACHE[index] = new ByteTag(value); return tag; } public static ByteTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to ByteTag!"); try { byte value = plugin.getNMSTags().getNBTByteValue(tag); return ByteTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag byte from NMS:"); return null; } } public static ByteTag fromStream(DataInputStream is) throws IOException { return ByteTag.of(is.readByte()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Optional; import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.OptionalLong; import java.util.Set; /** * The TAG_Compound tag. * * @author Graham Edgecombe */ public class CompoundTag extends Tag>> implements Iterable> { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice("NBTTagCompound", "CompoundTag"); private CompoundTag(Map> value, boolean cloneMap) { super(cloneMap ? new HashMap<>(value) : value); } @Override protected void writeData(DataOutputStream os) throws IOException { for (Map.Entry> entry : value.entrySet()) { entry.getValue().write(os); byte[] keyBytes = entry.getKey().getBytes(StandardCharsets.UTF_8); os.writeShort(keyBytes.length); os.write(keyBytes); } os.writeByte((byte) 0); } public CompoundTag copy() { return of(this.value); } public Optional> getTag(String key) { return Optional.ofNullable(getTagInternal(key)); } public Optional getByteArray(String key) { return getTagInternal(key, ByteArrayTag.class).map(tag -> tag.value); } public OptionalInt getByte(String key) { NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.byteValue()); } public Optional getCompound(String key) { return getTagInternal(key, CompoundTag.class); } public OptionalDouble getDouble(String key) { NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); return tag == null ? OptionalDouble.empty() : OptionalDouble.of(tag.value.doubleValue()); } public OptionalDouble getFloat(String key) { NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); return tag == null ? OptionalDouble.empty() : OptionalDouble.of(tag.value.floatValue()); } public Optional getIntArray(String key) { return getTagInternal(key, IntArrayTag.class).map(tag -> tag.value); } public OptionalInt getInt(String key) { NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.intValue()); } public Optional getList(String key) { return getTagInternal(key, ListTag.class); } public OptionalLong getLong(String key) { NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); return tag == null ? OptionalLong.empty() : OptionalLong.of(tag.value.longValue()); } public Optional getNumber(String key) { return getTagInternal(key, NumberTag.class).map(tag -> (Number) tag.value); } public OptionalInt getShort(String key) { NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.shortValue()); } public Optional getString(String key) { return getTagInternal(key, StringTag.class).map(tag -> tag.value); } @Nullable public Tag setTag(String key, Tag value) { return this.value.put(key, value); } public void setByteArray(String key, byte[] value) { setTag(key, ByteArrayTag.of(value)); } public void setByte(String key, byte value) { setTag(key, ByteTag.of(value)); } public void setDouble(String key, double value) { setTag(key, DoubleTag.of(value)); } public void setFloat(String key, float value) { setTag(key, FloatTag.of(value)); } public void setIntArray(String key, int[] value) { setTag(key, IntArrayTag.of(value)); } public void setInt(String key, int value) { setTag(key, IntTag.of(value)); } public void setLong(String key, long value) { setTag(key, LongTag.of(value)); } public void setShort(String key, short value) { setTag(key, ShortTag.of(value)); } public void setString(String key, String value) { setTag(key, StringTag.of(value)); } public void putAll(CompoundTag other) { this.value.putAll(other.value); } public boolean containsKey(String key) { return this.value.containsKey(key); } public Tag remove(String key) { return this.value.remove(key); } public int size() { return value.size(); } public boolean isEmpty() { return value.isEmpty(); } public Set>> entrySet() { return value.entrySet(); } @NotNull @Override public Iterator> iterator() { return value.values().iterator(); } @Override public String toString() { StringBuilder bldr = new StringBuilder(); bldr.append("TAG_Compound: ").append(value.size()).append(" entries\r\n{\r\n"); for (Map.Entry> entry : value.entrySet()) { bldr.append(" ").append((entry.getValue() + "").replaceAll("\r\n", "\r\n ")).append("\r\n"); } bldr.append("}"); return bldr.toString(); } @Override public Object toNBT() { try { Object nbtTagCompound = TAG_CONVERTER.toNBT(); for (Map.Entry> entry : value.entrySet()) { plugin.getNMSTags().setNBTCompoundTagValue(nbtTagCompound, entry.getKey(), entry.getValue().toNBT()); } return nbtTagCompound; } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag compound to NMS:"); return null; } } @Nullable private Tag getTagInternal(String key) { return this.value.get(key); } @Nullable private > Optional getTagInternal(String key, Class valueType) { Tag tag = this.value.get(key); return tag != null && valueType.isAssignableFrom(tag.getClass()) ? Optional.of(valueType.cast(tag)) : Optional.empty(); } public static CompoundTag of() { return new CompoundTag(new HashMap<>(), false); } public static CompoundTag of(Map> value) { return new CompoundTag(value, true); } public static CompoundTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to CompoundTag!"); Map> map = new HashMap<>(); try { Set keySet = plugin.getNMSTags().getNBTCompoundValue(tag); for (String key : keySet) { map.put(key, Tag.fromNBT(plugin.getNMSTags().getNBTCompoundTag(tag, key))); } return new CompoundTag(map, false); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag compound from NMS:"); return null; } } public static CompoundTag fromStream(DataInputStream is, int depth) throws IOException { Map> tagMap = new HashMap<>(); Tag tag; while (!((tag = Tag.fromStream(is, depth + 1)) instanceof EndTag)) { int keyLength = is.readShort() & 0xFFFF; byte[] keyBytes = new byte[keyLength]; is.readFully(keyBytes); String key = new String(keyBytes, StandardCharsets.UTF_8); tagMap.put(key, tag); } return new CompoundTag(tagMap, false); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * The TAG_Double tag. * * @author Graham Edgecombe */ public class DoubleTag extends NumberTag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagDouble", "DoubleTag"}, double.class); private static final DoubleTag[] CACHE = new DoubleTag[100]; private DoubleTag(double value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeDouble(value); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } public static DoubleTag of(double value) { if (value == (int) value && value >= 0 && value < CACHE.length) { DoubleTag tag = CACHE[(int) value]; if (tag == null) tag = CACHE[(int) value] = new DoubleTag(value); return tag; } else { return new DoubleTag(value); } } public static DoubleTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to DoubleTag!"); try { double value = plugin.getNMSTags().getNBTDoubleValue(tag); return DoubleTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag double from NMS:"); return null; } } public static DoubleTag fromStream(DataInputStream is) throws IOException { return DoubleTag.of(is.readDouble()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * The TAG_End tag. * * @author Graham Edgecombe */ public class EndTag extends Tag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice("NBTTagEnd", "EndTag"); private static final EndTag INSTANCE = new EndTag(); private EndTag() { super(null); } @Override protected void writeData(DataOutputStream os) { // Do nothing. } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } @Override public String toString() { return "TAG_End"; } public static EndTag of() { return INSTANCE; } public static EndTag fromStream(DataInputStream is, int depth) throws IOException { if (depth == 0) { throw new IOException("TAG_End found without a TAG_Compound/TAG_List tag preceding it."); } else { return EndTag.INSTANCE; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * The TAG_Float tag. * * @author Graham Edgecombe */ public class FloatTag extends NumberTag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagFloat", "FloatTag"}, float.class); private static final FloatTag[] CACHE = new FloatTag[100]; private FloatTag(float value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeFloat(value); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } public static FloatTag of(float value) { if (value == (int) value && value >= 0 && value < CACHE.length) { FloatTag tag = CACHE[(int) value]; if (tag == null) tag = CACHE[(int) value] = new FloatTag(value); return tag; } else { return new FloatTag(value); } } public static FloatTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to FloatTag!"); try { float value = plugin.getNMSTags().getNBTFloatValue(tag); return FloatTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag float from NMS:"); return null; } } public static FloatTag fromStream(DataInputStream is) throws IOException { return FloatTag.of(is.readFloat()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java ================================================ //@formatter:off /* * JNBT License * * Copyright (c) 2010 Graham Edgecombe * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of the JNBT team nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ //@formatter:on package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.UUID; /** * The TAG_Byte_Array tag. * * @author Jocopa3 */ @SuppressWarnings("WeakerAccess") public class IntArrayTag extends Tag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagIntArray", "IntArrayTag"}, int[].class); private static final IntArrayTag EMPTY = new IntArrayTag(new int[0]); /** * Creates the tag. * * @param value The value. */ private IntArrayTag(int[] value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeInt(value.length); for (int i : value) os.writeInt(i); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } @Override public String toString() { StringBuilder integers = new StringBuilder(); for (int b : value) { integers.append(b).append(" "); } return "TAG_Int_Array: " + integers; } @Override public int hashCode() { int prime = 31; int result = super.hashCode(); result = (prime * result) + Arrays.hashCode(value); return result; } @Override public boolean equals(final Object obj) { return this == obj || (obj instanceof IntArrayTag && Arrays.equals(value, ((IntArrayTag) obj).value)); } public static IntArrayTag of(int[] value) { return value.length == 0 ? EMPTY : new IntArrayTag(value); } public static IntArrayTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to IntArrayTag!"); try { int[] value = plugin.getNMSTags().getNBTIntArrayValue(tag); return IntArrayTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag int-array from NMS:"); return null; } } public static IntArrayTag fromUUID(UUID uuid) { long MSB = uuid.getMostSignificantBits(); long LSB = uuid.getLeastSignificantBits(); return IntArrayTag.of(new int[]{(int) (MSB >> 32), (int) MSB, (int) (LSB >> 32), (int) LSB}); } public static IntArrayTag fromStream(DataInputStream is) throws IOException { int length = is.readInt(); int[] data = new int[length]; for (int i = 0; i < length; i++) { data[i] = is.readInt(); } return IntArrayTag.of(data); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * The TAG_Int tag. * * @author Graham Edgecombe */ public class IntTag extends NumberTag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagInt", "IntTag"}, int.class); private static final IntTag[] CACHE = new IntTag[100]; private IntTag(int value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeInt(value); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } public static IntTag of(int value) { if (value >= 0 && value < CACHE.length) { IntTag tag = CACHE[value]; if (tag == null) tag = CACHE[value] = new IntTag(value); return tag; } else { return new IntTag(value); } } public static IntTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to IntTag!"); try { int value = plugin.getNMSTags().getNBTIntValue(tag); return IntTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag int from NMS:"); return null; } } public static IntTag fromStream(DataInputStream is) throws IOException { return IntTag.of(is.readInt()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.RandomAccess; /** * The TAG_List tag. * * @author Graham Edgecombe */ @SuppressWarnings("rawtypes") public class ListTag extends Tag>> implements Iterable> { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice("NBTTagList", "ListTag"); private static final byte DYNAMIC_LIST_INDICATOR = (byte) 0xFF; /** * Hint to the type of elements in the list. */ @Nullable private Class hintType; private ListTag(List> value, @Nullable Class hintType, boolean cloneList) { super(cloneListIfNeeded(value, cloneList)); this.hintType = hintType; } public ListTag copy() { return of(this.value, this.hintType); } public void addTag(Tag tag) { this.value.add(tag); // In case the type of the tag is not similar to the hintType, we reset it. if (this.hintType != null && tag.getClass() != this.hintType) { this.hintType = null; } } @Override public List> getValue() { return Collections.unmodifiableList(value); } @NotNull @Override public Iterator> iterator() { return value.iterator(); } public int size() { return this.value.size(); } @Override public String toString() { StringBuilder bldr = new StringBuilder(); bldr.append("TAG_List: ").append(value.size()).append(" entries"); if (this.hintType != null) { bldr.append(" of type ").append(NBTUtils.getTypeName(hintType)); } bldr.append("\r\n{\r\n"); for (Tag t : value) { bldr.append(" ").append(t.toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); } bldr.append("}"); return bldr.toString(); } @Override protected void writeData(DataOutputStream os) throws IOException { if (this.hintType != null) { writeDataWithHint(os); } else { writeDataWithoutHint(os); } } private void writeDataWithHint(DataOutputStream os) throws IOException { int size = value.size(); os.writeByte(NBTUtils.getTypeCode(this.hintType)); os.writeInt(size); for (Tag _tag : value) _tag.writeData(os); } private void writeDataWithoutHint(DataOutputStream os) throws IOException { int size = value.size(); os.writeByte(DYNAMIC_LIST_INDICATOR); os.writeInt(size); for (Tag _tag : value) _tag.write(os); } @Override public Object toNBT() { return plugin.getNMSTags().parseList(this); } public static ListTag of(@Nullable Class hintType) { return new ListTag(new LinkedList<>(), hintType, false); } public static ListTag of(List> value) { return of(value, null); } public static ListTag of(List> value, @Nullable Class hintType) { return new ListTag(value, hintType, true); } public static ListTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to ListTag!"); List> list = new LinkedList<>(); try { int size = plugin.getNMSTags().getNBTTagListSize(tag); Class lastTagType = null; boolean isSimilarType = true; for (int i = 0; i < size; i++) { Tag currTag = Tag.fromNBT(plugin.getNMSTags().getNBTListIndexValue(tag, i)); if (isSimilarType) { if (lastTagType != null && currTag.getClass() != lastTagType) { isSimilarType = false; } else { lastTagType = currTag.getClass(); } } list.add(currTag); } return new ListTag(list, !isSimilarType || size == 0 ? null : lastTagType, false); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag list from NMS:"); return null; } } public static ListTag fromStream(DataInputStream is, int depth) throws IOException { int childType = is.readByte(); return childType == DYNAMIC_LIST_INDICATOR ? fromStreamWithoutHint(is, depth) : fromStreamWithHint(is, depth, childType); } private static ListTag fromStreamWithHint(DataInputStream is, int depth, int childType) throws IOException { int length = is.readInt(); List> tagList = new LinkedList<>(); for (int i = 0; i < length; i++) { Tag tag = Tag.fromStream(is, depth + 1, childType); if (tag instanceof EndTag) { throw new IOException("TAG_End not permitted in a list."); } tagList.add(tag); } return new ListTag(tagList, NBTUtils.getTypeClass(childType), false); } private static ListTag fromStreamWithoutHint(DataInputStream is, int depth) throws IOException { int length = is.readInt(); List> tagList = new LinkedList<>(); for (int i = 0; i < length; i++) { Tag tag = Tag.fromStream(is, depth + 1); if (tag instanceof EndTag) { throw new IOException("TAG_End not permitted in a list."); } tagList.add(tag); } return new ListTag(tagList, null, false); } private static List cloneListIfNeeded(List list, boolean cloneList) { return cloneList || list instanceof RandomAccess ? new LinkedList<>(list) : list; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * The TAG_Long tag. * * @author Graham Edgecombe */ public class LongTag extends NumberTag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagLong", "LongTag"}, long.class); private static final LongTag[] CACHE = new LongTag[100]; private LongTag(long value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeLong(value); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } public static LongTag of(long value) { if (value >= 0 && value < CACHE.length) { LongTag tag = CACHE[(int) value]; if (tag == null) tag = CACHE[(int) value] = new LongTag(value); return tag; } else { return new LongTag(value); } } public static LongTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to LongTag!"); try { long value = plugin.getNMSTags().getNBTLongValue(tag); return LongTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag long from NMS:"); return null; } } public static LongTag fromStream(DataInputStream is) throws IOException { return LongTag.of(is.readLong()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/NBTTags.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; public class NBTTags { public static final int TYPE_END = 0; public static final int TYPE_BYTE = 1; public static final int TYPE_SHORT = 2; public static final int TYPE_INT = 3; public static final int TYPE_LONG = 4; public static final int TYPE_FLOAT = 5; public static final int TYPE_DOUBLE = 6; public static final int TYPE_BYTE_ARRAY = 7; public static final int TYPE_STRING = 8; public static final int TYPE_LIST = 9; public static final int TYPE_COMPOUND = 10; public static final int TYPE_INT_ARRAY = 11; public static final int TYPE_BIG_DECIMAL = 12; public static final int TYPE_UUID = 13; public static final int TYPE_PERSISTENT_DATA = 14; private NBTTags() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; /** * A class which contains NBT-related utility methods. * * @author Graham Edgecombe */ @SuppressWarnings("WeakerAccess") public class NBTUtils { /** * Default private constructor. */ private NBTUtils() { } /** * Gets the type name of a tag. * * @param clazz The tag class. * @return The type name. */ public static String getTypeName(Class clazz) { if (clazz.equals(BigDecimalTag.class)) { return "TAG_Big_Decimal"; } else if (clazz.equals(ByteArrayTag.class)) { return "TAG_Byte_Array"; } else if (clazz.equals(ByteTag.class)) { return "TAG_Byte"; } else if (clazz.equals(CompoundTag.class)) { return "TAG_Compound"; } else if (clazz.equals(DoubleTag.class)) { return "TAG_Double"; } else if (clazz.equals(EndTag.class)) { return "TAG_End"; } else if (clazz.equals(FloatTag.class)) { return "TAG_Float"; } else if (clazz.equals(IntTag.class)) { return "TAG_Int"; } else if (clazz.equals(ListTag.class)) { return "TAG_List"; } else if (clazz.equals(LongTag.class)) { return "TAG_Long"; } else if (clazz.equals(ShortTag.class)) { return "TAG_Short"; } else if (clazz.equals(StringTag.class)) { return "TAG_String"; } else if (clazz.equals(IntArrayTag.class)) { return "TAG_Int_Array"; } else { throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")."); } } /** * Gets the type code of a tag class. * * @param clazz The tag class. * @return The type code. * @throws IllegalArgumentException if the tag class is invalid. */ public static int getTypeCode(Class clazz) { if (clazz.equals(BigDecimalTag.class)) { return NBTTags.TYPE_BIG_DECIMAL; } else if (clazz.equals(ByteArrayTag.class)) { return NBTTags.TYPE_BYTE_ARRAY; } else if (clazz.equals(ByteTag.class)) { return NBTTags.TYPE_BYTE; } else if (clazz.equals(CompoundTag.class)) { return NBTTags.TYPE_COMPOUND; } else if (clazz.equals(DoubleTag.class)) { return NBTTags.TYPE_DOUBLE; } else if (clazz.equals(EndTag.class)) { return NBTTags.TYPE_END; } else if (clazz.equals(FloatTag.class)) { return NBTTags.TYPE_FLOAT; } else if (clazz.equals(IntTag.class)) { return NBTTags.TYPE_INT; } else if (clazz.equals(ListTag.class)) { return NBTTags.TYPE_LIST; } else if (clazz.equals(LongTag.class)) { return NBTTags.TYPE_LONG; } else if (clazz.equals(PersistentDataTag.class) || clazz.equals(PersistentDataTagSerialized.class)) { return NBTTags.TYPE_PERSISTENT_DATA; } else if (clazz.equals(ShortTag.class)) { return NBTTags.TYPE_SHORT; } else if (clazz.equals(StringTag.class)) { return NBTTags.TYPE_STRING; } else if (clazz.equals(IntArrayTag.class)) { return NBTTags.TYPE_INT_ARRAY; } else if (clazz.equals(UUIDTag.class)) { return NBTTags.TYPE_UUID; } else { throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")."); } } /** * Gets the class of a type of tag. * * @param type The type. * @return The class. * @throws IllegalArgumentException if the tag type is invalid. */ public static Class getTypeClass(int type) { switch (type) { case NBTTags.TYPE_END: return EndTag.class; case NBTTags.TYPE_BYTE: return ByteTag.class; case NBTTags.TYPE_SHORT: return ShortTag.class; case NBTTags.TYPE_INT: return IntTag.class; case NBTTags.TYPE_LONG: return LongTag.class; case NBTTags.TYPE_FLOAT: return FloatTag.class; case NBTTags.TYPE_DOUBLE: return DoubleTag.class; case NBTTags.TYPE_BYTE_ARRAY: return ByteArrayTag.class; case NBTTags.TYPE_STRING: return StringTag.class; case NBTTags.TYPE_LIST: return ListTag.class; case NBTTags.TYPE_COMPOUND: return CompoundTag.class; case NBTTags.TYPE_INT_ARRAY: return IntArrayTag.class; case NBTTags.TYPE_BIG_DECIMAL: return BigDecimalTag.class; case NBTTags.TYPE_UUID: return UUIDTag.class; case NBTTags.TYPE_PERSISTENT_DATA: return PersistentDataTagSerialized.class; default: throw new IllegalArgumentException("Invalid tag type : " + type + "."); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java ================================================ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.common.reflection.ReflectConstructor; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Bukkit; import javax.annotation.Nullable; public class NMSTagConverter { private static final Class[] EMPTY_PARAMS = new Class[0]; private final Class clazz; private final ReflectMethod A; private final ReflectConstructor CONSTRUCTOR; public static NMSTagConverter of(String nbtClassName) { return of(nbtClassName, null); } public static NMSTagConverter of(String nbtClassName, @Nullable Class parameterType) { Class[] parameterTypes = parameterType == null ? EMPTY_PARAMS : new Class[]{parameterType}; return new NMSTagConverter(nbtClassName, parameterTypes); } public static NMSTagConverter choice(String... nbtClassNames) { return choice(nbtClassNames, null); } public static NMSTagConverter choice(String[] nbtClassNames, @Nullable Class parameterType) { for (int i = nbtClassNames.length - 1; i >= 1; --i) { String nbtClassName = nbtClassNames[i]; Either, Exception> clazz = getNNTClass(nbtClassName); if (clazz.getLeft() != null) return of(nbtClassName, parameterType); } // Couldn't find one, we'll try the first one and return whatever the result is return of(nbtClassNames[0], parameterType); } private NMSTagConverter(String nbtClassName, Class[] parameterTypes) { this.clazz = getNNTClassOrError(nbtClassName); this.A = new ReflectMethod<>(this.clazz, this.clazz, "a", parameterTypes); this.CONSTRUCTOR = new ReflectConstructor<>(this.clazz, parameterTypes); } public Class getNBTClass() { return clazz; } public Object toNBT(Object... args) { if (A.isValid()) { return A.invoke(null, args); } else { return CONSTRUCTOR.newInstance(args); } } private static Either, Exception> getNNTClass(String nbtType) { try { if (ServerVersion.isAtLeast(ServerVersion.v1_17)) { return Either.left(Class.forName("net.minecraft.nbt." + nbtType)); } else { String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; return Either.left(Class.forName("net.minecraft.server." + version + "." + nbtType)); } } catch (Exception error) { return Either.right(error); } } private static Class getNNTClassOrError(String nbtType) { Either, Exception> clazz = getNNTClass(nbtType); if (clazz.getRight() != null) { Log.error(clazz.getRight(), "An unexpected error while loading nbt class ", nbtType, ":"); return null; } return clazz.getLeft(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java ================================================ package com.bgsoftware.superiorskyblock.tag; public abstract class NumberTag extends Tag { protected NumberTag(E value) { super(value); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java ================================================ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataTypeContext; import java.io.DataOutputStream; import java.io.IOException; public class PersistentDataTag extends Tag { private final PersistentDataTypeContext serializer; private PersistentDataTag(E value, PersistentDataTypeContext serializer) { super(value); this.serializer = serializer; } @Override protected void writeData(DataOutputStream os) throws IOException { byte[] data = serializer.serialize(value); os.writeInt(data.length); os.write(data); } public static PersistentDataTag of(E value, PersistentDataTypeContext serializer) { return new PersistentDataTag<>(value, serializer); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java ================================================ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataType; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataTypeContext; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; public class PersistentDataTagSerialized extends Tag { private static final PersistentDataTagSerialized EMPTY = new PersistentDataTagSerialized(new byte[0]); private PersistentDataTagSerialized(byte[] value) { super(value); } public PersistentDataTag getPersistentDataTag(PersistentDataType type) { PersistentDataTypeContext serializer = type.getContext(); if (serializer == null) throw new IllegalArgumentException("Cannot find a valid serializer for " + type); return PersistentDataTag.of(serializer.deserialize(value), serializer); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeInt(value.length); os.write(value); } public static PersistentDataTagSerialized of(byte[] value) { return value.length == 0 ? EMPTY : new PersistentDataTagSerialized(value); } public static PersistentDataTagSerialized fromStream(DataInputStream is) throws IOException { int length = is.readInt(); byte[] bytes = new byte[length]; is.readFully(bytes); return new PersistentDataTagSerialized(bytes); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; /** * The TAG_Short tag. * * @author Graham Edgecombe */ public class ShortTag extends NumberTag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagShort", "ShortTag"}, short.class); private static final ShortTag[] CACHE = new ShortTag[100]; private ShortTag(short value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeShort(value); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } public static ShortTag of(short value) { if (value >= 0 && value < CACHE.length) { ShortTag tag = CACHE[value]; if (tag == null) tag = CACHE[value] = new ShortTag(value); return tag; } else { return new ShortTag(value); } } public static ShortTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to ShortTag!"); try { short value = plugin.getNMSTags().getNBTShortValue(tag); return ShortTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag short from NMS:"); return null; } } public static ShortTag fromStream(DataInputStream is) throws IOException { return ShortTag.of(is.readShort()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; /** * The TAG_String tag. * * @author Graham Edgecombe */ public class StringTag extends Tag { /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( new String[]{"NBTTagString", "StringTag"}, String.class); private static final StringTag EMPTY = new StringTag(""); private StringTag(String value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { byte[] bytes = value.getBytes(StandardCharsets.UTF_8); os.writeShort(bytes.length); if (bytes.length > 0) os.write(bytes); } @Override protected NMSTagConverter getNMSConverter() { return TAG_CONVERTER; } public static StringTag of(String value) { return value.isEmpty() ? EMPTY : new StringTag(value); } public static StringTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to StringTag!"); try { String value = plugin.getNMSTags().getNBTStringValue(tag); return StringTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag string from NMS:"); return null; } } public static StringTag fromStream(DataInputStream is) throws IOException { int length = is.readShort(); if (length <= 0) return EMPTY; byte[] bytes = new byte[length]; is.readFully(bytes); return StringTag.of(new String(bytes, StandardCharsets.UTF_8)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java ================================================ /* * JNBT License Copyright (c) 2010 Graham Edgecombe All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the JNBT team nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Objects; /** * Represents a single NBT tag. * * @author Graham Edgecombe */ public abstract class Tag { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); protected final E value; protected Tag(E value) { this.value = value; } public static Tag fromNBT(Object tag) { if (tag.getClass().equals(ByteArrayTag.TAG_CONVERTER.getNBTClass())) return ByteArrayTag.fromNBT(tag); else if (tag.getClass().equals(ByteTag.TAG_CONVERTER.getNBTClass())) return ByteTag.fromNBT(tag); else if (tag.getClass().equals(CompoundTag.TAG_CONVERTER.getNBTClass())) return CompoundTag.fromNBT(tag); else if (tag.getClass().equals(DoubleTag.TAG_CONVERTER.getNBTClass())) return DoubleTag.fromNBT(tag); else if (tag.getClass().equals(EndTag.TAG_CONVERTER.getNBTClass())) return EndTag.of(); else if (tag.getClass().equals(FloatTag.TAG_CONVERTER.getNBTClass())) return FloatTag.fromNBT(tag); else if (tag.getClass().equals(IntArrayTag.TAG_CONVERTER.getNBTClass())) return IntArrayTag.fromNBT(tag); else if (tag.getClass().equals(IntTag.TAG_CONVERTER.getNBTClass())) return IntTag.fromNBT(tag); else if (tag.getClass().equals(ListTag.TAG_CONVERTER.getNBTClass())) return ListTag.fromNBT(tag); else if (tag.getClass().equals(LongTag.TAG_CONVERTER.getNBTClass())) return LongTag.fromNBT(tag); else if (tag.getClass().equals(ShortTag.TAG_CONVERTER.getNBTClass())) return ShortTag.fromNBT(tag); else if (tag.getClass().equals(StringTag.TAG_CONVERTER.getNBTClass())) return StringTag.fromNBT(tag); throw new IllegalArgumentException("Cannot convert " + tag.getClass() + " to Tag!"); } public static Tag fromStream(DataInputStream is, int depth) throws IOException { int type = is.readByte() & 0xFF; return fromStream(is, depth, type); } protected static Tag fromStream(DataInputStream is, int depth, int type) throws IOException { switch (type) { case NBTTags.TYPE_END: return EndTag.fromStream(is, depth); case NBTTags.TYPE_BYTE: return ByteTag.fromStream(is); case NBTTags.TYPE_SHORT: return ShortTag.fromStream(is); case NBTTags.TYPE_INT: return IntTag.fromStream(is); case NBTTags.TYPE_LONG: return LongTag.fromStream(is); case NBTTags.TYPE_FLOAT: return FloatTag.fromStream(is); case NBTTags.TYPE_DOUBLE: return DoubleTag.fromStream(is); case NBTTags.TYPE_BYTE_ARRAY: return ByteArrayTag.fromStream(is); case NBTTags.TYPE_STRING: return StringTag.fromStream(is); case NBTTags.TYPE_LIST: return ListTag.fromStream(is, depth); case NBTTags.TYPE_COMPOUND: return CompoundTag.fromStream(is, depth); case NBTTags.TYPE_INT_ARRAY: return IntArrayTag.fromStream(is); case NBTTags.TYPE_BIG_DECIMAL: return BigDecimalTag.fromStream(is); case NBTTags.TYPE_UUID: return UUIDTag.fromStream(is); case NBTTags.TYPE_PERSISTENT_DATA: return PersistentDataTagSerialized.fromStream(is); } throw new IllegalArgumentException("Invalid tag: " + type); } public E getValue() { return value; } @Override public String toString() { return NBTUtils.getTypeName(this.getClass()) + ": " + value; } public void write(DataOutputStream os) throws IOException { int type = NBTUtils.getTypeCode(this.getClass()); os.writeByte(type); if (type == NBTTags.TYPE_END) { throw new IOException("Named TAG_End not permitted."); } writeData(os); } protected abstract void writeData(DataOutputStream outputStream) throws IOException; @Nullable protected NMSTagConverter getNMSConverter() { return null; } public Object toNBT() { NMSTagConverter converter = getNMSConverter(); if (converter == null) throw new UnsupportedOperationException(); return Objects.requireNonNull(converter.toNBT(this.value)); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java ================================================ package com.bgsoftware.superiorskyblock.tag; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.UUID; public class UUIDTag extends Tag { private UUIDTag(UUID value) { super(value); } @Override protected void writeData(DataOutputStream os) throws IOException { os.writeLong(value.getMostSignificantBits()); os.writeLong(value.getLeastSignificantBits()); } public static UUIDTag of(long mostSigBits, long leastSigBits) { return new UUIDTag(new UUID(mostSigBits, leastSigBits)); } public static UUIDTag of(UUID value) { return new UUIDTag(value); } public static UUIDTag fromStream(DataInputStream is) throws IOException { return UUIDTag.of(is.readLong(), is.readLong()); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java ================================================ package com.bgsoftware.superiorskyblock.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import org.bukkit.Material; import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Hanging; import org.bukkit.entity.Horse; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Pig; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.entity.Tameable; import org.bukkit.entity.Vehicle; import org.bukkit.inventory.AbstractHorseInventory; import org.bukkit.inventory.HorseInventory; import org.bukkit.inventory.ItemStack; import org.bukkit.projectiles.ProjectileSource; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Optional; public class BukkitEntities { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Synchronized>> entityContent = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap()); @Nullable private static final EntityType NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, "NAUTILUS"); @Nullable private static final EntityType ZOMBIE_NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, "ZOMBIE_NAUTILUS"); private BukkitEntities() { } public static boolean isEquipment(LivingEntity livingEntity, ItemStack itemStack) { List entityEquipment = entityContent.writeAndGet(entityContent -> entityContent.computeIfAbsent(livingEntity.getEntityId(), u -> cacheEntityEquipmentInternal(livingEntity))); return entityEquipment.stream().anyMatch(equipmentItem -> equipmentItem != null && equipmentItem.getType() == itemStack.getType()); } public static void cacheEntityEquipment(LivingEntity livingEntity) { List entityEquipment = cacheEntityEquipmentInternal(livingEntity); entityContent.write(entityContent -> entityContent.put(livingEntity.getEntityId(), entityEquipment)); } private static List cacheEntityEquipmentInternal(LivingEntity livingEntity) { List entityEquipment = new LinkedList<>(Arrays.asList(plugin.getNMSEntities().getEquipment(livingEntity.getEquipment()))); if (livingEntity instanceof Pig) { if (((Pig) livingEntity).hasSaddle()) entityEquipment.add(new ItemStack(Material.SADDLE)); } else if (livingEntity instanceof Horse) { HorseInventory horseInventory = ((Horse) livingEntity).getInventory(); horseInventory.forEach(itemStack -> { if (itemStack != null) entityEquipment.add(itemStack); }); entityEquipment.add(new ItemStack(Material.CHEST)); if (horseInventory.getSaddle() != null) entityEquipment.add(horseInventory.getSaddle()); if (horseInventory.getArmor() != null) entityEquipment.add(horseInventory.getArmor()); } try { if (livingEntity instanceof AbstractHorse) { AbstractHorseInventory horseInventory = ((AbstractHorse) livingEntity).getInventory(); horseInventory.forEach(itemStack -> { if (itemStack != null) entityEquipment.add(itemStack); }); entityEquipment.add(new ItemStack(Material.CHEST)); if (horseInventory.getSaddle() != null) entityEquipment.add(horseInventory.getSaddle()); if (horseInventory instanceof HorseInventory && ((HorseInventory) horseInventory).getArmor() != null) entityEquipment.add(((HorseInventory) horseInventory).getArmor()); } } catch (Throwable ignored) { } return entityEquipment.isEmpty() ? Collections.emptyList() : entityEquipment; } public static void clearEntityEquipment(LivingEntity livingEntity) { entityContent.write(entityContent -> entityContent.remove(livingEntity.getEntityId())); } public static Optional getPlayerSource(Entity damager) { if (damager instanceof Projectile) { ProjectileSource shooter = ((Projectile) damager).getShooter(); if (shooter instanceof Player) return Optional.of((Player) shooter); } else if (damager instanceof Player) { return Optional.of((Player) damager); } return Optional.empty(); } public static Key getLimitEntityType(Entity entity) { // TODO - Is this really necessary? return Keys.of(entity.getType()); } public static boolean canHaveLimit(EntityType entityType) { Class entityClass = entityType.getEntityClass(); return (entityClass != null && (LivingEntity.class.isAssignableFrom(entityClass) || Hanging.class.isAssignableFrom(entityClass) || Vehicle.class.isAssignableFrom(entityClass))); } public static boolean canBypassEntityLimit(Entity entity) { return canBypassEntityLimit(entity, true); } public static boolean canBypassEntityLimit(Entity entity, boolean checkProviders) { if (entity instanceof ArmorStand && !((ArmorStand) entity).isVisible()) return true; if (checkProviders) { for (EntitiesProvider entitiesProvider : plugin.getProviders().getEntitiesProviders()) { if (!entitiesProvider.shouldTrackEntity(entity)) return true; } } return false; } public static boolean isTameable(Entity entity) { return entity instanceof Tameable && ((Tameable) entity).isTamed(); } public static boolean isHorse(Entity entity) { return entity instanceof Horse || (ServerVersion.isAtLeast(ServerVersion.v1_11) && entity instanceof org.bukkit.entity.AbstractHorse); } public static boolean isNautilus(EntityType entityType) { return entityType == NAUTILUS_TYPE || entityType == ZOMBIE_NAUTILUS_TYPE; } public static List getCategories(Entity entity) { List categories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity)); if (isTameable(entity)) { categories = new LinkedList<>(categories); categories.add(BuiltinEntityCategory.TAMEABLE.getEntityCategory()); } return categories; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java ================================================ package com.bgsoftware.superiorskyblock.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.SpawnEggMeta; import java.util.Map; public class BukkitItems { private static final ReflectMethod GET_HAND_BLOCK_PLACE = new ReflectMethod<>(BlockPlaceEvent.class, "getHand"); private static final ReflectMethod GET_HAND_PLAYER_INTERACT = new ReflectMethod<>(PlayerInteractEvent.class, "getHand"); private static final ReflectMethod GET_HAND_PLAYER_INTERACT_ENTITY = new ReflectMethod<>(PlayerInteractEntityEvent.class, "getHand"); private static final ReflectMethod GET_ITEM_IN_OFF_HAND = new ReflectMethod<>(PlayerInventory.class, "getItemInOffHand"); private static final ReflectMethod SET_ITEM_IN_OFF_HAND = new ReflectMethod<>(PlayerInventory.class, "setItemInOffHand", ItemStack.class); private static final Material END_CRYSTAL_ITEM_TYPE = EnumHelper.getEnum(Material.class, "END_CRYSTAL"); private BukkitItems() { } public static void removeHandItem(Player onlinePlayer, PlayerHand usedHand, int amount) { PlayerInventory playerInventory = onlinePlayer.getInventory(); if (usedHand == PlayerHand.MAIN_HAND) { ItemStack mainHand = playerInventory.getItemInHand(); if (mainHand != null) { mainHand.setAmount(mainHand.getAmount() - amount); playerInventory.setItemInHand(mainHand); } } else if (usedHand == PlayerHand.OFF_HAND) { ItemStack offHand = GET_ITEM_IN_OFF_HAND.invoke(playerInventory); if (offHand != null) { offHand.setAmount(offHand.getAmount() - amount); SET_ITEM_IN_OFF_HAND.invoke(playerInventory, offHand); } } } @Nullable public static PlayerHand getHand(Event event) { ReflectMethod reflectMethod; if (event instanceof BlockPlaceEvent) { reflectMethod = GET_HAND_BLOCK_PLACE; } else if (event instanceof PlayerInteractEvent) { reflectMethod = GET_HAND_PLAYER_INTERACT; } else if (event instanceof PlayerInteractEntityEvent) { reflectMethod = GET_HAND_PLAYER_INTERACT_ENTITY; } else { throw new IllegalArgumentException("Cannot get hand of event: " + event.getClass()); } EquipmentSlot equipmentSlot = reflectMethod.isValid() ? reflectMethod.invoke(event) : EquipmentSlot.HAND; return equipmentSlot == null ? null : PlayerHand.of(equipmentSlot); } @Nullable public static ItemStack getHandItem(Player onlinePlayer, @Nullable PlayerHand usedHand) { if (usedHand == null) { return null; } ItemStack handItem; if (usedHand == PlayerHand.OFF_HAND) { handItem = GET_ITEM_IN_OFF_HAND.invoke(onlinePlayer.getInventory()); } else { handItem = onlinePlayer.getItemInHand(); } return handItem == null || handItem.getType() == Material.AIR ? null : handItem; } public static void setHandItem(Player player, PlayerHand playerHand, @Nullable ItemStack itemStack) { if (playerHand == PlayerHand.MAIN_HAND) { player.getInventory().setItemInHand(itemStack == null ? new ItemStack(Material.AIR) : itemStack); } else if (playerHand == PlayerHand.OFF_HAND) { SET_ITEM_IN_OFF_HAND.invoke(player.getInventory(), itemStack == null ? new ItemStack(Material.AIR) : itemStack); } } @SuppressWarnings("deprecation") public static EntityType getEntityType(ItemStack itemStack) { if (!isValidAndSpawnEgg(itemStack)) { Material itemType = itemStack.getType(); if (itemType == Material.ARMOR_STAND) { return EntityType.ARMOR_STAND; } else if (itemType == END_CRYSTAL_ITEM_TYPE) { return EntityType.ENDER_CRYSTAL; } return EntityType.UNKNOWN; } if (ServerVersion.isLegacy()) { try { SpawnEggMeta spawnEggMeta = (SpawnEggMeta) itemStack.getItemMeta(); return spawnEggMeta.getSpawnedType() == null ? EntityType.PIG : spawnEggMeta.getSpawnedType(); } catch (NoClassDefFoundError error) { return EntityType.fromId(itemStack.getDurability()); } } else { return EntityType.fromName(itemStack.getType().name().replace("_SPAWN_EGG", "")); } } public static void addItem(ItemStack itemStack, PlayerInventory playerInventory, Location toDrop) { Map additionalItems = playerInventory.addItem(itemStack); for (ItemStack additionalItem : additionalItems.values()) toDrop.getWorld().dropItemNaturally(toDrop, additionalItem); } public static boolean isValidAndSpawnEgg(@Nullable ItemStack itemStack) { return itemStack != null && isValidAndSpawnEgg(itemStack.getType()); } public static boolean isValidAndSpawnEgg(Material itemType) { return !itemType.isBlock() && itemType.name().contains(ServerVersion.isLegacy() ? "MONSTER_EGG" : "SPAWN_EGG"); } public static boolean isInteractableItem(@Nullable ItemStack itemStack) { if (itemStack == null) return false; Material itemType = itemStack.getType(); return itemType == Material.ARMOR_STAND || isValidAndSpawnEgg(itemType); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/Dimensions.java ================================================ package com.bgsoftware.superiorskyblock.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import org.bukkit.World; import java.util.EnumMap; public class Dimensions { private static final EnumMap ENVIRONMENT_TO_DIMENSION = new EnumMap<>(World.Environment.class); public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, Dimensions::onSettingsUpdate); } private static void onSettingsUpdate() { ENVIRONMENT_TO_DIMENSION.clear(); for (Dimension dimension : Dimension.values()) { Dimension currentDimension = ENVIRONMENT_TO_DIMENSION.get(dimension.getEnvironment()); if (currentDimension == null || dimension.ordinal() < currentDimension.ordinal()) ENVIRONMENT_TO_DIMENSION.put(dimension.getEnvironment(), dimension); } } @Nullable public static Dimension fromEnvironment(World.Environment environment) { return ENVIRONMENT_TO_DIMENSION.get(environment); } private Dimensions() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java ================================================ package com.bgsoftware.superiorskyblock.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Preconditions; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import java.time.Duration; import java.util.Comparator; import java.util.LinkedList; import java.util.Objects; import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; public class EntityTeleports { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private EntityTeleports() { } public static void warmupTeleport(SuperiorPlayer superiorPlayer, long warmupInMillis, TeleportCallback teleportCallback) { if (warmupInMillis > 0 && !superiorPlayer.hasBypassModeEnabled() && !superiorPlayer.hasPermission("superior.admin.bypass.warmup")) { Message.TELEPORT_WARMUP.send(superiorPlayer, Formatters.TIME_FORMATTER.format( Duration.ofMillis(warmupInMillis), superiorPlayer.getUserLocale())); superiorPlayer.setTeleportTask(BukkitExecutor.sync(() -> teleportCallback.accept(true), warmupInMillis / 50)); } else { teleportCallback.accept(false); } } public static void teleport(Entity entity, Location location) { teleport(entity, location, null); } public static void teleport(Entity entity, Location location, @Nullable Consumer teleportResult) { Island island = plugin.getGrid().getIslandAt(location); if (island != null) { plugin.getProviders().getWorldsProvider().prepareTeleport(island, location.clone(), () -> teleportEntity(entity, location, teleportResult)); } else { teleportEntity(entity, location, teleportResult); } } public static void teleportUntilSuccess(Entity entity, Location location, long cooldown, @Nullable Runnable onFinish) { teleport(entity, location, succeed -> { if (!succeed) { if (cooldown > 0) { BukkitExecutor.sync(() -> teleportUntilSuccess(entity, location, cooldown, onFinish), cooldown); } else { teleportUntilSuccess(entity, location, cooldown, onFinish); } } else if (onFinish != null) { onFinish.run(); } }); } public static CompletableFuture findIslandSafeLocation(Island island, Dimension dimension) { CompletableFuture result = new CompletableFuture<>(); IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(result::completeExceptionally).ifLeft(world -> findIslandSafeLocation(island, dimension, result)); }); return result; } public static void findIslandSafeLocation(Island island, Dimension dimension, CompletableFuture result) { Location homeLocation = island.getIslandHome(dimension); Preconditions.checkNotNull(homeLocation, "Cannot find a suitable home location for island " + island.getUniqueId()); World islandsWorld = Objects.requireNonNull(plugin.getGrid().getIslandsWorld(island, dimension), "world is null"); float rotationYaw = homeLocation.getYaw(); float rotationPitch = homeLocation.getPitch(); Log.debug(Debug.FIND_SAFE_TELEPORT, island.getOwner().getName(), dimension.getName()); // We first check that the home location is safe. If it is, we can return. { Block homeLocationBlock = homeLocation.getBlock(); if (island.isSpawn() || WorldBlocks.isSafeBlock(homeLocationBlock)) { Log.debugResult(Debug.FIND_SAFE_TELEPORT, "Result Location", homeLocation); result.complete(homeLocation); return; } } // In case it is not safe anymore, we check in the same location if the highest block is safe. { Block teleportLocationHighestBlock = islandsWorld.getHighestBlockAt(homeLocation).getRelative(BlockFace.UP); if (WorldBlocks.isSafeBlock(teleportLocationHighestBlock)) { result.complete(adjustLocationToHome(island, teleportLocationHighestBlock, rotationYaw, rotationPitch)); return; } } // The teleport location is not safe. We check for a safe spot in the center of the island. Location islandCenterLocation = island.getCenter(dimension); if (!islandCenterLocation.equals(homeLocation)) { ChunksProvider.loadChunk(ChunkPosition.of(islandCenterLocation), ChunkLoadReason.FIND_SAFE_SPOT, chunk -> { { Block islandCenterBlock = islandCenterLocation.getBlock().getRelative(BlockFace.UP); if (WorldBlocks.isSafeBlock(islandCenterBlock)) { result.complete(adjustLocationToHome(island, islandCenterBlock, rotationYaw, rotationPitch)); return; } } // The center is not safe, we check in the same location if the highest block is safe. { Block islandCenterHighestBlock = islandsWorld.getHighestBlockAt(islandCenterLocation).getRelative(BlockFace.UP); if (WorldBlocks.isSafeBlock(islandCenterHighestBlock)) { result.complete(adjustLocationToHome(island, islandCenterHighestBlock, rotationYaw, rotationPitch)); return; } } // The center is not safe; we look for a new spot on the island. findNewSafeSpotOnIsland(island, islandsWorld, homeLocation, rotationYaw, rotationPitch, result); }); } else { findNewSafeSpotOnIsland(island, islandsWorld, homeLocation, rotationYaw, rotationPitch, result); } } private static void findNewSafeSpotOnIsland(Island island, World islandsWorld, Location homeLocation, float rotationYaw, float rotationPitch, CompletableFuture result) { LinkedList islandChunks = new LinkedList<>(IslandUtils.getChunkCoords(island, WorldInfo.of(islandsWorld), IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS)); try (ChunkPosition homeChunk = ChunkPosition.of(homeLocation)) { islandChunks.sort(Comparator.comparingInt(o -> o.distanceSquared(homeChunk))); } findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, safeSpot -> { if (safeSpot != null) { result.complete(adjustLocationToHome(island, safeSpot.getBlock(), rotationYaw, rotationPitch)); } else { result.complete(null); } }); } private static void findSafeSpotInChunk(Island island, Queue islandChunks, World islandsWorld, Location homeLocation, Consumer onResult) { ChunkPosition chunkPosition = islandChunks.poll(); if (chunkPosition == null) { onResult.accept(null); return; } ChunksProvider.loadChunk(chunkPosition, ChunkLoadReason.FIND_SAFE_SPOT, null).whenComplete((chunk, err) -> { ChunkSnapshot chunkSnapshot = chunk.getChunkSnapshot(); if (WorldBlocks.isChunkEmpty(island, chunkSnapshot)) { findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, onResult); return; } BukkitExecutor.createTask().runAsync(v -> { Location closestSafeSpot = null; double closestSafeSpotDistance = 0; int worldBuildLimit = islandsWorld.getMaxHeight() - 1; int worldMinLimit = plugin.getNMSWorld().getMinHeight(islandsWorld); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { int y = chunkSnapshot.getHighestBlockYAt(x, z); if (y < worldMinLimit || y + 2 > worldBuildLimit) continue; int worldX = chunkSnapshot.getX() * 16 + x; int worldZ = chunkSnapshot.getZ() * 16 + z; // In some versions, the ChunkSnapshot#getHighestBlockYAt seems to return // one block above the actual highest block. Therefore, the check is on the // returned block and the block below it. Location safeSpot; if (WorldBlocks.isSafeBlock(chunkSnapshot, x, y, z)) { safeSpot = new Location(islandsWorld, worldX, y, worldZ); } else if (WorldBlocks.isSafeBlock(chunkSnapshot, x, y - 1, z)) { safeSpot = new Location(islandsWorld, worldX, y - 1, worldZ); } else { continue; } double distanceFromHome = safeSpot.distanceSquared(homeLocation); if (closestSafeSpot == null || distanceFromHome < closestSafeSpotDistance) { closestSafeSpotDistance = distanceFromHome; closestSafeSpot = safeSpot; } } } return closestSafeSpot; }).runSync(location -> { if (location != null) { onResult.accept(location); } else { findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, onResult); } }); }); } private static void teleportEntity(Entity entity, Location location, @Nullable Consumer teleportResult) { entity.eject(); plugin.getProviders().getAsyncProvider().teleport(entity, location, teleportResult); } private static Location adjustLocationToHome(Island island, Block block, float yaw, float pitch) { Location newHomeLocation; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = block.getLocation(wrapper.getHandle()).add(0.5, 0, 0.5); location.setYaw(yaw); location.setPitch(pitch); PluginEvent event = PluginEventsFactory.callIslandSetHomeEvent( island, (SuperiorPlayer) null, location, IslandSetHomeEvent.Reason.SAFE_HOME); if (event.isCancelled()) { newHomeLocation = location; } else { newHomeLocation = event.getArgs().islandHome; island.setIslandHome(newHomeLocation); } } Log.debugResult(Debug.FIND_SAFE_TELEPORT, "Result Location", newHomeLocation); return newHomeLocation; } public interface TeleportCallback { void accept(boolean afterWarmup); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/GeneratorType.java ================================================ package com.bgsoftware.superiorskyblock.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; public enum GeneratorType { NORMAL(ConstantKeys.COBBLESTONE), BASALT(ConstantKeys.BASALT), NONE(null); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final BlockFace[] nearbyFaces = new BlockFace[]{ BlockFace.WEST, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.UP }; private static final Material BLUE_ICE_MATERIAL = EnumHelper.getEnum(Material.class, "BLUE_ICE"); private static final Material SOUL_SOIL_MATERIAL = EnumHelper.getEnum(Material.class, "SOUL_SOIL"); public static GeneratorType fromDimension(Dimension dimension) { return dimension.getEnvironment() == World.Environment.NETHER && ServerVersion.isAtLeast(ServerVersion.v1_16) ? BASALT : NORMAL; } public static GeneratorType detectGenerator(Block block) { if (ServerVersion.isAtLeast(ServerVersion.v1_16) && block.getWorld().getEnvironment() == World.Environment.NETHER) { for (BlockFace blockFace : nearbyFaces) { if (block.getRelative(blockFace).getType() == BLUE_ICE_MATERIAL && block.getRelative(BlockFace.DOWN).getType() == SOUL_SOIL_MATERIAL) return GeneratorType.BASALT; } } else { for (BlockFace blockFace : nearbyFaces) { if (plugin.getNMSWorld().isWaterLogged(block.getRelative(blockFace))) return GeneratorType.NORMAL; } } return GeneratorType.NONE; } @Nullable private final Key defaultBlock; GeneratorType(@Nullable Key defaultBlock) { this.defaultBlock = defaultBlock; } @Nullable public Key getDefaultBlock() { return defaultBlock; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/SignType.java ================================================ package com.bgsoftware.superiorskyblock.world; public enum SignType { STANDING_SIGN, WALL_SIGN, HANGING_WALL_SIGN, HANGING_SIGN, UNKNOWN } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java ================================================ package com.bgsoftware.superiorskyblock.world; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import org.bukkit.Bukkit; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; public class WorldBlocks { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private WorldBlocks() { } public static boolean isSafeBlock(Block block) { return isSafeBlockInternal(block) || isSafeBlockInternal(block.getRelative(BlockFace.DOWN)); } private static boolean isSafeBlockInternal(Block block) { // Checks that the block in the parameter is safe for teleportation. // This means that the block below it is considered "safe", and the two blocks above the safe blocks // cannot suffocate the player. return !canPlayerSuffocateFromBlock(block) && !canPlayerSuffocateFromBlock(block.getRelative(BlockFace.UP)) && plugin.getSettings().getSafeBlocks().contains(Keys.of(block.getRelative(BlockFace.DOWN))); } private static boolean canPlayerSuffocateFromBlock(Block block) { return canPlayerGetHurtFromBlock(block.getType()) || plugin.getNMSWorld().canPlayerSuffocate(block); } public static boolean isSafeBlock(ChunkSnapshot chunkSnapshot, int x, int y, int z) { return isSafeBlockInternal(chunkSnapshot, x, y, z) || isSafeBlockInternal(chunkSnapshot, x, y - 1, z); } private static boolean isSafeBlockInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { // Checks that the block in the parameter is safe for teleportation. // This means that the block below it is considered "safe", and the two blocks above the safe blocks // cannot suffocate the player. return !canPlayerSuffocateFromBlock(chunkSnapshot, x, y, z) && !canPlayerSuffocateFromBlock(chunkSnapshot, x, y + 1, z) && plugin.getSettings().getSafeBlocks().contains(plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y - 1, z)); } private static boolean canPlayerSuffocateFromBlock(ChunkSnapshot chunkSnapshot, int x, int y, int z) { if (plugin.getNMSWorld().canPlayerSuffocate(chunkSnapshot, x, y, z)) return true; Key blockKey = plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y, z); return blockKey != null && canPlayerGetHurtFromBlock(((MaterialKey) blockKey).getMaterial()); } private static boolean canPlayerGetHurtFromBlock(Material material) { return material == Material.LAVA || material == Material.FIRE; } public static boolean isChunkEmpty(Island island, ChunkSnapshot chunkSnapshot) { for (int i = 0; i < 16; i++) { if (!chunkSnapshot.isSectionEmpty(i)) { return false; } } island.markChunkEmpty(Bukkit.getWorld(chunkSnapshot.getWorldName()), chunkSnapshot.getX(), chunkSnapshot.getZ(), true); return true; } public static Location getChunkBlock(ChunkPosition chunkPosition, int x, int y, int z) { int realWorldChunkX = chunkPosition.getX() << 4; int realWorldChunkZ = chunkPosition.getZ() << 4; return new LazyWorldLocation(chunkPosition.getWorldName(), realWorldChunkX + x, y, realWorldChunkZ + z, 0, 0); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/WorldGenerator.java ================================================ package com.bgsoftware.superiorskyblock.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.io.FileClassLoader; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.io.JarFiles; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import org.bukkit.generator.ChunkGenerator; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; import java.lang.reflect.Constructor; import java.util.List; public class WorldGenerator { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final EnumerateMap defaultWorldGenerators = new EnumerateMap<>(Dimension.values()); @Nullable private static ChunkGenerator customWorldGenerator; private static boolean loadedCustomWorldGenerator = false; public static ChunkGenerator getWorldGenerator(Dimension dimension) { if (!loadedCustomWorldGenerator && customWorldGenerator == null) customWorldGenerator = loadGeneratorFromFile(); if (customWorldGenerator != null) return customWorldGenerator; return defaultWorldGenerators.computeIfAbsent(dimension, d -> plugin.getNMSWorld().createGenerator(d)); } @Nullable private static ChunkGenerator loadGeneratorFromFile() { if (loadedCustomWorldGenerator) return null; loadedCustomWorldGenerator = true; File generatorFolder = new File(plugin.getDataFolder(), "world-generator"); if (!generatorFolder.isDirectory()) { generatorFolder.delete(); } if (!generatorFolder.exists()) { generatorFolder.mkdirs(); return null; } List generatorsFiles = Files.listFolderFiles(generatorFolder, false, f -> f.getName().endsWith(".jar")); if (generatorsFiles.isEmpty()) return null; try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(generatorFolder)) { for (File file : generatorsFiles) { String fileName = file.getName(); file = filesLookup.getFile(fileName); FileClassLoader classLoader = new FileClassLoader(file, plugin.getPluginClassLoader(), plugin.getNMSAlgorithms().getClassProcessor()); //noinspection deprecation Class generatorClass = JarFiles.getClass(file.toURL(), ChunkGenerator.class, classLoader).getLeft(); if (generatorClass != null) { for (Constructor constructor : generatorClass.getConstructors()) { if (constructor.getParameterCount() == 0) { return (ChunkGenerator) generatorClass.newInstance(); } else if (constructor.getParameterTypes()[0].equals(JavaPlugin.class) || constructor.getParameterTypes()[0].equals(SuperiorSkyblock.class)) { return (ChunkGenerator) constructor.newInstance(plugin); } } } } } catch (Exception error) { Log.error(error, "An unexpected error occurred while loading the generator:"); } return null; } private WorldGenerator() { } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/WorldReader.java ================================================ package com.bgsoftware.superiorskyblock.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import org.bukkit.World; import java.util.HashMap; import java.util.Map; public class WorldReader { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final World world; private final ChunkLoadReason chunkLoadReason; private final CompletableFutureList chunkReaderFutures = new CompletableFutureList<>(-1L); private final Map cachedChunkReaders = new HashMap<>(); private boolean finishCalled = false; private boolean inFinishCallback = false; public WorldReader(World world, ChunkLoadReason chunkLoadReason) { this.world = world; this.chunkLoadReason = chunkLoadReason; } public void prepareChunk(ChunkPosition chunkPosition) { if (this.finishCalled) throw new IllegalStateException("Cannot call WorldReader#prepareChunk after WorldReader#finish was called"); chunkReaderFutures.add(ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null) .thenApply(chunk -> plugin.getNMSWorld().createChunkReader(chunk))); } @Nullable public ChunkReader getChunkReader(int blockX, int blockZ) { if (!this.inFinishCallback) throw new IllegalStateException("Cannot call WorldReader#getChunkReader from this state"); int chunkX = blockX >> 4; int chunkZ = blockZ >> 4; try (ChunkPosition chunkPosition = ChunkPosition.of(this.world, chunkX, chunkZ)) { return this.cachedChunkReaders.get(chunkPosition); } } public void finish(Runnable onFinish) { this.finishCalled = true; BukkitExecutor.async(() -> { MutableBoolean failed = new MutableBoolean(false); chunkReaderFutures.forEachCompleted(chunkReader -> { ChunkPosition chunkPosition = ChunkPosition.of(world, chunkReader.getX(), chunkReader.getZ(), false); cachedChunkReaders.put(chunkPosition, chunkReader); }, error -> { failed.set(true); Log.error(error, "An error occurred while waiting for chunks to load:"); }); if (!failed.get()) { try { this.inFinishCallback = true; onFinish.run(); } finally { this.inFinishCallback = true; } } }); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java ================================================ package com.bgsoftware.superiorskyblock.world.chunk; public enum ChunkLoadReason { SCHEMATIC_PLACE, SCHEMATIC_SAVE, ENTITY_TELEPORT, BLOCKS_RECALCULATE, ENTITIES_RECALCULATE, FIND_SAFE_SPOT, API_REQUEST, BIOME_REQUEST, WARP_SIGN_BREAK, SET_BIOME, DELETE_CHUNK } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java ================================================ package com.bgsoftware.superiorskyblock.world.chunk; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.executors.IWorker; import com.bgsoftware.common.executors.WorkerExecutor; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.Chunk; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; public class ChunksProvider { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final WorkerExecutor chunksExecutor = new WorkerExecutor(10); private static final Map pendingRequests = new ConcurrentHashMap<>(); private static boolean stopped = false; private ChunksProvider() { } public static CompletableFuture loadChunk(ChunkPosition chunkPosition, ChunkLoadReason chunkLoadReason, @Nullable Consumer onLoadConsumer) { try { return loadChunkInternal(chunkPosition, chunkLoadReason, onLoadConsumer); } finally { chunkPosition.release(); } } private static CompletableFuture loadChunkInternal(ChunkPosition chunkPosition, ChunkLoadReason chunkLoadReason, @Nullable Consumer onLoadConsumer) { if (stopped) return new CompletableFuture<>(); Log.debug(Debug.LOAD_CHUNK, chunkPosition, chunkLoadReason); Chunk loadedChunk = ChunkPosition.getLoadedChunk(chunkPosition).orElse(null); if (loadedChunk != null) { processPendingChunkLoadRequest(loadedChunk, chunkPosition); if (onLoadConsumer != null) onLoadConsumer.accept(loadedChunk); return CompletableFuture.completedFuture(loadedChunk); } PendingChunkLoadRequest pendingRequest = pendingRequests.get(chunkPosition); if (pendingRequest != null) { if (onLoadConsumer != null) pendingRequest.callbacks.add(onLoadConsumer); return pendingRequest.completableFuture; } else { CompletableFuture completableFuture = new CompletableFuture<>(); Set> chunkConsumers = new HashSet<>(); if (onLoadConsumer != null) chunkConsumers.add(onLoadConsumer); // Copy pool resource ChunkPosition clonedChunkPos = chunkPosition.copy(); pendingRequests.put(clonedChunkPos, new PendingChunkLoadRequest(completableFuture, chunkConsumers)); BukkitExecutor.ensureMain(() -> { chunksExecutor.addWorker(new ChunkLoadWorker(clonedChunkPos, chunkLoadReason)); if (!chunksExecutor.isRunning()) start(); }); return completableFuture; } } public static void stop() { stopped = true; if (chunksExecutor.isRunning()) chunksExecutor.stop(); } public static void start() { chunksExecutor.start(plugin); } private static class ChunkLoadWorker implements IWorker { private final ChunkPosition chunkPosition; private final ChunkLoadReason chunkLoadReason; public ChunkLoadWorker(ChunkPosition chunkPosition, ChunkLoadReason chunkLoadReason) { this.chunkPosition = chunkPosition; this.chunkLoadReason = chunkLoadReason; } @Override public void work() { if (stopped) return; long profiler = Profiler.start(ProfileType.LOAD_CHUNK); Log.debug(Debug.LOAD_CHUNK, chunkPosition, chunkLoadReason); plugin.getProviders().getChunksProvider().loadChunk(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ()).whenComplete((chunk, error) -> { if (error != null) { Log.entering("ENTER", chunkPosition, chunkLoadReason); Log.error(error, "An unexpected error occurred while loading chunk:"); error.printStackTrace(); } try { finishLoad(chunk, profiler); } catch (Exception error2) { Log.entering("ENTER", chunkPosition, chunkLoadReason); Log.error(error2, "An unexpected error occurred while finishing chunk loading:"); } }); } private void finishLoad(Chunk chunk, long profiler) { Profiler.end(profiler); Log.debug(Debug.LOAD_CHUNK, chunkPosition, chunkLoadReason); processPendingChunkLoadRequest(chunk, chunkPosition); } } private static void processPendingChunkLoadRequest(Chunk chunk, ChunkPosition chunkPosition) { PendingChunkLoadRequest pendingRequest = pendingRequests.remove(chunkPosition); if (pendingRequest == null) return; pendingRequest.callbacks.forEach(chunkConsumer -> chunkConsumer.accept(chunk)); pendingRequest.completableFuture.complete(chunk); } private static class PendingChunkLoadRequest { private final CompletableFuture completableFuture; private final Set> callbacks; public PendingChunkLoadRequest(CompletableFuture completableFuture, Set> callbacks) { this.completableFuture = completableFuture; this.callbacks = callbacks; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/entity/BuiltinEntityCategory.java ================================================ package com.bgsoftware.superiorskyblock.world.entity; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import org.bukkit.entity.Ambient; import org.bukkit.entity.Creature; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Flying; import org.bukkit.entity.Monster; import org.bukkit.entity.Slime; import org.bukkit.entity.Tameable; import org.bukkit.entity.Vehicle; import java.lang.ref.WeakReference; import java.util.Objects; public enum BuiltinEntityCategory { TAMEABLE { @Override protected boolean isEntityListedInternal(Class entityClass) { return Tameable.class.isAssignableFrom(entityClass); } }, VEHICLE { @Override protected boolean isEntityListedInternal(Class entityClass) { return Vehicle.class.isAssignableFrom(entityClass) && !Creature.class.isAssignableFrom(entityClass); } }, MONSTER { @Override protected boolean isEntityListedInternal(Class entityClass) { return Monster.class.isAssignableFrom(entityClass) || Slime.class.isAssignableFrom(entityClass) || Flying.class.isAssignableFrom(entityClass) || entityClass == HOGLIN_CLASS || entityClass == SKELETON_HORSE_CLASS || entityClass == ZOMBIE_HORSE_CLASS || entityClass == ZOMBIE_NAUTILUS_CLASS; } }, ANIMAL { @Override protected boolean isEntityListedInternal(Class entityClass) { return !BuiltinEntityCategory.MONSTER.isEntityListedInternal(entityClass) && (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass)); } }; @Nullable private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); @Nullable private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); @Nullable private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); @Nullable private static final Class ZOMBIE_NAUTILUS_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieNautilus"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final KeySet entities = getEntitiesInternal(); private WeakReference entityCategoryReference; public KeySet getEntities() { return entities; } @NotNull public EntityCategory getEntityCategory() { if (this.entityCategoryReference == null) { EntityCategory entityCategory = plugin.getSettings().getEntityCategoriesMap().getCategoryByName(name()); this.entityCategoryReference = new WeakReference<>(entityCategory); return Objects.requireNonNull(entityCategory); } EntityCategory entityCategory = this.entityCategoryReference.get(); if (entityCategory == null) { entityCategory = plugin.getSettings().getEntityCategoriesMap().getCategoryByName(name()); this.entityCategoryReference = new WeakReference<>(entityCategory); } return Objects.requireNonNull(entityCategory); } private KeySet getEntitiesInternal() { KeySet entities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); for (EntityType entityType : EntityType.values()) { Class entityClass = entityType.getEntityClass(); if (entityClass != null && isEntityListedInternal(entityClass)) { entities.add(Keys.of(entityType)); } } return entities.isEmpty() ? KeySets.createEmptySet() : KeySets.unmodifiableKeySet(entities); } protected boolean isEntityListedInternal(Class entityClass) { throw new UnsupportedOperationException(); } @Nullable private static Class getEntityTypeClass(String clazz) { try { return Class.forName(clazz); } catch (ClassNotFoundException error) { return null; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategoryImpl.java ================================================ package com.bgsoftware.superiorskyblock.world.entity; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import java.util.HashSet; public class EntityCategoryImpl implements EntityCategory { private final String name; private final KeySet entities; @Nullable private final IslandPrivilege spawnPrivilege; @Nullable private final IslandPrivilege damagePrivilege; @Nullable private final IslandPrivilege interactPrivilege; @Nullable private final IslandFlag spawnerSpawnFlag; @Nullable private final IslandFlag naturalSpawnFlag; public EntityCategoryImpl(String name, KeySet entities, @Nullable IslandPrivilege spawnPrivilege, @Nullable IslandPrivilege damagePrivilege, @Nullable IslandPrivilege interactPrivilege, @Nullable IslandFlag spawnerSpawnFlag, @Nullable IslandFlag naturalSpawnFlag) { this.name = name; this.entities = KeySets.unmodifiableKeySet(entities); this.spawnPrivilege = spawnPrivilege; this.damagePrivilege = damagePrivilege; this.interactPrivilege = interactPrivilege; this.spawnerSpawnFlag = spawnerSpawnFlag; this.naturalSpawnFlag = naturalSpawnFlag; } @Override public String getName() { return this.name; } @Override public KeySet getEntities() { return this.entities; } @Override public IslandPrivilege getSpawnPrivilege() { return this.spawnPrivilege; } @Override public IslandPrivilege getDamagePrivilege() { return this.damagePrivilege; } @Override public IslandPrivilege getInteractPrivilege() { return this.interactPrivilege; } @Override public IslandFlag getSpawnerSpawningIslandFlag() { return this.spawnerSpawnFlag; } @Override public IslandFlag getNaturalSpawningIslandFlag() { return this.naturalSpawnFlag; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/generator/IslandsGenerator.java ================================================ package com.bgsoftware.superiorskyblock.world.generator; import org.bukkit.generator.ChunkGenerator; public abstract class IslandsGenerator extends ChunkGenerator { } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import org.bukkit.Location; import java.util.Collections; import java.util.List; import java.util.Map; public abstract class BaseSchematic implements Schematic { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); protected final String name; protected final KeyMap cachedCounts; protected BaseSchematic(String name) { this(name, KeyMaps.createArrayMap(KeyIndicator.MATERIAL)); } protected BaseSchematic(String name, KeyMap cachedCounts) { this.name = name; this.cachedCounts = cachedCounts; } @Override public String getName() { return name; } @Override public Map getBlockCounts() { return Collections.unmodifiableMap(cachedCounts); } @Override public void pasteSchematic(Island island, Location location, Runnable callback) { pasteSchematic(island, location, callback, null); } public abstract List getAffectedChunks(); @Nullable public abstract Runnable onTeleportCallback(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.schematic.SchematicEntityFilter; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.EntityType; @SuppressWarnings("UnusedReturnValue") public class SchematicBuilder { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final CompoundTag compoundTag = CompoundTag.of(); public SchematicBuilder withBlockOffset(BlockOffset blockOffset) { this.compoundTag.setString("blockPosition", Serializers.OFFSET_SERIALIZER.serialize(blockOffset)); return this; } public SchematicBuilder withBlockType(Material blockType, int data) { if (ServerVersion.isLegacy()) { this.compoundTag.setInt("combinedId", plugin.getNMSAlgorithms().getCombinedId(blockType, (byte) data)); } else { this.compoundTag.setString("type", blockType.name()); if (data != 0) this.compoundTag.setInt("data", data); } return this; } public SchematicBuilder withLightLevels(byte[] lightLevels) { if (lightLevels.length > 0 && lightLevels[0] > 0) this.compoundTag.setByte("skyLightLevel", lightLevels[0]); if (lightLevels.length > 1 && lightLevels[1] > 0) this.compoundTag.setByte("blockLightLevel", lightLevels[1]); return this; } public SchematicBuilder withStates(CompoundTag statesTag) { if (statesTag != null) this.compoundTag.setTag("states", statesTag); return this; } public SchematicBuilder withTileEntity(CompoundTag tileEntity) { if (tileEntity != null) this.compoundTag.setTag("tileEntity", tileEntity); return this; } public SchematicBuilder applyEntity(EntityType entityType, CompoundTag entityTag, Location offset) { this.compoundTag.setString("offset", Serializers.LOCATION_SERIALIZER.serialize(offset)); this.compoundTag.setString("entityType", entityType.name()); this.compoundTag.setTag("NBT", SchematicEntityFilter.filterNBTTag(entityTag)); return this; } public CompoundTag build() { return this.compoundTag; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.SchematicManager; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParseException; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.io.Resources; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.FloatTag; import com.bgsoftware.superiorskyblock.tag.IntTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.WorldReader; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.schematic.container.SchematicsContainer; import com.bgsoftware.superiorskyblock.world.schematic.impl.CachedSuperiorSchematic; import com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic; import com.bgsoftware.superiorskyblock.world.schematic.parser.DefaultSchematicParser; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; public class SchematicsManagerImpl extends Manager implements SchematicManager { private final SchematicsContainer schematicsContainer; public SchematicsManagerImpl(SuperiorSkyblockPlugin plugin, SchematicsContainer schematicsContainer) { super(plugin); this.schematicsContainer = schematicsContainer; } public void loadData() throws ManagerLoadException { File schematicsFolder = new File(plugin.getDataFolder(), "schematics"); if (!schematicsFolder.exists()) { schematicsFolder.mkdirs(); Resources.saveResource("schematics/desert.schematic"); Resources.saveResource("schematics/desert_nether.schematic", "schematics/normal_nether.schematic"); Resources.saveResource("schematics/desert_the_end.schematic", "schematics/normal_the_end.schematic"); Resources.saveResource("schematics/mycel.schematic"); Resources.saveResource("schematics/mycel_nether.schematic", "schematics/normal_nether.schematic"); Resources.saveResource("schematics/mycel_the_end.schematic", "schematics/normal_the_end.schematic"); Resources.saveResource("schematics/normal.schematic"); Resources.saveResource("schematics/normal_nether.schematic"); Resources.saveResource("schematics/normal_the_end.schematic"); } loadDefaultSchematicParsers(); loadSchematics(); } public void loadSchematics() throws ManagerLoadException { this.schematicsContainer.clearSchematics(); File schematicsFolder = new File(plugin.getDataFolder(), "schematics"); List schematicFilesList = Files.listFolderFiles(schematicsFolder, false); if (!schematicFilesList.isEmpty()) { int schematicFilesCount = schematicFilesList.size(); List loadedSchematics = Collections.synchronizedList(new LinkedList<>()); CountDownLatch latch = new CountDownLatch(schematicFilesCount); int threadCount = Math.min(schematicFilesCount, Runtime.getRuntime().availableProcessors() * 2); ExecutorService loadService = Executors.newFixedThreadPool(threadCount, new ThreadFactoryBuilder().setNameFormat("SuperiorSkyblock Load Schematic Worker #%d").build()); Log.info("Loading " + schematicFilesCount + " schematics using " + threadCount + " threads..."); try { for (File schemFile : schematicFilesList) { loadService.submit(() -> { String schemName = Files.getFileName(schemFile).toLowerCase(Locale.ENGLISH); try { Schematic schematic = loadFromFile(schemName, schemFile); if (schematic != null) { loadedSchematics.add(schematic); } } catch (Throwable error) { Log.error(error, "An unexpected error occurred while loading schematic " + schemName); } finally { latch.countDown(); long remaining = latch.getCount(); if (remaining > 0 && remaining % 50 == 0) { Log.info("Schematic loading progress: " + (schematicFilesCount - remaining) + "/" + schematicFilesCount); } } }); } latch.await(); loadService.shutdown(); Log.info("Successfully loaded " + loadedSchematics.size() + " schematics."); for (Schematic schematic : loadedSchematics) { this.schematicsContainer.addSchematic(schematic); } } catch (InterruptedException e) { Log.error("Schematic loading thread was interrupted."); loadService.shutdownNow(); Thread.currentThread().interrupt(); } } if (this.schematicsContainer.getSchematics().isEmpty()) { throw new ManagerLoadException("&cThere were no valid schematics.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } // Force garbage collection to release file handles on Windows System.gc(); } public void cacheSchematics() { if (!plugin.getSettings().isCacheSchematics() || plugin.getSettings().getMaxIslandSize() % 4 != 0 || true) return; List newSchematics = new LinkedList<>(); boolean cachedSchematic = false; for (Schematic schematic : this.schematicsContainer.getSchematics().values()) { if (schematic instanceof SuperiorSchematic) { try { schematic = new CachedSuperiorSchematic((SuperiorSchematic) schematic); cachedSchematic = true; } catch (Throwable error) { Log.warn("Cannot cache schematic ", schematic.getName(), ", skipping..."); } } newSchematics.add(schematic); } if (!cachedSchematic) return; this.schematicsContainer.clearSchematics(); newSchematics.forEach(this.schematicsContainer::addSchematic); } private void loadDefaultSchematicParsers() { if (Bukkit.getPluginManager().isPluginEnabled("FastAsyncWorldEdit")) { try { Class.forName("com.boydti.fawe.object.schematic.Schematic"); SchematicParser schematicParser = (SchematicParser) Class.forName("com.bgsoftware.superiorskyblock.world.schematic.parser.FAWESchematicParser").newInstance(); this.schematicsContainer.addSchematicParser(schematicParser); } catch (Exception ignored) { } } } @Override public Schematic getSchematic(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); return this.schematicsContainer.getSchematic(name); } @Override public List getSchematics() { return new SequentialListBuilder() .build(this.schematicsContainer.getSchematics().keySet()); } @Override public void registerSchematicParser(SchematicParser schematicParser) { Preconditions.checkNotNull(schematicParser, "schematicParser parameter cannot be null."); this.schematicsContainer.addSchematicParser(schematicParser); } @Override public List getSchematicParsers() { return this.schematicsContainer.getSchematicParsers(); } @Override public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName) { saveSchematic(superiorPlayer, schematicName, false); } @Override public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName, boolean saveAir) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkArgument(superiorPlayer.isOnline(), "superiorPlayer must be online."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); BlockPosition pos1 = superiorPlayer.getSchematicPos1(); BlockPosition pos2 = superiorPlayer.getSchematicPos2(); Location offset; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { offset = superiorPlayer.getLocation(wrapper.getHandle()).subtract( Math.min(pos1.getX(), pos2.getX()), Math.min(pos1.getY(), pos2.getY()) + 1, Math.min(pos1.getZ(), pos2.getZ()) ); } SchematicOptions schematicOptions = SchematicOptions.newBuilder(schematicName) .setOffset(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ()) .setDirection(offset.getYaw(), offset.getPitch()) .setSaveAir(saveAir) .build(); World world = offset.getWorld(); saveSchematic(pos1.toLocation(world), pos2.toLocation(world), schematicOptions, () -> Message.SCHEMATIC_SAVED.send(superiorPlayer)); superiorPlayer.setSchematicPos1(null); superiorPlayer.setSchematicPos2(null); } @Override public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, String schematicName) { Preconditions.checkNotNull(pos1, "pos1 parameter cannot be null."); Preconditions.checkNotNull(pos2, "pos2 parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); saveSchematic(pos1, pos2, offsetX, offsetY, offsetZ, 0, 0, schematicName); } @Override public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, String schematicName) { Preconditions.checkNotNull(pos1, "pos1 parameter cannot be null."); Preconditions.checkNotNull(pos2, "pos2 parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); saveSchematic(pos1, pos2, offsetX, offsetY, offsetZ, yaw, pitch, schematicName, null); } @Override public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, String schematicName, Runnable callable) { Preconditions.checkNotNull(pos1, "pos1 parameter cannot be null."); Preconditions.checkNotNull(pos2, "pos2 parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); saveSchematic(pos1, pos2, offsetX, offsetY, offsetZ, 0, 0, schematicName, callable); } @Override public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, String schematicName, @Nullable Runnable callable) { Preconditions.checkNotNull(pos1, "pos1 parameter cannot be null."); Preconditions.checkNotNull(pos2, "pos2 parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); SchematicOptions schematicOptions = SchematicOptions.newBuilder(schematicName) .setOffset(offsetX, offsetY, offsetZ) .setDirection(yaw, pitch) .build(); saveSchematic(pos1, pos2, schematicOptions, callable); } @Override public void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions) { saveSchematic(pos1, pos2, schematicOptions, null); } @Override public void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions, @Nullable Runnable callable) { Preconditions.checkNotNull(pos1, "pos1 parameter cannot be null."); Preconditions.checkNotNull(pos2, "pos2 parameter cannot be null."); Preconditions.checkNotNull(schematicOptions, "schematicOptions parameter cannot be null."); Log.debug(Debug.SAVE_SCHEMATIC, pos1, pos2, schematicOptions.getOffsetX(), schematicOptions.getOffsetY(), schematicOptions.getOffsetZ(), schematicOptions.getYaw(), schematicOptions.getPitch(), schematicOptions.shouldSaveAir(), schematicOptions.getSchematicName()); World world = pos1.getWorld(); int minBlockX = Math.min(pos1.getBlockX(), pos2.getBlockX()); int minBlockY = Math.min(pos1.getBlockY(), pos2.getBlockY()); int minBlockZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); int maxBlockX = Math.max(pos1.getBlockX(), pos2.getBlockX()); int maxBlockY = Math.max(pos1.getBlockY(), pos2.getBlockY()); int maxBlockZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); int xSize = maxBlockX - minBlockX; int ySize = maxBlockY - minBlockY; int zSize = maxBlockZ - minBlockZ; WorldReader worldReader = new WorldReader(world, ChunkLoadReason.SCHEMATIC_SAVE); int minChunkX = minBlockX >> 4; int minChunkZ = minBlockZ >> 4; int maxChunkX = maxBlockX >> 4; int maxChunkZ = maxBlockZ >> 4; for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { worldReader.prepareChunk(ChunkPosition.of(world, chunkX, chunkZ)); } } worldReader.finish(() -> { List> entities = new ArrayList<>(); List> blocks = new ArrayList<>(); for (int x = minBlockX; x <= maxBlockX; ++x) { for (int z = minBlockZ; z <= maxBlockZ; ++z) { ChunkReader chunkReader = worldReader.getChunkReader(x, z); int offsetBlockX = x - minBlockX; int offsetBlockZ = z - minBlockZ; int chunkBlockX = x & 0xF; int chunkBlockZ = z & 0xF; for (int chunkBlockY = minBlockY; chunkBlockY <= maxBlockY; ++chunkBlockY) { Material blockType = chunkReader.getType(chunkBlockX, chunkBlockY, chunkBlockZ); if (!schematicOptions.shouldSaveAir() && blockType == Material.AIR) continue; short blockData = chunkReader.getData(chunkBlockX, chunkBlockY, chunkBlockZ); CompoundTag blockStates = chunkReader.readBlockStates(chunkBlockX, chunkBlockY, chunkBlockZ); byte[] lightLevels = chunkReader.getLightLevels(chunkBlockX, chunkBlockY, chunkBlockZ); CompoundTag tileEntity = chunkReader.getTileEntity(chunkBlockX, chunkBlockY, chunkBlockZ); int offsetBlockY = chunkBlockY - minBlockY; blocks.add(new SchematicBuilder() .withBlockOffset(SBlockOffset.fromOffsets(offsetBlockX, offsetBlockY, offsetBlockZ)) .withBlockType(blockType, blockData) .withStates(blockStates) .withLightLevels(lightLevels) .withTileEntity(tileEntity) .build() ); } } } for (int x = minChunkX; x <= maxChunkX; ++x) { for (int z = minChunkZ; z <= maxChunkZ; ++z) { ChunkReader chunkReader = worldReader.getChunkReader(x << 4, z << 4); if (chunkReader != null) { chunkReader.forEachEntity((entityType, entityTag, location) -> { if (entityType != EntityType.PLAYER && location.getBlockX() >= minBlockX && location.getBlockX() <= maxBlockX && location.getBlockY() >= minBlockY && location.getBlockY() <= maxBlockY && location.getBlockZ() >= minBlockZ && location.getBlockZ() <= maxBlockZ) { location.subtract(minBlockX, minBlockY, minBlockZ); entities.add(new SchematicBuilder().applyEntity(entityType, entityTag, location).build()); } }); } } } Map> compoundValue = new HashMap<>(); compoundValue.put("xSize", IntTag.of(xSize)); compoundValue.put("ySize", IntTag.of(ySize)); compoundValue.put("zSize", IntTag.of(zSize)); compoundValue.put("blocks", ListTag.of(blocks, CompoundTag.class)); compoundValue.put("entities", ListTag.of(entities, CompoundTag.class)); compoundValue.put("offsetX", IntTag.of(schematicOptions.getOffsetX())); compoundValue.put("offsetY", IntTag.of(schematicOptions.getOffsetY())); compoundValue.put("offsetZ", IntTag.of(schematicOptions.getOffsetZ())); compoundValue.put("yaw", FloatTag.of(schematicOptions.getYaw())); compoundValue.put("pitch", FloatTag.of(schematicOptions.getPitch())); compoundValue.put("version", StringTag.of(ServerVersion.getBukkitVersion())); if (!ServerVersion.isLegacy()) compoundValue.put("minecraftDataVersion", IntTag.of(plugin.getNMSAlgorithms().getDataVersion())); CompoundTag schematicTag = CompoundTag.of(compoundValue); SuperiorSchematic schematic = new SuperiorSchematic(schematicOptions.getSchematicName(), schematicTag); this.schematicsContainer.addSchematic(schematic); saveIntoFile(schematicOptions.getSchematicName(), schematicTag); if (callable != null) BukkitExecutor.sync(callable); }); } public String getDefaultSchematic(Dimension dimension) { String suffix = "_" + dimension.getName().toLowerCase(Locale.ENGLISH); for (String schematicName : this.schematicsContainer.getSchematics().keySet()) { if (getSchematic(schematicName + suffix) != null) return schematicName; } return ""; } private Schematic parseSchematic(File file, String schemName, SchematicParser schematicParser, Consumer onSchematicParseError) { try (DataInputStream reader = new DataInputStream(new GZIPInputStream(java.nio.file.Files.newInputStream(file.toPath())))) { return schematicParser.parseSchematic(reader, schemName); } catch (SchematicParseException error) { onSchematicParseError.accept(error); } catch (Exception error) { Log.entering("SchematicsManagerImpl", "parseSchematic", "ENTER", file.getName(), schemName); Log.error(error, "An unexpected error occurred while loading schematic:"); } return null; } private Schematic loadFromFile(String schemName, File file) { Schematic schematic = null; SchematicParser usedParser = null; for (SchematicParser schematicParser : this.schematicsContainer.getSchematicParsers()) { schematic = parseSchematic(file, schemName, schematicParser, error -> { }); if (schematic != null) { usedParser = schematicParser; break; } } if (schematic == null) { schematic = parseSchematic(file, schemName, DefaultSchematicParser.getInstance(), error -> Log.warn("Schematic ", file.getName(), " is not a valid schematic, ignoring...") ); if (schematic != null) usedParser = DefaultSchematicParser.getInstance(); } if (schematic != null && usedParser != null) { Log.info("Successfully loaded schematic ", file.getName(), " (", usedParser.getClass().getSimpleName(), ")"); } return schematic; } private void saveIntoFile(String name, CompoundTag schematicTag) { try { File file = new File(plugin.getDataFolder(), "schematics/" + name + ".schematic"); if (file.exists()) file.delete(); file.getParentFile().mkdirs(); file.createNewFile(); try (DataOutputStream writer = new DataOutputStream(new GZIPOutputStream(java.nio.file.Files.newOutputStream(file.toPath())))) { schematicTag.write(writer); } } catch (IOException error) { Log.entering("SchematicsManagerImpl", "saveIntoFile", "ENTER", name); Log.error(error, "An unexpected error occurred while saving schematic into file:"); } } private List getEntities(Location min, Location max) { List livingEntities = new LinkedList<>(); Chunk minChunk = min.getChunk(); Chunk maxChunk = max.getChunk(); for (int x = minChunk.getX(); x <= maxChunk.getX(); x++) { for (int z = minChunk.getZ(); z <= maxChunk.getZ(); z++) { Chunk currentChunk = min.getWorld().getChunkAt(x, z); for (Entity entity : currentChunk.getEntities()) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (!(entity instanceof Player) && betweenLocations(entity.getLocation(wrapper.getHandle()), min, max)) livingEntities.add(entity); } } } } return livingEntities; } private boolean betweenLocations(Location location, Location min, Location max) { return location.getBlockX() >= min.getBlockX() && location.getBlockX() <= max.getBlockX() && location.getBlockY() >= min.getBlockY() && location.getBlockY() <= max.getBlockY() && location.getBlockZ() >= min.getBlockZ() && location.getBlockZ() <= max.getBlockZ(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; public class DefaultSchematicsContainer implements SchematicsContainer { private final Map schematicMap = new LinkedHashMap<>(); private final List schematicParsers = new LinkedList<>(); @Nullable @Override public Schematic getSchematic(String name) { return this.schematicMap.get(name.toLowerCase(Locale.ENGLISH)); } @Override public void addSchematic(Schematic schematic) { this.schematicMap.put(schematic.getName().toLowerCase(Locale.ENGLISH), schematic); } @Override public Map getSchematics() { return Collections.unmodifiableMap(this.schematicMap); } @Override public void addSchematicParser(SchematicParser schematicParser) { this.schematicParsers.add(schematicParser); } @Override public List getSchematicParsers() { return Collections.unmodifiableList(this.schematicParsers); } @Override public void clearSchematics() { this.schematicMap.clear(); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.container; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import java.util.List; import java.util.Map; public interface SchematicsContainer { @Nullable Schematic getSchematic(String name); void addSchematic(Schematic schematic); Map getSchematics(); void addSchematicParser(SchematicParser schematicParser); List getSchematicParsers(); void clearSchematics(); } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic; import org.bukkit.Location; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.function.Consumer; public class CachedSuperiorSchematic extends BaseSchematic implements Schematic { private final Int2ObjectMapView cachedSessions = CollectionsFactory.createInt2ObjectArrayMap(); private final SuperiorSchematic baseSchematic; private final Dimension schematicDimension; public CachedSuperiorSchematic(SuperiorSchematic baseSchematic) { super(baseSchematic.getName(), KeyMaps.createEmptyMap()); this.baseSchematic = baseSchematic; this.schematicDimension = getSchematicDimension(baseSchematic.getName()); if (!(WorldGenerator.getWorldGenerator(this.schematicDimension) instanceof IslandsGenerator)) throw new IllegalStateException("Cannot use cached schematics with custom generators"); populateCache(); } @Override public Map getBlockCounts() { return this.baseSchematic.getBlockCounts(); } @Override public List getAffectedChunks() { return this.baseSchematic.getAffectedChunks(); } @Override public Runnable onTeleportCallback() { return this.baseSchematic.onTeleportCallback(); } @Override public void pasteSchematic(Island island, Location location, Runnable callback, Consumer onFailure) { BukkitExecutor.ensureAsync(() -> pasteSchematicInternal(island, location, callback, onFailure)); } private void pasteSchematicInternal(Island island, Location location, Runnable callback, Consumer onFailure) { long profiler = Profiler.start(ProfileType.SCHEMATIC_PLACE, getName()); Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location); try { pasteSchematicAsyncInternal(island, location, profiler, callback, onFailure); } catch (Throwable error) { Log.debugResult(Debug.PASTE_SCHEMATIC, "Failed Schematic Placement", error); Profiler.end(profiler); if (onFailure != null) onFailure.accept(error); } } private void pasteSchematicAsyncInternal(Island island, Location location, long profiler, Runnable callback, Consumer onFailure) { int chunkX = location.getBlockX() & 0xF; int chunkZ = location.getBlockZ() & 0xF; long placeProfiler = Profiler.start(ProfileType.SCHEMATIC_BLOCKS_PLACE, getName()); WorldEditSessionCache worldEditSessionCache = this.cachedSessions.get(posKey(chunkX, chunkZ)); if (worldEditSessionCache == null) throw new IllegalStateException("Cannot find cache for (" + chunkX + "," + chunkZ + ")"); WorldEditSession worldEditSession = plugin.getNMSWorld().createEditSession(location.getWorld()); worldEditSession.applyData(worldEditSessionCache.sessionData, location); worldEditSessionCache.prePlaceTasks.forEach(schematicBlock -> { schematicBlock.doPrePlace(island); Location newBlockLoc = new Location( location.getWorld(), location.getBlockX() - worldEditSessionCache.baseLocation.getX() + schematicBlock.getLocation().getBlockX(), schematicBlock.getLocation().getBlockY(), location.getBlockZ() - worldEditSessionCache.baseLocation.getZ() + schematicBlock.getLocation().getBlockZ() ); worldEditSession.setBlock(newBlockLoc, schematicBlock.getCombinedId(), schematicBlock.getStatesTag(), schematicBlock.getTileEntityData()); }); Profiler.end(placeProfiler); List postPlaceTasks = worldEditSessionCache.postPlaceTasks.isEmpty() ? Collections.emptyList() : new LinkedList<>(); worldEditSessionCache.postPlaceTasks.forEach(schematicBlock -> { Location newBlockLoc = new Location( location.getWorld(), location.getBlockX() - worldEditSessionCache.baseLocation.getX() + schematicBlock.getLocation().getBlockX(), schematicBlock.getLocation().getBlockY(), location.getBlockZ() - worldEditSessionCache.baseLocation.getZ() + schematicBlock.getLocation().getBlockZ() ); postPlaceTasks.add(schematicBlock.setLocation(newBlockLoc)); }); this.baseSchematic.finishPlaceSchematic(worldEditSession, postPlaceTasks, island, location, profiler, callback, onFailure); } @Override public Location adjustRotation(Location location) { return this.baseSchematic.adjustRotation(location); } private void populateCache() { Log.info("Caching schematics for ", this.name, "..."); int cacheSize = calculateCacheSize(); switch (cacheSize) { case 1: populateCache1Size(); break; case 4: populateCache4Size(); break; case 16: populateCache16Size(); break; } } private void populateCache1Size() { // Possible chunk offsets: {(0, 0)} this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0)); } private void populateCache4Size() { // Possible chunk offsets: {(8, 8), (0, 8), (8, 0), (0, 0)} this.cachedSessions.put(posKey(8, 8), createSessionCache(24, 24)); this.cachedSessions.put(posKey(0, 8), createSessionCache(0, 24)); this.cachedSessions.put(posKey(8, 0), createSessionCache(24, 0)); this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0)); } private void populateCache16Size() { // 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)} this.cachedSessions.put(posKey(4, 4), createSessionCache(-12, -12)); this.cachedSessions.put(posKey(12, 4), createSessionCache(12, -12)); this.cachedSessions.put(posKey(8, 8), createSessionCache(24, 24)); this.cachedSessions.put(posKey(4, 0), createSessionCache(-12, 0)); this.cachedSessions.put(posKey(0, 4), createSessionCache(0, -12)); this.cachedSessions.put(posKey(8, 4), createSessionCache(24, -12)); this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0)); this.cachedSessions.put(posKey(12, 0), createSessionCache(12, 0)); this.cachedSessions.put(posKey(4, 12), createSessionCache(-12, 12)); this.cachedSessions.put(posKey(8, 0), createSessionCache(24, 0)); this.cachedSessions.put(posKey(0, 12), createSessionCache(0, 12)); this.cachedSessions.put(posKey(12, 12), createSessionCache(12, 12)); this.cachedSessions.put(posKey(4, 8), createSessionCache(-12, 24)); this.cachedSessions.put(posKey(8, 12), createSessionCache(-24, 12)); this.cachedSessions.put(posKey(0, 8), createSessionCache(0, 24)); this.cachedSessions.put(posKey(12, 8), createSessionCache(12, 24)); } private WorldEditSessionCache createSessionCache(int x, int z) { Location location = new Location(null, x, plugin.getSettings().getIslandHeight() - 1, z); List prePlaceTasks = new LinkedList<>(); List postPlaceTasks = new LinkedList<>(); WorldEditSession worldEditSession = plugin.getNMSWorld().createPartialEditSession(this.schematicDimension); this.baseSchematic.populateSessionWithSchematicBlocks(worldEditSession, location, prePlaceTasks, postPlaceTasks); WorldEditSession.Data sessionData = worldEditSession.readData(location); worldEditSession.release(); return new WorldEditSessionCache(sessionData, prePlaceTasks, postPlaceTasks, location); } private static int posKey(int x, int z) { byte xByte = (byte) (x & 0xF); byte zByte = (byte) (z & 0xF); return xByte << 8 | zByte; } private static int calculateCacheSize() { switch ((plugin.getSettings().getMaxIslandSize() / 4) % 4) { case 0: return 1; case 2: return 4; // case 1: // case 3: default: return 16; } } private static Dimension getSchematicDimension(String name) { for (Dimension dimension : Dimension.values()) { if (name.endsWith("_" + dimension.getName().toLowerCase(Locale.ENGLISH))) return dimension; } return plugin.getSettings().getWorlds().getDefaultWorldDimension(); } private static class WorldEditSessionCache { private final WorldEditSession.Data sessionData; private final List prePlaceTasks; private final List postPlaceTasks; private final Location baseLocation; WorldEditSessionCache(WorldEditSession.Data sessionData, List prePlaceTasks, List postPlaceTasks, Location baseLocation) { this.sessionData = sessionData; this.prePlaceTasks = prePlaceTasks; this.postPlaceTasks = postPlaceTasks; this.baseLocation = baseLocation; } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.impl; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.core.BigBitSet; import com.bgsoftware.superiorskyblock.core.ByteBigArray; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.VarintArray; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock; import com.bgsoftware.superiorskyblock.core.schematic.SchematicBlockData; import com.bgsoftware.superiorskyblock.core.schematic.SchematicEntity; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.entity.EntityType; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeSet; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; public class SuperiorSchematic extends BaseSchematic implements Schematic { private static final ByteBigArray EMPTY_BLOCK_IDS = new ByteBigArray((short) 0); private static final BigBitSet EMPTY_BIT_SET = new BigBitSet(0); private final Data data; private List affectedChunks = null; private Runnable onTeleportCallback = null; public SuperiorSchematic(String name, CompoundTag compoundTag) { super(name); int xSize = compoundTag.getInt("xSize").orElse(0); int ySize = compoundTag.getInt("ySize").orElse(0); int zSize = compoundTag.getInt("zSize").orElse(0); int offsetX = compoundTag.getInt("offsetX").orElse(xSize / 2); int offsetY = compoundTag.getInt("offsetY").orElse(ySize / 2); int offsetZ = compoundTag.getInt("offsetZ").orElse(zSize / 2); BlockOffset schematicOffset = SBlockOffset.fromOffsets(offsetX, offsetY, offsetZ).negate(); float yaw = (float) compoundTag.getFloat("yaw").orElse(0f); float pitch = (float) compoundTag.getFloat("pitch").orElse(0f); int dataVersion = compoundTag.getInt("minecraftDataVersion").orElse(-1); ByteBigArray blockIds; BigBitSet bitSet; Map extra; int minX; int minY; int minZ; ListTag blocksList = compoundTag.getList("blocks").orElse(null); if (blocksList == null) { blockIds = EMPTY_BLOCK_IDS; bitSet = EMPTY_BIT_SET; extra = Collections.emptyMap(); minX = 0; minY = 0; minZ = 0; } else { minX = Integer.MAX_VALUE; minY = Integer.MAX_VALUE; minZ = Integer.MAX_VALUE; int maxX = Integer.MIN_VALUE; int maxY = Integer.MIN_VALUE; int maxZ = Integer.MIN_VALUE; TreeSet schematicBlocks = new TreeSet<>(Comparator.naturalOrder()); for (Tag tag : blocksList) { SchematicBlockData schematicBlock = SuperiorSchematicDeserializer.deserializeSchematicBlock((CompoundTag) tag, dataVersion); if (schematicBlock != null) { schematicBlocks.add(schematicBlock); readBlock(schematicBlock); // Compute the min and max block offset as we want to shrink as much as possible the amount // of blocks in the schematic in memory. This will give us a layout of blocks that do not // include any AIR blocks at all. BlockOffset blockOffset = schematicBlock.getBlockOffset(); minX = Math.min(blockOffset.getOffsetX(), minX); minY = Math.min(blockOffset.getOffsetY(), minY); minZ = Math.min(blockOffset.getOffsetZ(), minZ); maxX = Math.max(blockOffset.getOffsetX(), maxX); maxY = Math.max(blockOffset.getOffsetY(), maxY); maxZ = Math.max(blockOffset.getOffsetZ(), maxZ); } } // The xSize,ySize,zSize in the schematic consider air blocks, however we do not want them. // Therefore, we adjust the sizes accordingly to the actual blocks in the schematic. xSize = maxX - minX + 1; ySize = maxY - minY + 1; zSize = maxZ - minZ + 1; if ((long) xSize * (long) ySize * (long) zSize > Integer.MAX_VALUE) { throw new IllegalStateException("Cannot create such large schematic of size " + xSize + "x" + ySize + "x" + zSize); } VarintArray blockIdsVarintArray = new VarintArray(); bitSet = new BigBitSet(xSize * ySize * zSize); extra = new HashMap<>(); for (SchematicBlockData schematicBlock : schematicBlocks) { BlockOffset blockOffset = schematicBlock.getBlockOffset(); int x = blockOffset.getOffsetX() - minX; int y = blockOffset.getOffsetY() - minY; int z = blockOffset.getOffsetZ() - minZ; // Calculate index in the BitSet for the given x,y,z. // The BitSet is sorted similar to how SchematicBlockData#compareTo is implemented. int index = y * (xSize * zSize) + x * zSize + z; bitSet.set(index); blockIdsVarintArray.add(schematicBlock.getCombinedId()); if (schematicBlock.getExtra() != null) extra.put(blockOffset, schematicBlock.getExtra()); } blockIds = blockIdsVarintArray.toArray(); } List entities; ListTag entitiesList = compoundTag.getList("entities").orElse(null); if (entitiesList == null) { entities = Collections.emptyList(); } else { entities = new LinkedList<>(); for (Tag tag : entitiesList) { CompoundTag compound = (CompoundTag) tag; try { EntityType entityType = EntityType.valueOf(compound.getString("entityType").orElse(null)); CompoundTag entityTag = compound.getCompound("NBT").orElse(null); Location offset = Serializers.LOCATION_SERIALIZER.deserialize(compound.getString("offset").orElse(null)); if (offset != null) entities.add(new SchematicEntity(entityType, entityTag, SBlockOffset.fromOffsets(offset.getX(), offset.getY(), offset.getZ()))); } catch (Exception error) { error.printStackTrace(); } } } this.data = new Data(schematicOffset, yaw, pitch, bitSet, blockIds, xSize, ySize, zSize, minX, minY, minZ, extra, entities); } private SuperiorSchematic(String name, Data data, KeyMap cachedCounts) { super(name, cachedCounts); this.data = data; } @Override public void pasteSchematic(Island island, Location location, Runnable callback, Consumer onFailure) { BukkitExecutor.ensureAsync(() -> pasteSchematicInternal(island, location, callback, onFailure)); } private void pasteSchematicInternal(Island island, Location location, Runnable callback, Consumer onFailure) { long profiler = Profiler.start(ProfileType.SCHEMATIC_PLACE, getName()); Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location); try { pasteSchematicAsyncInternal(island, location, profiler, callback, onFailure); } catch (Throwable error) { Log.debugResult(Debug.PASTE_SCHEMATIC, "Failed Schematic Placement", error); Profiler.end(profiler); if (onFailure != null) onFailure.accept(error); } } public void populateSessionWithSchematicBlocks(WorldEditSession worldEditSession, Location location, List prePlaceTasks, List postPlaceTasks) { Location min = this.data.offset.applyToLocation(location); VarintArray.Itr blockIdsIterator = new VarintArray(this.data.blockIds).iterator(); for (int i = this.data.bitSet.nextSetBit(0); i >= 0; i = this.data.bitSet.nextSetBit(i + 1)) { int x = ((i / this.data.zSize) % this.data.xSize) + this.data.minX; int y = (i / (this.data.xSize * this.data.zSize)) + this.data.minY; int z = (i % this.data.zSize) + this.data.minZ; BlockOffset blockOffset = SBlockOffset.fromOffsets(x, y, z); Location blockLocation = blockOffset.applyToLocation(min); SchematicBlock schematicBlock = new SchematicBlock(blockLocation, (int) blockIdsIterator.next(), data.extra.get(blockOffset)); prePlaceTasks.add(schematicBlock); worldEditSession.setBlock(blockLocation, schematicBlock.getCombinedId(), schematicBlock.getStatesTag(), schematicBlock.getTileEntityData()); if (schematicBlock.shouldPostPlace()) postPlaceTasks.add(schematicBlock); } if (blockIdsIterator.hasNext()) throw new IllegalStateException("Not all blocks were read from varint iterator"); } public void finishPlaceSchematic(WorldEditSession worldEditSession, List postPlaceTasks, Island island, Location location, long profiler, Runnable callback, Consumer onFailure) { List affectedChunks = worldEditSession.getAffectedChunks(); List> chunkFutures = new ArrayList<>(affectedChunks.size()); AtomicBoolean failed = new AtomicBoolean(false); MutableBoolean printedWarning = new MutableBoolean(false); affectedChunks.forEach(chunkPosition -> { if (!island.isInside(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ())) { if (!printedWarning.get()) { Log.warn("Part of the schematic ", name, " is placed outside of the island, skipping this part..."); printedWarning.set(true); } return; } chunkFutures.add(ChunksProvider.loadChunk(chunkPosition, ChunkLoadReason.SCHEMATIC_PLACE, chunk -> { if (failed.get()) return; try { worldEditSession.applyBlocks(chunk); boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class); if (cropGrowthEnabled && island.isInsideRange(chunk)) { BukkitExecutor.ensureMain(() -> plugin.getNMSChunks().startTickingChunk(island, chunk, false)); } island.markChunkDirty(chunk.getWorld(), chunk.getX(), chunk.getZ(), true); Log.debugResult(Debug.PASTE_SCHEMATIC, "Loaded Chunk", chunkPosition); } catch (Throwable error) { Log.debugResult(Debug.PASTE_SCHEMATIC, "Failed Loading Chunk", error); failed.set(true); Profiler.end(profiler); if (onFailure != null) onFailure.accept(error); } })); }); CompletableFuture.allOf(chunkFutures.toArray(new CompletableFuture[0])).whenComplete((v, error) -> { if (failed.get()) return; Log.debugResult(Debug.PASTE_SCHEMATIC, "Finished Chunks Loading", ""); BukkitExecutor.ensureMain(() -> { try { Log.debugResult(Debug.PASTE_SCHEMATIC, "Placing Schematic", ""); worldEditSession.finish(island); if (island.getOwner().isOnline()) { postPlaceTasks.forEach(schematicBlock -> { schematicBlock.doPostPlace(island); }); } Log.debugResult(Debug.PASTE_SCHEMATIC, "Finished Schematic Placement", ""); island.handleBlocksPlace(cachedCounts); PluginEventsFactory.callIslandSchematicPasteEvent(island, null, name, location); Profiler.end(profiler); synchronized (this) { try { Location min = this.data.offset.applyToLocation(location); prepareCallback(affectedChunks, min); callback.run(); } finally { finishCallback(); } } } catch (Throwable error2) { Log.debugResult(Debug.PASTE_SCHEMATIC, "Failed Finishing Placement", error2); Profiler.end(profiler); if (onFailure != null) onFailure.accept(error2); } }); }); } private void pasteSchematicAsyncInternal(Island island, Location location, long profiler, Runnable callback, Consumer onFailure) { List postPlaceTasks = new LinkedList<>(); List prePlaceTasks = new LinkedList<>(); long placeProfiler = Profiler.start(ProfileType.SCHEMATIC_BLOCKS_PLACE, getName()); WorldEditSession worldEditSession = plugin.getNMSWorld().createEditSession(location.getWorld()); populateSessionWithSchematicBlocks(worldEditSession, location, prePlaceTasks, postPlaceTasks); prePlaceTasks.forEach(schematicBlock -> { schematicBlock.doPrePlace(island); worldEditSession.setBlock(schematicBlock.getLocation(), schematicBlock.getCombinedId(), schematicBlock.getStatesTag(), schematicBlock.getTileEntityData()); }); Profiler.end(placeProfiler); finishPlaceSchematic(worldEditSession, postPlaceTasks, island, location, profiler, callback, onFailure); } @Override public Location adjustRotation(Location location) { location.setYaw(this.data.yaw); location.setPitch(this.data.pitch); return location; } @Override public List getAffectedChunks() { return affectedChunks == null ? Collections.emptyList() : Collections.unmodifiableList(affectedChunks); } @Override public Runnable onTeleportCallback() { return this.onTeleportCallback; } public SuperiorSchematic copy(String newName) { return new SuperiorSchematic(newName, this.data, this.cachedCounts); } private void readBlock(SchematicBlockData block) { Key key = plugin.getNMSAlgorithms().getBlockKey(block.getCombinedId()); cachedCounts.put(key, cachedCounts.getRaw(key, 0) + 1); } private void prepareCallback(List affectedChunks, Location min) { this.affectedChunks = new LinkedList<>(affectedChunks); // We spawn the entities with a delay, waiting for players to teleport to the island first. this.onTeleportCallback = () -> { BukkitExecutor.sync(() -> { for (SchematicEntity entity : data.entities) { entity.spawnEntity(min); } }, 20L); }; } private void finishCallback() { this.affectedChunks = null; this.onTeleportCallback = null; } private static class Data { private final BlockOffset offset; private final float yaw; private final float pitch; private final BigBitSet bitSet; private final ByteBigArray blockIds; private final Map extra; private final List entities; /* Required to deserialize the bitset */ private final int minX; private final int minY; private final int minZ; private final int xSize; private final int ySize; private final int zSize; Data(BlockOffset offset, float yaw, float pitch, BigBitSet bitSet, ByteBigArray blockIds, int xSize, int ySize, int zSize, int minX, int minY, int minZ, Map extra, List entities) { this.offset = offset; this.yaw = yaw; this.pitch = pitch; this.bitSet = bitSet; this.blockIds = blockIds; this.minX = minX; this.minY = minY; this.minZ = minZ; this.xSize = xSize; this.ySize = ySize; this.zSize = zSize; this.extra = Collections.unmodifiableMap(extra); this.entities = Collections.unmodifiableList(entities); } } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock; import com.bgsoftware.superiorskyblock.core.schematic.SchematicBlockData; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.google.common.collect.Maps; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.SkullType; import org.bukkit.block.BlockFace; import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.EnumMap; import java.util.Map; public class SuperiorSchematicDeserializer { private static final ListTag EMPTY_ITEMS_LIST = ListTag.of(Collections.emptyList()); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final EnumMap rotationToByte = Maps.newEnumMap(BlockFace.class); static { rotationToByte.put(BlockFace.EAST, (byte) 4); rotationToByte.put(BlockFace.SOUTH, (byte) 8); rotationToByte.put(BlockFace.WEST, (byte) 12); rotationToByte.put(BlockFace.NORTH_EAST, (byte) 2); rotationToByte.put(BlockFace.NORTH_WEST, (byte) 14); rotationToByte.put(BlockFace.SOUTH_EAST, (byte) 6); rotationToByte.put(BlockFace.SOUTH_WEST, (byte) 10); rotationToByte.put(BlockFace.WEST_NORTH_WEST, (byte) 13); rotationToByte.put(BlockFace.NORTH_NORTH_WEST, (byte) 15); rotationToByte.put(BlockFace.NORTH_NORTH_EAST, (byte) 1); rotationToByte.put(BlockFace.EAST_NORTH_EAST, (byte) 3); rotationToByte.put(BlockFace.EAST_SOUTH_EAST, (byte) 5); rotationToByte.put(BlockFace.SOUTH_SOUTH_EAST, (byte) 7); rotationToByte.put(BlockFace.SOUTH_SOUTH_WEST, (byte) 9); rotationToByte.put(BlockFace.WEST_SOUTH_WEST, (byte) 11); } private SuperiorSchematicDeserializer() { } public static void convertOldTileEntity(CompoundTag compoundTag) { CompoundTag tileEntity = CompoundTag.of(); compoundTag.getString("baseColor").ifPresent(baseColor -> tileEntity.setInt("Base", DyeColor.valueOf(baseColor).getDyeData())); compoundTag.getCompound("patterns").ifPresent(patterns -> { ListTag patternsList = ListTag.of(CompoundTag.class); for (Tag tag : patterns) { if (tag instanceof CompoundTag) { CompoundTag oldPatternTag = (CompoundTag) tag; CompoundTag patternTag = CompoundTag.of(); patternTag.setInt("Color", oldPatternTag.getInt("color").orElse(0)); patternTag.setString("Pattern", oldPatternTag.getString("type").orElse("")); patternsList.addTag(patternTag); } } tileEntity.setTag("Patterns", patternsList); }); compoundTag.getCompound("contents").ifPresent(contents -> { ListTag items = ListTag.of(CompoundTag.class); for (Map.Entry> item : contents.entrySet()) { if (item.getValue() instanceof CompoundTag) { try { ItemStack itemStack = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize((CompoundTag) item.getValue()); CompoundTag itemCompound = plugin.getNMSTags().serializeItem(itemStack); itemCompound.setByte("Slot", Byte.parseByte(item.getKey())); items.addTag(itemCompound); } catch (Exception ignored) { } } } tileEntity.setTag("Items", items); String inventoryType = compoundTag.getString("inventoryType").orElse("CHEST"); tileEntity.setString("inventoryType", inventoryType); }); compoundTag.getString("flower").ifPresent(flower -> { try { String[] flowerSections = flower.split(":"); tileEntity.setString("Item", plugin.getNMSAlgorithms().getMinecraftKey(new ItemStack(Material.valueOf(flowerSections[0])))); tileEntity.setInt("Data", Integer.parseInt(flowerSections[1])); } catch (Exception ignored) { } }); compoundTag.getString("skullType").ifPresent(skullType -> tileEntity.setByte("SkullType", (byte) (SkullType.valueOf(skullType).ordinal() - 1))); compoundTag.getString("rotation").ifPresent(rotation -> tileEntity.setByte("Rot", rotationToByte.getOrDefault(BlockFace.valueOf(rotation), (byte) 0))); compoundTag.getString("owner").ifPresent(owner -> tileEntity.setString("Name", owner)); for (int i = 0; i < 4; ++i) { final String textLineKey = "Text" + (i + 1); compoundTag.getString("signLine" + i).ifPresent(signLine -> tileEntity.setString(textLineKey, plugin.getNMSAlgorithms().parseSignLine(signLine))); } compoundTag.getString("spawnedType").ifPresent(spawnedType -> tileEntity.setString("EntityId", spawnedType)); if (!tileEntity.isEmpty()) compoundTag.setTag("tileEntity", tileEntity); } @Nullable public static SchematicBlockData deserializeSchematicBlock(CompoundTag compoundTag, int dataVersion) { BlockOffset blockOffset = Serializers.OFFSET_SERIALIZER.deserialize(compoundTag.getString("blockPosition").orElse(null)); int combinedId; if (compoundTag.containsKey("combinedId")) { combinedId = compoundTag.getInt("combinedId").getAsInt(); } else if (compoundTag.containsKey("id") && compoundTag.containsKey("data")) { int id = compoundTag.getInt("id").getAsInt(); int data = compoundTag.getInt("data").getAsInt(); combinedId = id + (data << 12); } else if (compoundTag.containsKey("type")) { Material type; try { type = Material.valueOf(compoundTag.getString("type").get()); } catch (Exception ignored) { return null; } int data = compoundTag.getInt("data").orElse(0); combinedId = plugin.getNMSAlgorithms().getCombinedId(type, (byte) data); } else { Log.warn("Couldn't find combinedId for the block ", compoundTag.getString("blockPosition"), " - skipping..."); return null; } SuperiorSchematicDeserializer.convertOldTileEntity(compoundTag); SchematicBlock.Extra extra = deserializeSchematicBlockExtra(compoundTag, dataVersion); if (extra != null) { CompoundTag tileEntityTag = extra.getTileEntity(); if (tileEntityTag != null && !tileEntityTag.containsKey("id")) { // We try to detect the id from its combinedId plugin.getNMSAlgorithms().getTileEntityIdFromCombinedId(combinedId).ifPresent(tileEntityId -> { tileEntityTag.setString("id", tileEntityId); }); } } return new SchematicBlockData(combinedId, blockOffset, extra); } private static SchematicBlock.Extra deserializeSchematicBlockExtra(CompoundTag compoundTag, int dataVersion) { // Ignore light levels // byte skyLightLevel = compoundTag.getByte("skyLightLevel"); // byte blockLightLevel = compoundTag.getByte("blockLightLevel"); CompoundTag statesTag = compoundTag.getCompound("states").orElse(null); CompoundTag tileEntity = compoundTag.getCompound("tileEntity").orElse(null); tileEntity = SuperiorSchematicDeserializer.upgradeTileEntity(tileEntity, dataVersion); return statesTag == null && tileEntity == null ? null : new SchematicBlock.Extra(statesTag, tileEntity); } @Nullable private static CompoundTag upgradeTileEntity(@Nullable CompoundTag compoundTag, int dataVersion) { if (compoundTag == null || dataVersion == -1) return compoundTag; int currentDataVersion = plugin.getNMSAlgorithms().getDataVersion(); if (currentDataVersion <= dataVersion) return compoundTag; // Convert chest contents ListTag itemsTag = compoundTag.getList("Items").orElse(EMPTY_ITEMS_LIST); if (itemsTag.size() > 0) { ListTag newItemsTag = ListTag.of(CompoundTag.class); for (Tag tag : itemsTag) { if (tag instanceof CompoundTag) { CompoundTag itemTag = (CompoundTag) tag; int slot = itemTag.getInt("Slot").orElse(0); itemTag.setInt("DataVersion", dataVersion); ItemStack itemStack = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(itemTag); CompoundTag newItemTag = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack); newItemTag.setInt("Slot", slot); newItemsTag.addTag(newItemTag); } } if (newItemsTag.size() > 0) compoundTag.setTag("Items", newItemsTag); } return compoundTag; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsBuilderImpl.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.options; import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.core.SBlockOffset; public class SchematicOptionsBuilderImpl implements SchematicOptions.Builder { private final String schematicName; private BlockOffset blockOffset = SBlockOffset.ZERO; private float yaw = 0f; private float pitch = 0f; private boolean saveAir = false; public SchematicOptionsBuilderImpl(String schematicName) { this.schematicName = schematicName; } @Override public SchematicOptionsBuilderImpl setOffset(int offsetX, int offsetY, int offsetZ) { this.blockOffset = SBlockOffset.fromOffsets(offsetX, offsetY, offsetZ); return this; } @Override public SchematicOptionsBuilderImpl setDirection(float yaw, float pitch) { this.yaw = yaw; this.pitch = pitch; return this; } @Override public SchematicOptionsBuilderImpl setSaveAir(boolean saveAir) { this.saveAir = saveAir; return this; } @Override public SchematicOptions build() { return new SchematicOptionsImpl(this.schematicName, this.blockOffset, this.yaw, this.pitch, this.saveAir); } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsImpl.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.options; import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; public class SchematicOptionsImpl implements SchematicOptions { private final String schematicName; private final BlockOffset blockOffset; private final float yaw; private final float pitch; private final boolean saveAir; public SchematicOptionsImpl(String schematicName, BlockOffset blockOffset, float yaw, float pitch, boolean saveAir) { this.schematicName = schematicName; this.blockOffset = blockOffset; this.yaw = yaw; this.pitch = pitch; this.saveAir = saveAir; } @Override public String getSchematicName() { return this.schematicName; } @Override public int getOffsetX() { return this.blockOffset.getOffsetX(); } @Override public int getOffsetY() { return this.blockOffset.getOffsetY(); } @Override public int getOffsetZ() { return this.blockOffset.getOffsetZ(); } @Override public float getYaw() { return this.yaw; } @Override public float getPitch() { return this.pitch; } @Override public boolean shouldSaveAir() { return this.saveAir; } } ================================================ FILE: src/main/java/com/bgsoftware/superiorskyblock/world/schematic/parser/DefaultSchematicParser.java ================================================ package com.bgsoftware.superiorskyblock.world.schematic.parser; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParseException; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.io.IOUtils; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic; import com.google.common.hash.Hashing; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class DefaultSchematicParser implements SchematicParser { private static final DefaultSchematicParser INSTANCE = new DefaultSchematicParser(); private static final Map HASHED_SCHEMATIC = new ConcurrentHashMap<>(); public static DefaultSchematicParser getInstance() { return INSTANCE; } private DefaultSchematicParser() { } @Override public Schematic parseSchematic(DataInputStream inputStream, String schematicName) throws SchematicParseException { try { byte[] schematicData = IOUtils.toByteArray(inputStream); String hashedData = Hashing.sha256().hashBytes(schematicData).toString(); SuperiorSchematic hashedSchematic = HASHED_SCHEMATIC.get(hashedData); if (hashedSchematic != null) return hashedSchematic.copy(schematicName); DataInputStream schematicStream = new DataInputStream(new ByteArrayInputStream(schematicData)); CompoundTag compoundTag = (CompoundTag) Tag.fromStream(schematicStream, 0); if (ServerVersion.isLegacy() && compoundTag.containsKey("version") && !ServerVersion.getBukkitVersion().equals(compoundTag.getString("version"))) Log.warn("Schematic ", schematicName, " was created in a different version, may cause issues."); if (!compoundTag.isEmpty()) { SuperiorSchematic schematic = new SuperiorSchematic(schematicName, compoundTag); HASHED_SCHEMATIC.put(hashedData, schematic); return schematic; } } catch (IOException ignored) { ignored.printStackTrace(); } throw new SchematicParseException("This schematic is not valid."); } } ================================================ FILE: src/main/resources/block-values/levels.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # Here you can set all the level values for your blocks. # To set specific spawner types, use 'MOB_SPAWNER:': # If no level is found, the formula from config will be used. EXAMPLE: 5 ================================================ FILE: src/main/resources/block-values/worth.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # Here you can set all the block values for your blocks. # To set specific spawner types, use 'MOB_SPAWNER:': ACACIA_DOOR: 1 ACACIA_STAIRS: 1 ACACIA_FENCE: 1 ACACIA_FENCE_GATE: 1 ACTIVATOR_RAIL: 10 ANVIL: 10 ARMOR_STAND: 2 BANNER: 2 BEACON: 100 BED_BLOCK: 1 BEETROOT_BLOCK: 1 BIRCH_DOOR: 1 BIRCH_FENCE: 1 BIRCH_FENCE_GATE: 1 BIRCH_WOOD_STAIRS: 1 BLACK_GLAZED_TERRACOTTA: 1 BLACK_SHULKER_BOX: 1 BLUE_GLAZED_TERRACOTTA: 1 BLUE_SHULKER_BOX: 1 BOAT: 2 BOAT_ACACIA: 2 BOAT_BIRCH: 2 BOAT_DARK_OAK: 2 BOAT_JUNGLE: 2 BOAT_SPRUCE: 2 BONE_BLOCK: 1 BOOKSHELF: 5 BREWING_STAND: 20 BRICK: 5 BRICK_STAIRS: 5 BROWN_GLAZED_TERRACOTTA: 1 BROWN_SHULKER_BOX: 1 BURNING_FURNACE: 10 CACTUS: 1 CAKE_BLOCK: 1 CARPET: 1 CAULDRON: 10 CHEST: 2 CHORUS_FLOWER: 1 CHORUS_PLANT: 1 CLAY: 2 COAL_BLOCK: 9 COBBLE_WALL: 1 COBBLESTONE: 1 COBBLESTONE_STAIRS: 1 COCOA: 1 CONCRETE: 1 CONCRETE_POWDER: 1 CYAN_GLAZED_TERRACOTTA: 1 CYAN_SHULKER_BOX: 1 DARK_OAK_DOOR: 1 DARK_OAK_FENCE: 1 DARK_OAK_FENCE_GATE: 1 DARK_OAK_STAIRS: 1 DAYLIGHT_DETECTOR: 10 DAYLIGHT_DETECTOR_INVERTED: 10 DEAD_BUSH: 1 DETECTOR_RAIL: 10 DIAMOND_BLOCK: 300 DIODE: 5 DIODE_BLOCK_OFF: 5 DIODE_BLOCK_ON: 5 DIRT: 2 DISPENSER: 5 DOUBLE_PLANT: 2 DOUBLE_STEP: 1 DOUBLE_STONE_SLAB2: 1 DRAGON_EGG: 150 DROPPER: 5 EMERALD_BLOCK: 150 ENCHANTMENT_TABLE: 150 END_BRICKS: 2 ENDER_CHEST: 150 ENDER_STONE: 2 EXPLOSIVE_MINECART: 10 FENCE: 1 FENCE_GATE: 1 FLOWER_POT: 5 FROSTED_ICE: 1 FURNACE: 10 GLASS: 2 GLOWSTONE: 1 GOLD_BLOCK: 150 GRASS: 5 GRASS_PATH: 5 GRAY_GLAZED_TERRACOTTA: 1 GRAY_SHULKER_BOX: 1 GRAVEL: 1 GREEN_GLAZED_TERRACOTTA: 1 GREEN_SHULKER_BOX: 1 HARD_CLAY: 2 HAY_BLOCK: 2 HOPPER: 10 HOPPER_MINECART: 20 HUGE_MUSHROOM_1: 1 HUGE_MUSHROOM_2: 1 ICE: 5 IRON_BLOCK: 10 IRON_DOOR_BLOCK: 5 IRON_FENCE: 5 IRON_PLATE: 5 IRON_TRAPDOOR: 1 ITEM_FRAME: 2 JACK_O_LANTERN: 1 JUKEBOX: 10 JUNGLE_DOOR: 1 JUNGLE_FENCE: 1 JUNGLE_FENCE_GATE: 1 JUNGLE_WOOD_STAIRS: 1 LADDER: 1 LAPIS_BLOCK: 10 LEAVES_2: 1 LEAVES: 1 LEVER: 1 LIGHT_BLUE_GLAZED_TERRACOTTA: 1 LIGHT_BLUE_SHULKER_BOX: 1 LIME_GLAZED_TERRACOTTA: 1 LIME_SHULKER_BOX: 1 LOG: 1 LOG_2: 1 LONG_GRASS: 1 MAGENTA_GLAZED_TERRACOTTA: 1 MAGENTA_SHULKER_BOX: 1 MAGMA: 1 MELON_BLOCK: 1 MELON_STEM: 1 MINECART: 10 'MOB_SPAWNER:IRON_GOLEM': 10000 MOSSY_COBBLESTONE: 2 MYCEL: 5 NETHER_BRICK: 2 NETHER_BRICK_STAIRS: 2 NETHER_FENCE: 2 NETHER_STALK: 1 NETHER_WART_BLOCK: 2 NETHERRACK: 1 NOTE_BLOCK: 10 OBSERVER: 1 OBSIDIAN: 10 ORANGE_GLAZED_TERRACOTTA: 1 ORANGE_SHULKER_BOX: 1 PACKED_ICE: 5 PAINTING: 2 PINK_GLAZED_TERRACOTTA: 1 PINK_SHULKER_BOX: 1 PISTON_BASE: 2 PISTON_STICKY_BASE: 2 POWERED_MINECART: 10 POWERED_RAIL: 10 PRISMARINE: 10 PUMPKIN_STEM: 1 PUMPKIN: 1 PURPLE_GLAZED_TERRACOTTA: 1 PURPLE_SHULKER_BOX: 1 PURPUR_BLOCK: 1 PURPUR_DOUBLE_SLAB: 1 PURPUR_PILLAR: 1 PURPUR_SLAB: 1 PURPUR_STAIRS: 1 QUARTZ_BLOCK: 1 QUARTZ_STAIRS: 1 QUARTZ: 1 RAILS: 1 RED_GLAZED_TERRACOTTA: 1 RED_MUSHROOM: 1 RED_NETHER_BRICK: 2 RED_ROSE: 1 RED_SANDSTONE: 1 RED_SANDSTONE_STAIRS: 1 RED_SHULKER_BOX: 1 REDSTONE_BLOCK: 10 REDSTONE_COMPARATOR_OFF: 10 REDSTONE_COMPARATOR_ON: 10 REDSTONE_COMPARATOR: 10 REDSTONE_LAMP_OFF: 10 REDSTONE_LAMP_ON: 10 REDSTONE_TORCH_OFF: 5 REDSTONE_TORCH_ON: 5 REDSTONE_WIRE: 1 SAND: 1 SANDSTONE: 1 SANDSTONE_STAIRS: 1 SEA_LANTERN: 1 SIGN_POST: 1 SILVER_GLAZED_TERRACOTTA: 1 SILVER_SHULKER_BOX: 1 SKULL: 10 SLIME_BLOCK: 10 SMOOTH_BRICK: 2 SMOOTH_STAIRS: 2 SNOW_BLOCK: 1 SOIL: 2 SOUL_SAND: 2 SPONGE: 10 SPRUCE_DOOR: 1 SPRUCE_FENCE: 1 SPRUCE_FENCE_GATE: 1 SPRUCE_WOOD_STAIRS: 1 STAINED_CLAY: 2 STAINED_GLASS: 2 STAINED_GLASS_PANE: 1 STEP: 1 STONE: 1 STONE_BUTTON: 1 STONE_PLATE: 2 STORAGE_MINECART: 10 SUGAR_CANE_BLOCK: 1 THIN_GLASS: 1 TNT: 5 TORCH: 2 TRAP_DOOR: 5 TRAPPED_CHEST: 10 TRIPWIRE_HOOK: 2 TRIPWIRE: 2 VINE: 1 WALL_SIGN: 1 WATER_LILY: 5 WEB: 10 WHEAT: 1 WHITE_GLAZED_TERRACOTTA: 1 WHITE_SHULKER_BOX: 1 WOOD: 1 WOOD_BUTTON: 1 WOOD_DOOR: 1 WOOD_DOUBLE_STEP: 1 WOOD_PLATE: 1 WOOD_STAIRS: 1 WOOD_STEP: 1 WOODEN_DOOR: 1 WOOL: 1 WORKBENCH: 1 YELLOW_FLOWER: 1 YELLOW_GLAZED_TERRACOTTA: 1 YELLOW_SHULKER_BOX: 1 ================================================ FILE: src/main/resources/config.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # Here you can set the amount of time between auto calculations of all islands. # If you want to disable this feature, set interval to 0 # It's recommended to set the task to have a low interval, as it might cause lag. calc-interval: 0 # All settings related to the database of the plugin. database: # For local database, use "SQLite". # For remote database, use "MySQL" or "MariaDB" (Depends on your setup). type: SQLite # Whether the datastore folder should be back-up on startup. backup: true # Remote database information address: 'localhost' port: 3306 db-name: 'SuperiorSkyblock' user-name: 'root' password: 'root' prefix: '' useSSL: false allowPublicKeyRetrieval: true waitTimeout: 600000 maxLifetime: 1800000 # Set the main command of the plugin. # You can add aliases by adding "," after the command name, and split them using ",". # You must have a full restart in order to apply changes for the command. island-command: 'island,is,islands' # Set the maximum island size. Island distances is 3 times bigger than the max size. # Please, do not change it while you have a running islands world! max-island-size: 200 # All the default values for new islands that are created. # Please note: Upgrades with built-in values (upgrades that don't run commands to update values), # will override all the values here. For example, if I set an upgrade that changes generator rates, # there's no need to touch the default generator rates here, as new islands will get the rates from # the upgrade, and not from here. default-values: # The default island size of all islands. island-size: 20 # Set the default block limits of all islands. # The following example will set a limit of 8 hoppers in islands: # block-limits: # HOPPER: 8 # You can find a list of materials here: https://bg-software.com/materials/ block-limits: HOPPER: 8 # Set the default entity limits of all islands. # The following example will set a limit of 4 Minecarts in islands: # entity-limits: # MINECART: 4 # You can find a list of entities here: https://bg-software.com/entities/ entity-limits: MINECART: 4 # Set the default warps limit of all islands. warps-limit: 3 # Set the default team limit of all islands. team-limit: 4 # Set the default coop limit of all islands. coop-limit: 8 # Set the default crop-growth multiplier of all islands. crop-growth: 1 # Set the default spawner-rates multiplier of all islands. spawner-rates: 1 # Set the default mob-drops multiplier of all islands. mob-drops: 1 # Set the default bank limit of all islands. bank-limit: -1 # Set the default generator percentages of all islands. # The following example will set 0.5% chance for diamond block in the normal world, and 50% for gold block in nether: # generator: # normal: # DIAMOND_BLOCK: 1 # STONE: 199 # nether: # GOLD_BLOCK: 1 # NETHERRACK: 1 # You can find a list of materials here: https://bg-software.com/materials/ generator: normal: COBBLESTONE: 95 COAL_ORE: 5 # Set the default role limits of all islands. # The following example will set the limit of the role with the id 1 (Moderator by default) to 5: # role-limits: # '1': 5 role-limits: { } # Set the of default island effects for all islands. # The following example will set the effect level of Speed to 3: # island-effects: # SPEED: 4 # You can find the list of valid potion effects here: # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionEffectType.html island-effects: { } # Set the islands height generation for islands. islands-height: 100 # Feature that adds per player world border in islands. # If you want to globally disable it, set this section to false. # World borders can be toggled by using the /is toggle border command. world-borders: true # All settings related to stacked blocks. stacked-blocks: # If you want to globally disable stacked blocks, set this section to false. # Placement of stacked blocks can be toggled by using the /is toggle blocks command. enabled: true # Custom name for the blocks. custom-name: '&ex{0} {1}' # A list of worlds that blocks cannot stack in. disabled-worlds: [ ] # A list of whitelisted blocks that will get stacked when players have stack mode toggled on. whitelisted: - 'DIAMOND_BLOCK' # Set limits to stacked blocks. limits: EXAMPLE_BLOCK: 5 # Should blocks get added directly into the player's inventory? auto-collect: false # Settings related to the deposit menu. deposit-menu: # Should the menu be opened when shift-clicking stacked blocks? enabled: true # The title of the menu. title: '&lDeposit Blocks' # The formula used to calculate a block's level when it has a worth defined but no level specified. # Use {} as a placeholder for worth. Make sure you only use digits and mathematical operations! block-level-formula: '{} / 2' # Should the island levels be a rounded integer? rounded-island-level: false # How should the island level be rounded when rounded-island-level feature is enabled? # Use UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN or HALF_EVEN # You can see more information about it here: # https://docs.oracle.com/javase/8/docs/api/java/math/RoundingMode.html island-level-rounding-mode: 'HALF_UP' # Whether to automatic track block counts when players place and break blocks. # If set to true, block counts, worth and levels will automatically be updated upon # placement and breaking of blocks. auto-blocks-tracking: true # How should the island top be ordered by default? # Use WORTH, LEVEL, RATING or PLAYERS. island-top-order: 'WORTH' # How should the global warps be ordered by default? # Use WORTH, LEVEL, RATING or PLAYERS. global-warps-order: 'WORTH' # Whether coop members should be enabled or not. coop-members: true # Should players be able to edit island privileges for other players? # When set to false, island privileges could be edited only to island roles. edit-player-permissions: true # All settings related to island roles. # You can find a list of permissions here: https://wiki.bg-software.com/superiorskyblock/island-permissions island-roles: # This role is given to players that are not part of your island. guest: # A custom name for the role. name: 'Guest' # A list of default permissions for guests. permissions: [ ] # This role is given to players that are co-op. coop: name: 'Coop' permissions: - ALLAY_INTERACT - ANIMAL_BREED - ANIMAL_DAMAGE - ANIMAL_SHEAR - BREAK - BRUSH - BUILD - CLOSE_BYPASS - CHORUS_FRUIT - COPPER_GOLEM_INTERACT - CROPS_GROWTH - DROP_ITEMS - DYE_SHEEP - ENDER_PEARL - ENTITY_RIDE - EXPEL_BYPASS - FARM_TRAMPING - FERTILIZE - FISH - HORSE_INTERACT - INTERACT - ITEM_FRAME - LEASH - MINECART_DAMAGE - MINECART_ENTER - MINECART_OPEN - MINECART_PLACE - MONSTER_DAMAGE - NAME_ENTITY - PAINTING - PICKUP_AXOLOTL - PICKUP_DROPS - PICKUP_FISH - PICKUP_LECTERN_BOOK - SADDLE_ENTITY - SIGN_INTERACT - SCULK_SENSOR - TURTLE_EGG_TRAMPING - USE - VILLAGER_TRADING - WIND_CHARGE # The roles ladder for island members. # All the island member roles go here. # - You can add as many roles as you'd like. # - The default role for new members has a weight of 0. # - Every role has all the permissions of the role before it. # - Every role should have a custom id, to determine the role if the name is changed. # Do not change ids!!! They don't have to be in an order. ladder: member: id: 0 name: 'Member' weight: 0 permissions: - ANIMAL_SPAWN - CHEST_ACCESS - DEPOSIT_MONEY - FLY - ISLAND_CHEST - MONSTER_SPAWN - RANKUP - SPAWNER_BREAK - TAMED_ANIMAL_DAMAGE mod: id: 1 name: 'Moderator' weight: 1 permissions: - BAN_MEMBER - CLOSE_ISLAND - DELETE_WARP - EXPEL_PLAYERS - INVITE_MEMBER - KICK_MEMBER - OPEN_ISLAND - RATINGS_SHOW - SET_WARP - VALUABLE_BREAK - WITHDRAW_MONEY admin: id: 2 name: 'Admin' weight: 2 permissions: - COOP_MEMBER - DEMOTE_MEMBERS - DISCORD_SHOW - PAYPAL_SHOW - PROMOTE_MEMBERS - SET_BIOME - SET_DISCORD - SET_HOME - SET_PAYPAL - SET_PERMISSION - SET_ROLE - SET_SETTINGS - UNCOOP_MEMBER leader: id: 3 name: 'Leader' weight: 3 permissions: - ALL # Set the line to create the warp sign. sign-warp-line: '[IslandWarp]' # Set the lines of the island warp. sign-warp: - '&a[Island Warp]' - '' - '' - '' # All settings related to the visitors sign. visitors-sign: # Whether a visitors sign is required for others to visit islands. # If set to false, visitors will be teleported to the regular island home when using `/is visit` required-for-visit: true # Set the line to create the visitors sign. line: '[Welcome]' # The line that will be displayed when the sign is active. active: '&a[Welcome]' # The line that will be displayed when the sign is inactive. inactive: '&c[Welcome]' # The format in which the island description lines will be saved, players can set the island description # by entering it in the next lines of the Visitors Sign. Useful if you want to display a description # in the global-warps menu and want to give it a default color. {0} represents the text on that line. description-line-format: '{0}' # Settings related to the island worlds. worlds: # The default world that will be used. # Use one of the dimensions from below. # The dimension must be enabled or the server won't start. default-world: normal # Set the name of the islands world. world-name: SuperiorWorld # The difficulty of the island worlds. difficulty: EASY # Set the sea level height for island worlds. sea-level-height: 100 # Settings related to the dimensions of the plugin. # You can create custom dimensions by adding them here. dimensions: # Settings related to the normal world. normal: # Should the normal world be enabled? enabled: true # Should the normal be unlocked by default to islands? unlock: true # Should the schematics in this world will not be counted towards worth and level values? schematic-offset: true # The environment of this world environment: NORMAL # The default biome for the world. # If the biome is invalid, PLAINS will be set. biome: PLAINS # Configure the portal agents portals: NETHER: nether ENDER: the_end # Settings related to the nether world. nether: # Should the nether world be enabled? enabled: false # Should the nether be unlocked by default to islands? unlock: true # Custom name for the nether world. # When empty, the name will be "_nether" name: '' # Should the schematics in this world will not be counted towards worth and level values? schematic-offset: true # The environment of this world environment: NETHER # The default biome for the world. # If the biome is invalid, NETHER (or it's 1.16 equivalent) will be used. biome: NETHER_WASTES # Configure the portal agents portals: NETHER: normal ENDER: the_end the_end: # Should the end world be enabled? enabled: false # Should the end be unlocked by default to islands? unlock: false # Custom name for the end world. # When empty, the name will be "_the_end" name: '' # Should the schematics in this world will not be counted towards worth and level values? schematic-offset: true # The environment of this world environment: THE_END # The default biome for the world. # If the biome is invalid, THE_END will be used. biome: THE_END # Configure the portal agents portals: NETHER: nether ENDER: normal # Settings related to dragon fights on the server. dragon-fight: # Whether dragon fights should be enabled. # If enabled, each island will have it's own ender dragon to battle with. enabled: false # The offset of the end portal (where it should be spawning) from the middle of the island. # The format is ', , ' (may be negative). # Having the offset going beyond the island-radius is an undefined behavior! portal-offset: '0, 0, 0' # All settings related to the spawn island. spawn: # The location of the island. Players will be teleported to this # location in many events, such as disbanding islands & getting expelled from one. location: SuperiorWorld, 0, 100, 0, 0, 0 # Should the spawn be protected? # When set to false, settings and permissions will not be applied to the spawn region. # In that case, it is your own responsibility to protect the spawn region. protection: true # A list of settings that will be enabled for the spawn. settings: - CROPS_GROWTH - LAVA_FLOW - NATURAL_ANIMALS_SPAWN - SPAWNER_ANIMALS_SPAWN - TREE_GROWTH - WATER_FLOW # A list of permissions for the spawn island. permissions: [ ] # Should a world border be displayed in the spawn? world-border: false # Set the radius of the spawn island. # This can exceed the max island size, but be aware that it doesn't overlap other islands. size: 200 # Should players get damage in the spawn? players-damage: false # A list of permissions players will have in the islands world, outside of islands. # By adding permissions to this list, players will be able to grief the world, but not # other islands, so use this in caution. world-permissions: [ ] # When enabled, players will get teleported upon void fall. # If they fall not in an island, they will be teleported to spawn. void-teleport: members: true visitors: true # When disabled, visitors won't get damaged in other islands. visitors-damage: false # When disabled, coop won't get damaged in islands they are coop with. coop-damage: true # Should the list of members in island top also include the island leader? island-top-include-leader: true # Set default placeholders that will be returned if the island is null. # Please use the : format. # You can find a list of placeholders here: https://bg-software.com/superiorskyblock/#placeholders default-placeholders: - 'superior_island_leader:N/A' - 'superior_island_level:0' - 'superior_island_worth:0' # Should a confirm gui be displayed when /is ban is executed. ban-confirm: true # Should a confirm gui be displayed when /is disband is executed. disband-confirm: true # Should a confirm gui be displayed when /is kick is executed. kick-confirm: true # Should a confirm gui be displayed when /is leave is executed. leave-confirm: true # Should a confirm gui be displayed when /is transfer is executed. transfer-confirm: true # If you want a specific spawners provider to use, specify it here. # Providers: Auto, WildStacker, EpicSpawners, MergedSpawner, PvpingSpawners, SilkSpawners, RoseStacker spawners-provider: 'AUTO' # If you want a specific stacked-blocks provider to use, specify it here. # Providers: Auto, WildStacker, RoseStacker stacked-blocks-provider: 'AUTO' # All settings related to island names. island-names: # Should creation of islands will ask for name (/is create )? required-for-creation: true # The maximum length for names. max-length: 16 # The minimum length for names. min-length: 3 # A list of names that will be blacklisted. filtered-names: - fuck - duck - hypixel # Should names have color support enabled? color-support: true # Should names be displayed on island-top? island-top: true # Should the plugin prevent players from using player names as island names? prevent-player-names: false # Should the name change announcement be sent to all players? # When disabled, only island members will see the announcement. announce-change-to-all: true # Should players get teleported to the island when they create it? teleport-on-create: true # Should players get teleported to the island when they accept an invite? teleport-on-join: false # Should players get teleported to spawn when they are kicked from their island? teleport-on-kick: true # Should players get teleported to spawn when they leave an island? teleport-on-leave: false # List of clear actions to perform on island members when their island is disbanded. # Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY # You can disable this feature by setting the section to 'clear-on-disband: []' clear-on-disband: - ENDER_CHEST - INVENTORY # List of clear actions to perform on players when they accept an invite. # Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY # You can disable this feature by setting the section to 'clear-on-join: []' clear-on-join: [ ] # List of clear actions to perform on players when they are kicked from their island. # Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY # You can disable this feature by setting the section to 'clear-on-kick: []' clear-on-kick: [ ] # List of clear actions to perform on players when they leave an island. # Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY # You can disable this feature by setting the section to 'clear-on-leave: []' clear-on-leave: [ ] # Should players be able to rate their own islands? rate-own-island: false # Should players be able to change island rating? change-island-rating: true # A list of default settings for new islands. # You can find a list of settings here: https://wiki.bg-software.com/superiorskyblock/island-settings default-settings: - 'CREEPER_EXPLOSION' - 'NATURAL_ANIMALS_SPAWN' - 'NATURAL_MONSTER_SPAWN' - 'SPAWNER_ANIMALS_SPAWN' - 'SPAWNER_MONSTER_SPAWN' - 'WATER_FLOW' - 'LAVA_FLOW' - 'CROPS_GROWTH' - 'TREE_GROWTH' - 'FIRE_SPREAD' - 'EGG_LAY' # Should redstone be disabled on islands that none of the members are online? # This should increase performance on the server. disable-redstone-offline: true # Settings related to afk integrations. # Supported AFK plugins: Essentials, CMI afk-integrations: # Should redstone be disabled when all the players inside the island are AFK? disable-redstone: false # Should mob spawning be disabled when all the players inside the island are AFK? disable-spawning: false # A list of commands that should have cooldown. # Cooldowns are in milliseconds. # You can disable this section by using: # commands-cooldown: # random: # cooldown: 0 commands-cooldown: recalc: cooldown: 30000 bypass-permission: superior.cooldown.bypass.recalc # Set a cooldown for upgrading island values. # Cooldowns are in milliseconds. # You can disable this cooldown by setting it to -1. upgrade-cooldown: -1 # Set the number formatting to be used. # You can see a list of formats under the "Language Tag" column here: # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html number-format: "en-US" # Set the date formatting to be used. # You can see more information about it here: # https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html date-format: "dd/MM/yyyy HH:mm:ss" # Should players skip menus with only one items inside them? # When enabled, creation, island-warps, island-chest and missions menus will be skipped if only one item is inside them. skip-one-item-menus: false # Should visitors get teleported to spawn when pvp is enabled in an island? teleport-on-pvp-enable: true # Should visitors get immuned to pvp for 10 seconds when they teleport to an island that has the settings enabled? # This doesn't apply to the spawn island! immune-to-pvp-when-teleport: true # A list of commands that cannot be executed by visitors. blocked-visitors-commands: [ ] # Set items for containers inside island schematics. default-containers: # Should this setting be enabled? enabled: false containers: # The type of the container. chest: # The contents of the container. '0': type: ICE amount: 2 '1': type: MELON '2': type: TORCH amount: 2 '3': type: BONE '4': type: LAVA_BUCKET '5': type: PUMPKIN_SEEDS '6': type: SUGAR_CANE '7': type: RED_MUSHROOM '8': type: BROWN_MUSHROOM '9': type: CACTUS '10': type: BREAD '11': type: WHEAT '12': type: LEATHER_BOOTS '13': type: LEATHER_LEGGINGS '14': type: LEATHER_CHESTPLATE '15': type: LEATHER_HELMET # Set lines for signs inside island schematics. # You can use the following placeholders: # {player} - The island-owner's name # {island} - The island's name if exists. if not, the owner's name will be pasted. # You can disable this feature by setting the section to 'default-signs: []' default-signs: [ ] # A list of commands that will be executed when an event is called. # You can find a list of events at @ https://bg-software.com/superiorskyblock/api/ # A list of placeholders (Not all of them work for all the events): # %island% %player% %schematic% %enter-cause% %target% %leave-cause% %old-owner% %new-owner% %worth% %level% event-commands: IslandCreateEvent: [ ] # A delay before getting teleported to a warp (in milliseconds). # Players cannot move in that time, or the teleportation will be cancelled. warps-warmup: 0 # A delay before getting teleported to your island (in milliseconds). # Players cannot move in that time, or the teleportation will be cancelled. home-warmup: 0 # A delay before getting teleported to another island (in milliseconds). # Players cannot move in that time, or the teleportation will be cancelled. visit-warmup: 0 # Should liquids get updated when pasting schematics? liquid-update: false # Should lights get updated when pasting schematics? # Enabling this can drop performance a bit. lights-update: true # A list of worlds that PvP will be enabled between island members. pvp-worlds: - 'PvP' # Stop players from leaving their island by walking through the border. stop-leaving: false # Should the values menu be enabled? values-menu: true # A list of crops that will be affected by the crop growth multiplier. # You can find a list of materials here: https://bg-software.com/materials/ crops-to-grow: - 'SAPLING' - 'OAK_SAPLING' - 'SPRUCE_SAPLING' - 'BIRCH_SAPLING' - 'JUNGLE_SAPLING' - 'ACACIA_SAPLING' - 'DARK_OAK_SAPLING' - 'MANGROVE_PROPAGULE' - 'CHERRY_SAPLING' - 'PALE_OAK_SAPLING' - 'BROWN_MUSHROOM' - 'RED_MUSHROOM' - 'BAMBOO' - 'BAMBOO_SAPLING' - 'SUGAR_CANE_BLOCK' - 'SUGAR_CANE' - 'CACTUS' - 'WEEPING_VINES' - 'TWISTING_VINES' - 'VINE' - 'CHORUS_FLOWER' - 'WHEAT' - 'COCOA' - 'PUMPKIN_STEM' - 'ATTACHED_PUMPKIN_STEM' - 'MELON_STEM' - 'ATTACHED_MELON_STEM' - 'BEETROOTS' - 'TORCHFLOWER_CROP' - 'PITCHER_CROP' - 'CAVE_VINES' - 'SWEET_BERRY_BUSH' - 'NETHER_WART' - 'NETHER_WARTS' - 'KELP' - 'CARROT' - 'CARROTS' - 'POTATO' - 'POTATOES' - 'CROPS' # How frequency should the crops task run? (in ticks) # You can disable this feature by setting it to 0. # Warning: When disabled, crops-growth multiplier will not function! crops-interval: 5 # Should only the back button work for closing menus? only-back-button: false # Should players be able to build outside their islands? # All islands will have the size of the max-island-size * 1.5, which means islands will be connected to each other. # It's recommended to have a low max island size when this feature is enabled! build-outside-island: false # The default number of times new players can disband their island. # If you want to disable this feature, set it to -1. default-disband-count: 5 # The default language to be used. # This should be the same as your language file's name. default-language: 'en-US' # Should world borders be enabled by default for new players? default-world-border: true # Should blocks stacking be enabled by default for players? # The blocks stacking will reset every restart for all players to this value. default-blocks-stacker: true # Should panels be toggled by default for new players? default-toggled-panel: false # Should fly mode be enabled by default for new players? default-island-fly: false # What the default color for world borders be? # Can be BLUE, GREEN or RED. default-border-color: BLUE # Should obsidian get turned into a lava bucket when clicking it with a bucket in hand? obsidian-to-lava: false # Should the worth values be synced with other prices providers? # You can set the following values: NONE (disabled), BUY (buy prices), SELL (sell prices) # Supported Providers: ShopGUIPlus sync-worth: NONE # Can the worth value of the island be negative? negative-worth: true # Can the level of the island be negative? negative-level: true # A list of events that will not be fired. This can increase performance. # You can find a list of events at @ https://bg-software.com/superiorskyblock/api/ disabled-events: [ ] # A list of commands that should be disabled within the plugin. # You can add a label or an alias of a command to disable it. disabled-commands: [ ] # List of plugins that their hooks should not be enabled. # Simply add the plugin's name in order to prevent it from enabling. disabled-hooks: [ ] # Should there be a schematic-name argument in the create command? # When enabled, people will be able to skip the create menu and create islands directly with the command. schematic-name-argument: true # Settings related to the island chest. island-chests: # The chest title. chest-title: '&4Island Chest' # Default amount of pages. # You can set this value to 0 to not have any pages by default. default-pages: 0 # Default size for the pages. # This is the default number of rows for the chests. # This number must be between 1 and 6. default-size: 3 # Custom aliases for plugin's commands. command-aliases: example-command: - 'Aliase1' - 'Aliase2' # A list of valuable blocks. # These blocks require the "VALUABLE_BREAK" permission in order to break them. valuable-blocks: [ ] # Settings related to the island previews. island-previews: # The game mode that will be set for the player when they enter preview mode. # Use ADVENTURE, CREATIVE, SPECTATOR or SURVIVAL. game-mode: SPECTATOR # The maximum distance a player can move before the preview mode is canceled. max-distance: 100 # A list of commands that cannot be executed by players in preview mode. blocked-commands: [ ] # Preview locations for schematics. # You can disable this feature by setting the section to 'locations: []' # Make sure you follow the location format: ', , , , , ' locations: normal: world, 0, 100, 0 mycel: world, 0, 100, 0 desert: world, 0, 100, 0 # Should vanished players be hidden in tab completes? tab-complete-hide-vanished: true # When enabled, the drops multiplier will only multiply drops of entities that were killed by players. drops-upgrade-players-multiply: false # List of messages that should have a delay. (in milliseconds) message-delays: BUILD_OUTSIDE_ISLAND: 3000 ISLAND_BEING_CALCULATED: 3000 ISLAND_PROTECTED: 3000 ISLAND_PROTECTED_OPPED: 3000 SCHEMATIC_NOT_ADDED: 3000 SPAWN_PROTECTED: 3000 SPAWN_PROTECTED_OPPED: 3000 WORLD_NOT_ENABLED: 3000 WORLD_NOT_UNLOCKED: 3000 # Should players be able to create warp categories? warp-categories: true # Should the physics listener be activated? # This must be enabled if one of the stacked blocks can be affected by gravity or other things. # Disabling this listener can help with performance. physics-listener: true # Should players be charged when using island warps? # You can set an amount of money to charge, 0 to disable the feature. charge-on-warp: 0 # Should island warps be public by default? public-warps: false # Should islands be locked by default? locked-islands: false # Timeout for the recalculate task, in seconds. # If you want to disable the timeout, set this to 0 or below. recalc-task-timeout: 10 # Detect the player's language automatically when he first joins the server. # The language will only get changed if there is a valid translation available, # otherwise the default language will be chosen for the player. auto-language-detection: true # Automatically uncoop players when there are no island members left online that can remove uncoop players. auto-uncoop-when-alone: false # The way members of islands will be sorted in top islands when using the {4} placeholder. # The followings are available: # NAMES - Sort members by their names. # ROLES - Sort members by their island roles. island-top-members-sorting: NAMES # Limit of the amount of bossbar tasks each player can have at the same time. # Once the limit is reached, the old ones will get removed. bossbar-limit: 1 # Delete unsafe warps when players try to teleport to them automatically. # If disabled, warps that are unsafe will stay until players manually delete them. delete-unsafe-warps: true # List of actions to perform when a player respawns. # The plugin will try to perform the actions in the order they are entered here, from top to bottom, # until one action succeeds. Custom respawn actions can be registered using the API. # The default available actions: # BED_TELEPORT - Teleport the player to his bed spawn, if exists. # ISLAND_TELEPORT - Teleport the player to his own island, if exists. # SPAWN_TELEPORT - Teleport the player to spawn when he spawns. # VANILLA - Respawn the player in his vanilla spawn point (bed location or world spawn point). player-respawn: - ISLAND_TELEPORT - SPAWN_TELEPORT # The amount of blocks that are required to be updated on the island before updating the block counts in the database. # This means that if the threshold is at 100, it will require 100 blocks to be added/removed before updating the # database with the new block counts. If the server stops and there was a change to the block counts, the block counts # will be saved to the database despite the threshold. block-counts-save-threshold: 100 # Support for chat-signing in 1.19 or above. # When set to true, the plugin will properly handle messages to not interface # with the signing of chat messages. However, this may cause issues with other # plugins that do not properly handle signed messages, and in this case it # might be better to disable it. chat-signing-support: true # Amount of commands to be listed in the `/is help` and `/is admin` commands. # Setting this to 0 or below will result all commands to be shown in a single page. commands-per-page: 7 # Should players receive a help instead of an `INVALID_COMMAND` message # when using a command that doesn't exist? help-on-invalid-command: true # Should players receive a help instead of a `NO_COMMAND_PERMISSION` message # when using a command they don't have permission for? help-on-no-permission: false ================================================ FILE: src/main/resources/entity-categories.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # Configure the categories of entities of the plugin. # The format of the file is as so: # : # entities: # - # actions: # # The privilege required to spawn the entities using spawn eggs # SPAWN: # # The privilege required to damage the entities # DAMAGE: # # The privilege required to interact with the entities # INTERACT: # # The island flag required so the entities can spawn from spawners # SPAWNER_SPAWN: # # The island flag required so the entities can spawn vanilla # NATURAL_SPAWN: # You can create as many custom categories as you want. # There are custom groups used for detecting animals, monsters and tameable entities. # These groups do not have `entities` and the entities are added automatically depending on your Minecraft version. # Custom interact groups ALLAY: entities: - ALLAY actions: INTERACT: ALLAY_INTERACT AXOLOTL: entities: - AXOLOTL actions: INTERACT: PICKUP_AXOLOTL COPPER_GOLEM: entities: - COPPER_GOLEM actions: INTERACT: COPPER_GOLEM_INTERACT FISH: entities: - COD - PUFFERFISH - SALMON - TADPOLE - TROPICAL_FISH actions: INTERACT: PICKUP_FISH HORSES: entities: - CAMEL - CAMEL_HUSK - DONKEY - HORSE - LLAMA - MULE - SKELETON_HORSE - TRADER_LLAMA - ZOMBIE_HORSE actions: INTERACT: HORSE_INTERACT NAUTILUS: entities: - NAUTILUS - ZOMBIE_NAUTILUS actions: INTERACT: NAUTILUS_INTERACT VILLAGERS: entities: - VILLAGER actions: INTERACT: VILLAGER_TRADING # Custom entities with custom functionalities ARMOR_STAND: entities: - ARMOR_STAND actions: SPAWN: BUILD DAMAGE: BREAK INTERACT: BUILD ITEM_FRAME: entities: - GLOW_ITEM_FRAME - ITEM_FRAME actions: SPAWN: ITEM_FRAME DAMAGE: ITEM_FRAME INTERACT: ITEM_FRAME PAINTING: entities: - PAINTING actions: SPAWN: PAINTING DAMAGE: PAINTING INTERACT: PAINTING # Custom built-in groups TAMEABLE: actions: DAMAGE: TAMED_ANIMAL_DAMAGE VEHICLE: actions: SPAWN: MINECART_PLACE DAMAGE: MINECART_DAMAGE ANIMAL: actions: SPAWN: ANIMAL_SPAWN DAMAGE: ANIMAL_DAMAGE SPAWNER_SPAWN: SPAWNER_ANIMALS_SPAWN NATURAL_SPAWN: NATURAL_ANIMALS_SPAWN MONSTER: actions: SPAWN: MONSTER_SPAWN DAMAGE: MONSTER_DAMAGE SPAWNER_SPAWN: SPAWNER_MONSTER_SPAWN NATURAL_SPAWN: NATURAL_MONSTER_SPAWN ================================================ FILE: src/main/resources/heads.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # A list of skull textures for spawners. # You can find the texture values on https://minecraft-heads.com/ ALLAY: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmVlYTg0NWNjMGI1OGZmNzYzZGVjZmZlMTFjZDFjODQ1YzVkMDljM2IwNGZlODBiMDY2M2RhNWM3YzY5OWViMyJ9fX0=' ARMADILLO: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTE2NGVkMGUwZWY2OWIwY2U3ODE1ZTQzMDBiNDQxM2E0ODI4ZmNiMDA5MjkxODU0MzU0NWE0MThhNDhlMGMzYyJ9fX0=' AXOLOTL: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg3Mjg2MGRhNGQ0NWNlNDNkMWI5ZDAyMzQ0NDJjMDNhOTE3NjVkOThhM2JiMTVmNzMzZTNjZWE1MmFmNWYxOCJ9fX0=' BAT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmZmZDgwOGY4MTI3YjRhZDQ1OGQ5ZDJlMTgxYzY5MGFkZjQ4OWE2YWQzMmVlMmFhNGFjZmE2MzQxZmU4NDIifX19' BEE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTg3NDc4N2UzNjE1OWU0ZDc0ZGI1ZTI1YmFiYTk4N2I2NjVkY2M4OTBiZTlmMjYyYmIwY2JjZjVkMDFiODJiNiJ9fX0=' BLAZE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ==' BOGGED: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTNiOTAwM2JhMmQwNTU2MmM3NTExOWI4YTYyMTg1YzY3MTMwZTkyODJmN2FjYmFjNGJjMjgyNGMyMWViOTVkOSJ9fX0=' BREEZE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTI3NTcyOGFmN2U2YTI5Yzg4MTI1YjY3NWEzOWQ4OGFlOTkxOWJiNjFmZGMyMDAzMzdmZWQ2YWIwYzQ5ZDY1YyJ9fX0=' CAMEL: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2ViNmFkOTA4YjhkNTE1NWJjNGQyNDkyNzFlZjYwODRkNDU1ZGQwZTcwYTQwMDJlYjE0OGY5ZTIwYjlkZWIyYyJ9fX0=' CAMEL_HUSK: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzUwYmZjOWIyY2M0MGY0ZDhkMDIyNGNjYmFiYWMyNmIzMzhhYTk0N2Q5OWRjZGU3NjlmODU5YjU5YjhkMGIwZSJ9fX0=' CAT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmYxODA2NDE3YzE2Y2NkYzMzOWQ0NGQzMjgyNTFhOGQxYmJlYWI5NDVmODdhODViNDhlNGIxMTRmZGVmYiJ9fX0=' CAVE_SPIDER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19' CHICKEN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzODQ2OWE1OTljZWVmNzIwNzUzNzYwMzI0OGE5YWIxMWZmNTkxZmQzNzhiZWE0NzM1YjM0NmE3ZmFlODkzIn19fQ==' COD: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg5MmQ3ZGQ2YWFkZjM1Zjg2ZGEyN2ZiNjNkYTRlZGRhMjExZGY5NmQyODI5ZjY5MTQ2MmE0ZmIxY2FiMCJ9fX0=' COPPER_GOLEM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTllMjRlOTRkYmU0MmUyMzBkODMyOTNhNzdkNjFmZjcxMDFhOGM2OGFiNjhiYmM2YTkzZjk2MzBmYjJmZGI0In19fQ==' COW: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19' CREAKING: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzdiNWJlNzI3NjljY2ZmMWE2Y2I3N2M1ODQ4ZTAxZDdlNTcwNGEzZDM0OWMwNzM3ZmY5M2NiNTRkMDIzODBhYyJ9fX0=' CREEPER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0=' DOLPHIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGU5Njg4Yjk1MGQ4ODBiNTViN2FhMmNmY2Q3NmU1YTBmYTk0YWFjNmQxNmY3OGU4MzNmNzQ0M2VhMjlmZWQzIn19fQ==' DONKEY: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNmMzYzA1MmNmNzg3ZDIzNmEyOTE1ZjgwNzJiNzdjNTQ3NDk3NzE1ZDFkMmY4Y2JjOWQyNDFkODhhIn19fQ==' DROWNED: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzNmN2NjZjYxZGJjM2Y5ZmU5YTYzMzNjZGUwYzBlMTQzOTllYjJlZWE3MWQzNGNmMjIzYjNhY2UyMjA1MSJ9fX0=' ELDER_GUARDIAN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTkyMDg5NjE4NDM1YTBlZjYzZTk1ZWU5NWE5MmI4MzA3M2Y4YzMzZmE3N2RjNTM2NTE5OWJhZDMzYjYyNTYifX19' ENDER_DRAGON: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjY4YzFjMDc5YTdmZmIzNmY0OGRkNzE1MDM1NWUzZTBiN2Y2OGRkNjA1ZTZmODg0NzMxM2MzNjBjZjYxZTBjIn19fQ==' ENDERMAN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2E1OWJiMGE3YTMyOTY1YjNkOTBkOGVhZmE4OTlkMTgzNWY0MjQ1MDllYWRkNGU2YjcwOWFkYTUwYjljZiJ9fX0=' ENDERMITE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWJjN2I5ZDM2ZmI5MmI2YmYyOTJiZTczZDMyYzZjNWIwZWNjMjViNDQzMjNhNTQxZmFlMWYxZTY3ZTM5M2EzZSJ9fX0=' EVOKER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDk1NDEzNWRjODIyMTM5NzhkYjQ3ODc3OGFlMTIxMzU5MWI5M2QyMjhkMzZkZDU0ZjFlYTFkYTQ4ZTdjYmE2In19fQ==' FOX: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmJkZmZlOTY0MmZjNTI4MGU2OGNlNDg4ZTNiY2Y0NDA2ODdlZDNiYzU2NmUzMTVhZjgyNGY0MjhiNmZmNzE1In19fQ==' FROG: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjdiY2NjYzEyNWE0MTEwNDM0YTg1YzQwYWRhMDM5ZDA1MGYxNGVmN2RiMzRhMzQ0NDA2NzMxMGY4Y2U2OTYwNiJ9fX0=' GHAST: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19' GIANT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ==' GLOW_SQUID: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTVlMmI0NmU1MmFjOTJkNDE5YTJkZGJjYzljZGNlN2I0NTFjYjQ4YWU3MzlkODVkNjA3ZGIwNTAyYTAwOGNlMCJ9fX0=' GOAT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDU3YTBkNTM4ZmEwOGE3YWZmZTMxMjkwMzQ2ODg2MTcyMGY5ZmEzNGU4NmQ0NGI4OWRjZWM1NjM5MjY1ZjAzIn19fQ==' GUARDIAN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ==' HAPPY_GHAST: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTFhMzZjYjkzZDAxNjc1YzQ2MjJkZDVjOGQ4NzIxMTA5MTFlYzEyYzM3MmU4OWFmYThiYTAzODYyODY3ZjZmYiJ9fX0=' HOGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWJiOWJjMGYwMWRiZDc2MmEwOGQ5ZTc3YzA4MDY5ZWQ3Yzk1MzY0YWEzMGNhMTA3MjIwODU2MWI3MzBlOGQ3NSJ9fX0=' HORSE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjE5MDI4OTgzMDg3MzBjNDc0NzI5OWNiNWE1ZGE5YzI1ODM4YjFkMDU5ZmU0NmZjMzY4OTZmZWU2NjI3MjkifX19' HUSK: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDY3NGM2M2M4ZGI1ZjRjYTYyOGQ2OWEzYjFmOGEzNmUyOWQ4ZmQ3NzVlMWE2YmRiNmNhYmI0YmU0ZGIxMjEifX19' ILLUSIONER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWM2NzhjOWY0YzZkZDRkOTkxOTMwZjgyZTZlN2Q4Yjg5YjI4OTFmMzVjYmE0OGE0YjE4NTM5YmJlN2VjOTI3In19fQ==' IRON_GOLEM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19' LLAMA: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2YyNGU1NmZkOWZmZDcxMzNkYTZkMWYzZTJmNDU1OTUyYjFkYTQ2MjY4NmY3NTNjNTk3ZWU4MjI5OWEifX19' MAGMA_CUBE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzg5NTdkNTAyM2M5MzdjNGM0MWFhMjQxMmQ0MzQxMGJkYTIzY2Y3OWE5ZjZhYjM2Yjc2ZmVmMmQ3YzQyOSJ9fX0=' MOOSHROOM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDBiYzYxYjk3NTdhN2I4M2UwM2NkMjUwN2EyMTU3OTEzYzJjZjAxNmU3YzA5NmE0ZDZjZjFmZTFiOGRiIn19fQ==' MULE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTA0ODZhNzQyZTdkZGEwYmFlNjFjZTJmNTVmYTEzNTI3ZjFjM2IzMzRjNTdjMDM0YmI0Y2YxMzJmYjVmNWYifX19' MUSHROOM_COW: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDBiYzYxYjk3NTdhN2I4M2UwM2NkMjUwN2EyMTU3OTEzYzJjZjAxNmU3YzA5NmE0ZDZjZjFmZTFiOGRiIn19fQ==' NAUTILUS: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjUzZDYzZWIxNzViMDBmYjM1Mjg1ZjQzMzBkMGJlNjhhMDcxM2RiOTRlMDBlNmZkZDg1ODMyZDQxZTNhMDhiIn19fQ==' OCELOT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTY1N2NkNWMyOTg5ZmY5NzU3MGZlYzRkZGNkYzY5MjZhNjhhMzM5MzI1MGMxYmUxZjBiMTE0YTFkYjEifX19' PANDA: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGYwMDg1ODkyNmNkOGNkZjNmMWNmNzFlMjEwY2RlNWRhZjg3MDgzMjA1NDdiZDZkZjU3OTU4NTljNjhkOWIzZiJ9fX0=' PARCHED: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjRhZWNlZmY1ZjI2ZGQ4NDEzYzVjMDM1NDdjMjM0YWMwMzEwOGQxODdhZjBiOWNkODM0YThjZTEyNTk4NTkxYyJ9fX0=' PARROT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTRiYThkNjZmZWNiMTk5MmU5NGI4Njg3ZDZhYjRhNTMyMGFiNzU5NGFjMTk0YTI2MTVlZDRkZjgxOGVkYmMzIn19fQ==' PHANTOM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzQ2ODMwZGE1ZjgzYTNhYWVkODM4YTk5MTU2YWQ3ODFhNzg5Y2ZjZjEzZTI1YmVlZjdmNTRhODZlNGZhNCJ9fX0=' PIG: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjIxNjY4ZWY3Y2I3OWRkOWMyMmNlM2QxZjNmNGNiNmUyNTU5ODkzYjZkZjRhNDY5NTE0ZTY2N2MxNmFhNCJ9fX0=' PIGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTFkMThiYmQwZDc5NWI5YWM4ZWZhYWQ2NTVlM2QwYzU5ZmNiYjliOTY0YzJhOTk0OGVmNTM3ZjRhM2ZiYmY4NyJ9fX0=' PIGLIN_BRUTE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2UzMDBlOTAyNzM0OWM0OTA3NDk3NDM4YmFjMjllM2E0Yzg3YTg0OGM1MGIzNGMyMTI0MjcyN2I1N2Y0ZTFjZiJ9fX0=' PIG_ZOMBIE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRlOWM2ZTk4NTgyZmZkOGZmOGZlYjMzMjJjZDE4NDljNDNmYjE2YjE1OGFiYjExY2E3YjQyZWRhNzc0M2ViIn19fQ==' PILLAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGFlZTZiYjM3Y2JmYzkyYjBkODZkYjVhZGE0NzkwYzY0ZmY0NDY4ZDY4Yjg0OTQyZmRlMDQ0MDVlOGVmNTMzMyJ9fX0=' POLAR_BEAR: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDQ2ZDIzZjA0ODQ2MzY5ZmEyYTM3MDJjMTBmNzU5MTAxYWY3YmZlODQxOTk2NjQyOTUzM2NkODFhMTFkMmIifX19' PUFFERFISH: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzNiMTk1NWQzYjZlYjQyZjUwZTUzNmMxYTMyODVhYjczZWQ3ZTJiZTA1MWIwOWIyMWUxNzgxMWYxYTZkIn19fQ==' RABBIT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmYxNTU5MTk0YTE3NTkzNWI4YjRmZWE2NjE0YmVjNjBiZjgxY2Y1MjRhZjZmNTY0MzMzYzU1NWU2NTdiYyJ9fX0=' RAVAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2QyMGJmNTJlYzM5MGEwNzk5Mjk5MTg0ZmM2NzhiZjg0Y2Y3MzJiYjFiZDc4ZmQxYzRiNDQxODU4ZjAyMzVhOCJ9fX0=' SALMON: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWRmYzU3ZDA5MDU5ZTQ3OTlmYTkyYzE1ZTI4NTEyYmNmYWExMzE1NTc3ZmUzYTI3YWVkMzg5ZTRmNzUyMjg5YSJ9fX0=' SHEEP: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjMxZjljY2M2YjNlMzJlY2YxM2I4YTExYWMyOWNkMzNkMThjOTVmYzczZGI4YTY2YzVkNjU3Y2NiOGJlNzAifX19' SHULKER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTM3YTI5NGY2YjdiNGJhNDM3ZTVjYjM1ZmIyMGY0Njc5MmU3YWMwYTQ5MGE2NjEzMmE1NTcxMjRlYzVmOTk3YSJ9fX0=' SILVERFISH: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGE5MWRhYjgzOTFhZjVmZGE1NGFjZDJjMGIxOGZiZDgxOWI4NjVlMWE4ZjFkNjIzODEzZmE3NjFlOTI0NTQwIn19fQ==' SKELETON: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ==' SKELETON_HORSE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDdlZmZjZTM1MTMyYzg2ZmY3MmJjYWU3N2RmYmIxZDIyNTg3ZTk0ZGYzY2JjMjU3MGVkMTdjZjg5NzNhIn19fQ==' SLIME: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ==' SNIFFER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTViNjMxYjZhNDk5MDkxMGUwOTVmOGIzMThlYmQxMjE0MzI2YTRmMGY1OGQxYjQ4ZDQyZjk5NmMxZWNiYzk5NCJ9fX0=' SNOW_GOLEM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWZkZmQxZjc1MzhjMDQwMjU4YmU3YTkxNDQ2ZGE4OWVkODQ1Y2M1ZWY3MjhlYjVlNjkwNTQzMzc4ZmNmNCJ9fX0=' SNOWMAN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWZkZmQxZjc1MzhjMDQwMjU4YmU3YTkxNDQ2ZGE4OWVkODQ1Y2M1ZWY3MjhlYjVlNjkwNTQzMzc4ZmNmNCJ9fX0=' SPIDER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ==' SQUID: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ==' STRAY: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmM1MDk3OTE2YmMwNTY1ZDMwNjAxYzBlZWJmZWIyODcyNzdhMzRlODY3YjRlYTQzYzYzODE5ZDUzZTg5ZWRlNyJ9fX0=' STRIDER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMThhOWFkZjc4MGVjN2RkNDYyNWM5YzA3NzkwNTJlNmExNWE0NTE4NjY2MjM1MTFlNGM4MmU5NjU1NzE0YjNjMSJ9fX0=' TADPOLE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTg3MDM1ZjUzNTIzMzRjMmNiYTZhYzRjNjVjMmI5MDU5NzM5ZDZkMGU4MzljMWRkOThkNzVkMmU3Nzk1Nzg0NyJ9fX0=' TRADER_LLAMA: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQyNDc4MGIzYzVjNTM1MWNmNDlmYjViZjQxZmNiMjg5NDkxZGY2YzQzMDY4M2M4NGQ3ODQ2MTg4ZGI0Zjg0ZCJ9fX0=' TROPICAL_FISH: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDZkZDVlNmFkZGI1NmFjYmM2OTRlYTRiYTU5MjNiMWIyNTY4ODE3OGZlZmZhNzIyOTAyOTllMjUwNWM5NzI4MSJ9fX0=' TURTLE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMGE0MDUwZTdhYWNjNDUzOTIwMjY1OGZkYzMzOWRkMTgyZDdlMzIyZjlmYmNjNGQ1Zjk5YjU3MThhIn19fQ==' VEX: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzJlYzVhNTE2NjE3ZmYxNTczY2QyZjlkNWYzOTY5ZjU2ZDU1NzVjNGZmNGVmZWZhYmQyYTE4ZGM3YWI5OGNkIn19fQ==' VILLAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODIyZDhlNzUxYzhmMmZkNGM4OTQyYzQ0YmRiMmY1Y2E0ZDhhZThlNTc1ZWQzZWIzNGMxOGE4NmU5M2IifX19' VINDICATOR: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmRlYWVjMzQ0YWIwOTViNDhjZWFkNzUyN2Y3ZGVlNjFiMDYzZmY3OTFmNzZhOGZhNzY2NDJjODY3NmUyMTczIn19fQ==' WANDERING_TRADER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWYxMzc5YTgyMjkwZDdhYmUxZWZhYWJiYzcwNzEwZmYyZWMwMmRkMzRhZGUzODZiYzAwYzkzMGM0NjFjZjkzMiJ9fX0=' WARDEN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmNmMzY3NGIyZGRjMGVmN2MzOWUzYjljNmI1ODY3N2RlNWNmMzc3ZDJlYjA3M2YyZjNmZTUwOTE5YjFjYTRjOSJ9fX0=' WITCH: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGRlZGJlZTQyYmU0NzJlM2ViNzkxZTdkYmRmYWYxOGM4ZmU1OTNjNjM4YmExMzk2YzllZjY4ZjU1NWNiY2UifX19' WITHER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2RmNzRlMzIzZWQ0MTQzNjk2NWY1YzU3ZGRmMjgxNWQ1MzMyZmU5OTllNjhmYmI5ZDZjZjVjOGJkNDEzOWYifX19' WITHER_SKELETON: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzk1M2I2YzY4NDQ4ZTdlNmI2YmY4ZmIyNzNkNzIwM2FjZDhlMWJlMTllODE0ODFlYWQ1MWY0NWRlNTlhOCJ9fX0=' WOLF: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjlkMWQzMTEzZWM0M2FjMjk2MWRkNTlmMjgxNzVmYjQ3MTg4NzNjNmM0NDhkZmNhODcyMjMxN2Q2NyJ9fX0=' ZOGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTY3ZTE4NjAyZTAzMDM1YWQ2ODk2N2NlMDkwMjM1ZDg5OTY2NjNmYjllYTQ3NTc4ZDNhN2ViYmM0MmE1Y2NmOSJ9fX0=' ZOMBIE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ==' ZOMBIE_HORSE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTcxY2U0NjljYmE0NDI2YzgxMWY2OWJlNWQ5NThhMDliZmI5YjFiMmJiNjQ5ZDM1NzdhMGMyMTYxYWQyZjUyNCJ9fX0=' ZOMBIE_NAUTILUS: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmQ5YTkzMzM3NmRhNDRjMzM5MTMwN2NiOWY0Y2YwM2YxNmYzYTU0ZjQ5NWZkNWExMWJhZDhhMzczZjlkNTcyMCJ9fX0=' ZOMBIE_VILLAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTYyMjQ5NDEzMTRiY2EyZWJiYjY2YjEwZmZkOTQ2ODBjYzk4YzM0MzVlZWI3MWEyMjhhMDhmZDQyYzI0ZGIifX19' ZOMBIFIED_PIGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1NGQwZDFjMjg2YzFiMzRmYjA5MTg0MWMwNmFlZDc0MWExYmY5YjY1YjlhNDMwZTRlNWNhMWQxYzRiOWY2ZiJ9fX0=' ================================================ FILE: src/main/resources/interactables.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # A list of interactable blocks. # Only interactable blocks & stacked blocks will be blocked from being interacted. # The format of the file is as so: # : # - BLOCK_TYPE # - ... # You can create as many custom privileges as you want. interactables: - 'ACACIA_BUTTON' - 'ACACIA_DOOR' - 'ACACIA_FENCE' - 'ACACIA_FENCE_GATE' - 'ACACIA_HANGING_SIGN' - 'ACACIA_PRESSURE_PLATE' - 'ACACIA_SHELF' - 'ACACIA_SIGN' - 'ACACIA_TRAPDOOR' - 'ACACIA_WALL_HANGING_SIGN' - 'ACACIA_WALL_SIGN' - 'ANVIL' - 'BAMBOO_BUTTON' - 'BAMBOO_DOOR' - 'BAMBOO_FENCE' - 'BAMBOO_FENCE_GATE' - 'BAMBOO_HANGING_SIGN' - 'BAMBOO_PRESSURE_PLATE' - 'BAMBOO_SHELF' - 'BAMBOO_SIGN' - 'BAMBOO_TRAPDOOR' - 'BAMBOO_WALL_HANGING_SIGN' - 'BAMBOO_WALL_SIGN' - 'BARREL' - 'BEACON' - 'BED_BLOCK' - 'BEE_NEST' - 'BEEHIVE' - 'BELL' - 'BIRCH_BUTTON' - 'BIRCH_DOOR' - 'BIRCH_FENCE' - 'BIRCH_FENCE_GATE' - 'BIRCH_HANGING_SIGN' - 'BIRCH_PRESSURE_PLATE' - 'BIRCH_SHELF' - 'BIRCH_SIGN' - 'BIRCH_TRAPDOOR' - 'BIRCH_WALL_HANGING_SIGN' - 'BIRCH_WALL_SIGN' - 'BLACK_BED' - 'BLACK_CANDLE' - 'BLACK_SHULKER_BOX' - 'BLAST_FURNACE' - 'BLUE_BED' - 'BLUE_CANDLE' - 'BLUE_SHULKER_BOX' - 'BREWING_STAND' - 'BROWN_BED' - 'BROWN_CANDLE' - 'BROWN_SHULKER_BOX' - 'BURNING_FURNACE' - 'CAKE' - 'CAKE_BLOCK' - 'CAMPFIRE' - 'CANDLE' - 'CARTOGRAPHY_TABLE' - 'CAULDRON' - 'CAVE_VINES' - 'CAVE_VINES_PLANT' - 'CHAIN_COMMAND_BLOCK' - 'CHERRY_BUTTON' - 'CHERRY_DOOR' - 'CHERRY_FENCE' - 'CHERRY_FENCE_GATE' - 'CHERRY_HANGING_SIGN' - 'CHERRY_PRESSURE_PLATE' - 'CHERRY_SHELF' - 'CHERRY_SIGN' - 'CHERRY_TRAPDOOR' - 'CHERRY_WALL_HANGING_SIGN' - 'CHERRY_WALL_SIGN' - 'CHEST' - 'CHIPPED_ANVIL' - 'CHISELED_BOOKSHELF' - 'COMMAND' - 'COMMAND_BLOCK' - 'COMMAND_CHAIN' - 'COMMAND_REPEATING' - 'COMPARATOR' - 'COMPOSTER' - 'COPPER_CHEST' - 'COPPER_DOOR' - 'COPPER_GOLEM_STATUE' - 'COPPER_TRAPDOOR' - 'CRAFTER' - 'CRAFTING_TABLE' - 'CRIMSON_BUTTON' - 'CRIMSON_DOOR' - 'CRIMSON_FENCE' - 'CRIMSON_FENCE_GATE' - 'CRIMSON_HANGING_SIGN' - 'CRIMSON_PRESSURE_PLATE' - 'CRIMSON_SHELF' - 'CRIMSON_SIGN' - 'CRIMSON_TRAPDOOR' - 'CRIMSON_WALL_HANGING_SIGN' - 'CRIMSON_WALL_SIGN' - 'CYAN_BED' - 'CYAN_CANDLE' - 'CYAN_SHULKER_BOX' - 'DAMAGED_ANVIL' - 'DARK_OAK_BUTTON' - 'DARK_OAK_DOOR' - 'DARK_OAK_FENCE' - 'DARK_OAK_FENCE_GATE' - 'DARK_OAK_HANGING_SIGN' - 'DARK_OAK_PRESSURE_PLATE' - 'DARK_OAK_SHELF' - 'DARK_OAK_SIGN' - 'DARK_OAK_TRAPDOOR' - 'DARK_OAK_WALL_HANGING_SIGN' - 'DARK_OAK_WALL_SIGN' - 'DAYLIGHT_DETECTOR' - 'DAYLIGHT_DETECTOR_INVERTED' - 'DECORATED_POT' - 'DISPENSER' - 'DRAGON_EGG' - 'DROPPER' - 'ENCHANTING_TABLE' - 'ENCHANTMENT_TABLE' - 'END_PORTAL_FRAME' - 'ENDER_CHEST' - 'ENDER_PORTAL_FRAME' - 'EXPOSED_COPPER_CHEST' - 'EXPOSED_COPPER_DOOR' - 'EXPOSED_COPPER_GOLEM_STATUE' - 'EXPOSED_COPPER_TRAPDOOR' - 'FARMLAND' - 'FENCE' - 'FENCE_GATE' - 'FLOWER_POT' - 'FURNACE' - 'GLOWING_REDSTONE_ORE' - 'GOLD_PLATE' - 'GRAY_BED' - 'GRAY_CANDLE' - 'GRAY_SHULKER_BOX' - 'GREEN_BED' - 'GREEN_CANDLE' - 'GREEN_SHULKER_BOX' - 'GRINDSTONE' - 'HEAVY_WEIGHTED_PRESSURE_PLATE' - 'HOPPER' - 'IRON_PLATE' - 'JIGSAW' - 'JUKEBOX' - 'JUNGLE_BUTTON' - 'JUNGLE_DOOR' - 'JUNGLE_FENCE' - 'JUNGLE_FENCE_GATE' - 'JUNGLE_HANGING_SIGN' - 'JUNGLE_PRESSURE_PLATE' - 'JUNGLE_SHELF' - 'JUNGLE_SIGN' - 'JUNGLE_TRAPDOOR' - 'JUNGLE_WALL_HANGING_SIGN' - 'JUNGLE_WALL_SIGN' - 'KELP' - 'LECTERN' - 'LEVER' - 'LIGHT_BLUE_BED' - 'LIGHT_BLUE_CANDLE' - 'LIGHT_BLUE_SHULKER_BOX' - 'LIGHT_GRAY_BED' - 'LIGHT_GRAY_CANDLE' - 'LIGHT_GRAY_SHULKER_BOX' - 'LIGHT_WEIGHTED_PRESSURE_PLATE' - 'LIME_BED' - 'LIME_CANDLE' - 'LIME_SHULKER_BOX' - 'LODESTONE' - 'LOOM' - 'MAGENTA_BED' - 'MAGENTA_CANDLE' - 'MAGENTA_SHULKER_BOX' - 'MANGROVE_BUTTON' - 'MANGROVE_DOOR' - 'MANGROVE_FENCE' - 'MANGROVE_FENCE_GATE' - 'MANGROVE_HANGING_SIGN' - 'MANGROVE_PRESSURE_PLATE' - 'MANGROVE_SHELF' - 'MANGROVE_SIGN' - 'MANGROVE_TRAPDOOR' - 'MANGROVE_WALL_HANGING_SIGN' - 'MANGROVE_WALL_SIGN' - 'MOB_SPAWNER' - 'NETHER_BRICK_FENCE' - 'NETHER_FENCE' - 'NOTE_BLOCK' - 'OAK_BUTTON' - 'OAK_DOOR' - 'OAK_FENCE' - 'OAK_FENCE_GATE' - 'OAK_HANGING_SIGN' - 'OAK_PRESSURE_PLATE' - 'OAK_SHELF' - 'OAK_SIGN' - 'OAK_TRAPDOOR' - 'OAK_WALL_HANGING_SIGN' - 'OAK_WALL_SIGN' - 'ORANGE_BED' - 'ORANGE_CANDLE' - 'ORANGE_SHULKER_BOX' - 'OXIDIZED_COPPER_CHEST' - 'OXIDIZED_COPPER_DOOR' - 'OXIDIZED_COPPER_GOLEM_STATUE' - 'OXIDIZED_COPPER_TRAPDOOR' - 'PALE_OAK_BUTTON' - 'PALE_OAK_DOOR' - 'PALE_OAK_FENCE' - 'PALE_OAK_FENCE_GATE' - 'PALE_OAK_HANGING_SIGN' - 'PALE_OAK_PRESSURE_PLATE' - 'PALE_OAK_SHELF' - 'PALE_OAK_SIGN' - 'PALE_OAK_TRAPDOOR' - 'PALE_OAK_WALL_HANGING_SIGN' - 'PALE_OAK_WALL_SIGN' - 'PINK_BED' - 'PINK_CANDLE' - 'PINK_SHULKER_BOX' - 'POLISHED_BLACKSTONE_BUTTON' - 'POLISHED_BLACKSTONE_PRESSURE_PLATE' - 'POTTED_ACACIA_SAPLING' - 'POTTED_ALLIUM' - 'POTTED_AZALEA_BUSH' - 'POTTED_AZURE_BLUET' - 'POTTED_BAMBOO' - 'POTTED_BIRCH_SAPLING' - 'POTTED_BLUE_ORCHID' - 'POTTED_BROWN_MUSHROOM' - 'POTTED_CACTUS' - 'POTTED_CHERRY_SAPLING' - 'POTTED_CLOSED_EYEBLOSSOM' - 'POTTED_CORNFLOWER' - 'POTTED_CRIMSON_FUNGUS' - 'POTTED_CRIMSON_ROOTS' - 'POTTED_DANDELION' - 'POTTED_DARK_OAK_SAPLING' - 'POTTED_DEAD_BUSH' - 'POTTED_FERN' - 'POTTED_FLOWERING_AZALEA_BUSH' - 'POTTED_JUNGLE_SAPLING' - 'POTTED_LILY_OF_THE_VALLEY' - 'POTTED_MANGROVE_PROPAGULE' - 'POTTED_OAK_SAPLING' - 'POTTED_OPEN_EYEBLOSSOM' - 'POTTED_ORANGE_TULIP' - 'POTTED_OXEYE_DAISY' - 'POTTED_PALE_OAK_SAPLING' - 'POTTED_PINK_TULIP' - 'POTTED_POPPY' - 'POTTED_RED_MUSHROOM' - 'POTTED_RED_TULIP' - 'POTTED_SPRUCE_SAPLING' - 'POTTED_TORCHFLOWER' - 'POTTED_WARPED_FUNGUS' - 'POTTED_WARPED_ROOTS' - 'POTTED_WHITE_TULIP' - 'POTTED_WITHER_ROSE' - 'PUMPKIN' - 'PURPLE_BED' - 'PURPLE_CANDLE' - 'PURPLE_SHULKER_BOX' - 'RED_BED' - 'RED_CANDLE' - 'RED_SHULKER_BOX' - 'REDSTONE_COMPARATOR_OFF' - 'REDSTONE_COMPARATOR_ON' - 'REDSTONE_ORE' - 'REPEATER' - 'REPEATING_COMMAND_BLOCK' - 'RESPAWN_ANCHOR' - 'ROOTED_DIRT' - 'SHULKER_BOX' - 'SIGN_POST' - 'SMITHING_TABLE' - 'SMOKER' - 'SOIL' - 'SOUL_CAMPFIRE' - 'SPAWNER' - 'SPRUCE_BUTTON' - 'SPRUCE_DOOR' - 'SPRUCE_FENCE' - 'SPRUCE_FENCE_GATE' - 'SPRUCE_HANGING_SIGN' - 'SPRUCE_PRESSURE_PLATE' - 'SPRUCE_SHELF' - 'SPRUCE_SIGN' - 'SPRUCE_TRAPDOOR' - 'SPRUCE_WALL_HANGING_SIGN' - 'SPRUCE_WALL_SIGN' - 'STONE_BUTTON' - 'STONE_PRESSURE_PLATE' - 'STONECUTTER' - 'STRUCTURE_BLOCK' - 'SWEET_BERRY_BUSH' - 'TARGET' - 'TEST_BLOCK' - 'TEST_INSTANCE_BLOCK' - 'TNT' - 'TRAP_DOOR' - 'TRAPPED_CHEST' - 'TURTLE_EGG' - 'TWISTING_VINES' - 'VAULT' - 'WALL_SIGN' - 'WARPED_BUTTON' - 'WARPED_DOOR' - 'WARPED_FENCE' - 'WARPED_FENCE_GATE' - 'WARPED_HANGING_SIGN' - 'WARPED_PRESSURE_PLATE' - 'WARPED_SHELF' - 'WARPED_SIGN' - 'WARPED_TRAPDOOR' - 'WARPED_WALL_HANGING_SIGN' - 'WARPED_WALL_SIGN' - 'WAXED_COPPER_CHEST' - 'WAXED_COPPER_DOOR' - 'WAXED_COPPER_GOLEM_STATUE' - 'WAXED_COPPER_TRAPDOOR' - 'WAXED_EXPOSED_COPPER_CHEST' - 'WAXED_EXPOSED_COPPER_DOOR' - 'WAXED_EXPOSED_COPPER_GOLEM_STATUE' - 'WAXED_EXPOSED_COPPER_TRAPDOOR' - 'WAXED_OXIDIZED_COPPER_CHEST' - 'WAXED_OXIDIZED_COPPER_DOOR' - 'WAXED_OXIDIZED_COPPER_GOLEM_STATUE' - 'WAXED_OXIDIZED_COPPER_TRAPDOOR' - 'WAXED_WEATHERED_COPPER_CHEST' - 'WAXED_WEATHERED_COPPER_DOOR' - 'WAXED_WEATHERED_COPPER_GOLEM_STATUE' - 'WAXED_WEATHERED_COPPER_TRAPDOOR' - 'WEATHERED_COPPER_CHEST' - 'WEATHERED_COPPER_DOOR' - 'WEATHERED_COPPER_GOLEM_STATUE' - 'WEATHERED_COPPER_TRAPDOOR' - 'WEEPING_VINES' - 'WHITE_BED' - 'WHITE_CANDLE' - 'WHITE_SHULKER_BOX' - 'WOOD_BUTTON' - 'WOODEN_DOOR' - 'WORKBENCH' - 'YELLOW_BED' - 'YELLOW_CANDLE' - 'YELLOW_SHULKER_BOX' ================================================ FILE: src/main/resources/lang/de-DE.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # You can find a tutorial about configuring messages here: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lInsel | &7Der Spieler {0} wurde erfolgreich zur Insel von {1} hinzugefügt.' ADMIN_ADD_PLAYER_NAME: '&e&lInsel | &7Der Spieler {0} wurde erfolgreich zur Insel {1} ​​hinzugefügt.' ADMIN_DEPOSIT_MONEY: '&e&lBank | &7Du hast $ {0} auf die Inselbank von {1} eingezahlt. ' ADMIN_DEPOSIT_MONEY_NAME: '&e&lBank | &7Du hast {0} Citycoins auf die Bank der Insel {1} ​​eingezahlt. ' ADMIN_HELP_FOOTER: '&e&lSkyblock &7Entwickelt von einem Entwickler' ADMIN_HELP_HEADER: '&e&lSkyblock &7Admin Befehlsliste [{0} / {1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7 {1}' ADMIN_HELP_NEXT_PAGE: '&e&lSkyblock &7Verwende /is admin {0} für die nächste Seite.' ALREADY_IN_ISLAND: '&c&lError | &7Du bist bereits auf einer Insel. ' ALREADY_IN_ISLAND_OTHER: '&c&lFehler | &7Dieser Spieler ist bereits Mitglied deiner Insel.' BAN_ANNOUNCEMENT: '&e&lIsland | &7{0} wurde von {1} von der Insel GEBANNT.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lFehler | &7Du kannst nur Spieler mit einer niedrigeren Inselrolle als deiner bannen.' BANK_DEPOSIT_CUSTOM: '&e&lBank | &7Gebe den Betrag ein, den du einzahlen möchtest:' BANK_DEPOSIT_COMPLETED: Einzahlung abgeschlossen BANK_LIMIT_EXCEED: '&c&lError | &7Du hast dein Banklimit überschritten.' BANK_WITHDRAW_CUSTOM: '&e&lBank | &7Gebe den Betrag ein, den du abheben möchtest:' BANK_WITHDRAW_COMPLETED: Auszahlung abgeschlossen BANNED_FROM_ISLAND: '&c&lError | &7Du bist von dieser Insel verbannt.' BLOCK_COUNT_CHECK: '&e&lInsel | &7Diese Insel hat x{0} {1}.' BLOCK_COUNTS_CHECK: |- &e&lInsel | &7Diese Insel hat die folgenden Blöcke: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lInsel | &7Diese Insel hat keine verfolgten Blöcke.' BLOCK_COUNTS_CHECK_MATERIAL: x{0} {1} BLOCK_LEVEL: '&e&lLevel | &7Die Ebene des Blocks {0} ist {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7Der Block {0} ist wertlos.' BLOCK_VALUE: '&e&lWert | &7Der Block {0} im Wert von {1}.' BLOCK_VALUE_WORTHLESS: '&e&lWert | &7Der Block {0} ist wertlos.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' BORDER_PLAYER_COLOR_NAME_BLUE: Blau BORDER_PLAYER_COLOR_NAME_RED: Rot BORDER_PLAYER_COLOR_NAME_GREEN: Grün BORDER_PLAYER_COLOR_UPDATED: '&e&lGrenze | &7Dein persönlicher Border wurde erfolgreich in {0} geändert.' BUILD_OUTSIDE_ISLAND: '&c&lError | &7Du kannst nicht außerhalb deiner Border bauen.' CANNOT_SET_ROLE: '&c&lError | &7Du kannst die Rolle des Spielers nicht auf {0} setzen.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lError | &7Du kannst Berechtigungen nur auf eine niedrigere Inselrolle als deine ändern.' CHANGED_BANK_LIMIT: '&e&lUpgrades | &7Das Banklimit der Insel von {0} wurde erfolgreich aktualisiert.' CHANGED_BANK_LIMIT_ALL: '&e&lUpgrades | &7Das Banklimit aller Inseln wurde erfolgreich aktualisiert.' CHANGED_BANK_LIMIT_NAME: '&e&lUpgrades | &7Das Banklimit von {0} wurde erfolgreich aktualisiert.' CHANGED_BIOME: '&e&lIsland | &7Biom erfolgreich in {0} geändert. Möglicherweise musst du dich erneut mit dem Server verbinden, um die Änderungen anzuzeigen.' CHANGED_BIOME_ALL: '&e&lInsel | &7Biom für alle Inseln erfolgreich auf {0} geändert.' CHANGED_BIOME_NAME: '&e&lInsel | &7Biom erfolgreich auf {0} für Insel {1} ​​geändert.' CHANGED_BIOME_OTHER: '&e&lInsel | &7Das Biom wurde erfolgreich in {0} für die Insel von {1} geändert.' CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Der Blockbetrag bei {0} wurde erfolgreich in {1} geändert.' CHANGED_BLOCK_LIMIT: '&e&lUpgrades | &7Das {0} Blocklimit der Insel von {1} wurde erfolgreich aktualisiert.' CHANGED_BLOCK_LIMIT_ALL: '&e&lUpgrades | &7Das {0} Blocklimit aller Inseln wurde erfolgreich aktualisiert.' CHANGED_BLOCK_LIMIT_NAME: '&e&lUpgrades | &7Das {0} Blocklimit von {1} wurde erfolgreich aktualisiert.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7Die Zeilen von Seite #{0} wurden erfolgreich auf {1} für die Insel von {2} aktualisiert.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Die Zeilen der Seite #{0} wurden für alle Inseln erfolgreich auf {1} aktualisiert.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Die Zeilen von Seite #{0} wurden erfolgreich auf {1} für {2} aktualisiert.' CHANGED_COOP_LIMIT: '&e&lUpgrades | &7Das Koop-Spielerlimit von {0}s Insel wurde erfolgreich aktualisiert.' CHANGED_COOP_LIMIT_ALL: '&e&lUpgrades | &7Das Koop-Spielerlimit aller Inseln wurde erfolgreich aktualisiert.' CHANGED_COOP_LIMIT_NAME: '&e&lUpgrades | &7Das Koop-Spielerlimit von {0} wurde erfolgreich aktualisiert.' CHANGED_CROP_GROWTH: '&e&lUpgrades | &7Der Kulturpflanzenwachstumsmultiplikator der Insel {0} wurde erfolgreich aktualisiert.' CHANGED_CROP_GROWTH_ALL: '&e&lUpgrades | &7Der Kulturpflanzenwachstumsmultiplikator aller Inseln wurde erfolgreich aktualisiert.' CHANGED_CROP_GROWTH_NAME: '&e&lUpgrades | &7Der Kulturpflanzenwachstumsmultiplikator von {0} wurde erfolgreich aktualisiert.' CHANGED_DISCORD: '&e&lIsland | &7Die Inseldisharmonie wurde erfolgreich in {0} geändert.' CHANGED_ENTITY_LIMIT: '&e&lUpgrades | &7Das Limit von {0} Entitys für die Insel von {1} wurde erfolgreich aktualisiert.' CHANGED_ENTITY_LIMIT_ALL: '&e&lUpgrades | &7Das Limit von {0} Entitys für alle Inseln wurde erfolgreich aktualisiert.' CHANGED_ENTITY_LIMIT_NAME: '&e&lUpgrades | &7Das Limit von {0} Entitys für {1} wurde erfolgreich aktualisiert.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lUpgrades | &7Die Stufe des Inseleffekts {0} für die Insel von {1} wurde erfolgreich aktualisiert.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lUpgrades | &7Die Stufe des Inseleffekts {0} für alle Inseln erfolgreich aktualisiert.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lUpgrades | &7Die Stufe des Inseleffekts {0} für {1} wurde erfolgreich aktualisiert.' CHANGED_ISLAND_SIZE: '&e&lUpgrades | &7Die Inselgröße der Insel von {0} wurde erfolgreich aktualisiert.' CHANGED_ISLAND_SIZE_ALL: '&e&lUpgrades | &7Die Inselgröße aller Inseln wurde erfolgreich aktualisiert.' CHANGED_ISLAND_SIZE_NAME: '&e&lUpgrades | &7Die Inselgröße von {0} wurde erfolgreich aktualisiert.' CHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oSpieler können außerhalb ihrer Insel bauen, daher hat die Inselgröße keinen Einfluss. Sie können diese Funktion in der Konfiguration deaktivieren, damit sich die Inselgröße wieder auswirkt.' CHANGED_LANGUAGE: '&e&lSprache | &7Deine Sprache wurde erfolgreich auf Deutsch geändert.' CHANGED_MOB_DROPS: '&e&lUpgrades | &7Der Mob-Drop-Multiplikator von {0}´s Insel wurde erfolgreich aktualisiert.' CHANGED_MOB_DROPS_ALL: '&e&lUpgrades | &7Der Mob-Drop-Multiplikator aller Inseln wurde erfolgreich aktualisiert.' CHANGED_MOB_DROPS_NAME: '&e&lUpgrades | &7Der Mob-Drop-Multiplikator von {0} wurde erfolgreich aktualisiert.' CHANGED_NAME: '&e&lInsel | &7Du hast den Namen Ihrer Insel in {0}&7 geändert.' CHANGED_NAME_OTHER: '&e&lInsel | &7Du hast den Namen der Insel {0} in {1}&7 geändert.' CHANGED_NAME_OTHER_NAME: '&e&lInsel | &7Du hast den Namen von {0}&7 in {1}&7 geändert.' CHANGED_PAYPAL: '&e&lIsland | &7Island paypal erfolgreich auf {0} geändert.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Das Limit der Rolle {0} für die Insel von {1} wurde erfolgreich aktualisiert.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Das Limit der Rolle {0} für alle Inseln erfolgreich aktualisiert.' CHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Das Limit der Rolle {0} für {1} wurde erfolgreich aktualisiert.' CHANGED_SPAWNER_RATES: '&e&lUpgrades | &7Der Spawner-Raten-Multiplikator der Insel {0} wurde erfolgreich aktualisiert.' CHANGED_SPAWNER_RATES_ALL: '&e&lUpgrades | &7Der Spawner-Raten-Multiplikator aller Inseln wurde erfolgreich aktualisiert.' CHANGED_SPAWNER_RATES_NAME: '&e&lUpgrades | &7Der Spawner-Raten-Multiplikator von {0} wurde erfolgreich aktualisiert.' CHANGED_TEAM_LIMIT: '&e&lUpgrades | &7Das Teamlimit der Insel von {0} wurde erfolgreich aktualisiert.' CHANGED_TEAM_LIMIT_ALL: '&e&lUpgrades | &7Das Teamlimit aller Inseln wurde erfolgreich aktualisiert.' CHANGED_TEAM_LIMIT_NAME: '&e&lUpgrades | &7Das Teamlimit von {0} wurde erfolgreich aktualisiert.' CHANGED_TELEPORT_LOCATION: '&e&lInsel | &7Der Teleport-Standort wurde erfolgreich aktualisiert.' CHANGED_WARPS_LIMIT: '&e&lUpgrades | &7Das Warps-Limit der Insel von {0} wurde erfolgreich aktualisiert.' CHANGED_WARPS_LIMIT_ALL: '&e&lUpgrades | &7Das Warps-Limit aller Inseln wurde erfolgreich aktualisiert.' CHANGED_WARPS_LIMIT_NAME: '&e&lUpgrades | &7Das Warps-Limit von {0} wurde erfolgreich aktualisiert.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: Betrag COMMAND_ARGUMENT_BIOME: biom COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: Befehl... COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: Discord... COMMAND_ARGUMENT_EFFECT: Trank-Effekt COMMAND_ARGUMENT_EMAIL: E-Mail COMMAND_ARGUMENT_ENTITY: Entität COMMAND_ARGUMENT_ISLAND_NAME: Inselname COMMAND_ARGUMENT_ISLAND_ROLE: Inselrolle COMMAND_ARGUMENT_LEADER: Owner COMMAND_ARGUMENT_LEVEL: Stufe COMMAND_ARGUMENT_LIMIT: limit COMMAND_ARGUMENT_MATERIAL: Material COMMAND_ARGUMENT_MENU: Menüname COMMAND_ARGUMENT_MESSAGE: Nachricht... COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: mission-name COMMAND_ARGUMENT_MODULE_NAME: Modulname COMMAND_ARGUMENT_MULTIPLIER: Multiplikator COMMAND_ARGUMENT_NAME: name COMMAND_ARGUMENT_NEW_LEADER: neuer Owner COMMAND_ARGUMENT_PAGE: Seite COMMAND_ARGUMENT_PATH: 'path' COMMAND_ARGUMENT_PERMISSION: Berechtigung COMMAND_ARGUMENT_PLAYER_NAME: Spielername COMMAND_ARGUMENT_PRIVATE: privat COMMAND_ARGUMENT_RATING: Bewertung COMMAND_ARGUMENT_ROWS: Zeilen COMMAND_ARGUMENT_SCHEMATIC_NAME: schema-name COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: Einstellungen COMMAND_ARGUMENT_SIZE: Größe COMMAND_ARGUMENT_TIME: Zeit COMMAND_ARGUMENT_TITLE_DURATION: Dauer COMMAND_ARGUMENT_TITLE_FADE_IN: einblenden COMMAND_ARGUMENT_TITLE_FADE_OUT: Ausblenden COMMAND_ARGUMENT_UPGRADE_NAME: Upgrade-Name COMMAND_ARGUMENT_VALUE: Wert COMMAND_ARGUMENT_WARP_NAME: Warp-Name COMMAND_ARGUMENT_WARP_CATEGORY: Warp-Kategorie COMMAND_ARGUMENT_WORLD: Welt COMMAND_COOLDOWN_FORMAT: '&c&lError | &7Du darfst den Befehl nur in {0} verwenden.' COMMAND_DESCRIPTION_ACCEPT: Eine Einladung von einem Spieler annehmen. COMMAND_DESCRIPTION_ADMIN: Verwende die Admin-Befehle. COMMAND_DESCRIPTION_ADMIN_ADD: Einen Benutzer zu einer Insel hinzufügen. COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Blocklimit für die Insel eines anderen Spielers erhöhen. COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Einem Spieler einen Bonus hinzufügen. COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Koop-Spielerlimit für die Insel eines anderen Spielers erhöhen. COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Erhöht den Multiplikator für das Pflanzenwachstum für die Insel eines anderen Spielers. COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Einen Inseleffekt für die Insel eines anderen Spielers hinzufügen. COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Entity-Limit für die Insel eines anderen Spielers erhöhen. COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Prozentsatz eines Materials für den Kopfsteinpflaster-Generator hinzufügen. COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Erhöhe den Mob-Drop-Multiplikator für die Insel eines anderen Spielers. COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Erweitere die Inselgröße eines anderen Spielers. COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Erhöht den Spawner-Raten-Multiplikator für die Insel eines anderen Spielers. COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Mitgliederlimit für die Insel eines anderen Spielers erhöhen. COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Erhöht das Warps-Limit einer Insel. COMMAND_DESCRIPTION_ADMIN_BONUS: Einem Spieler einen Bonus gewähren. COMMAND_DESCRIPTION_ADMIN_BYPASS: Umgehungsmodus umschalten. COMMAND_DESCRIPTION_ADMIN_CHEST: Öffne die Truhe der Insel einer anderen Insel. COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Generatortarife für eine bestimmte Insel löschen. COMMAND_DESCRIPTION_ADMIN_CLOSE: Schließe eine Insel für die Öffentlichkeit. COMMAND_DESCRIPTION_ADMIN_CMD_ALL: Führe einen Befehl für alle Mitglieder der Inseln aus. COMMAND_DESCRIPTION_ADMIN_COUNT: Überprüfe eine Blockanzahl auf einer bestimmten Insel. COMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.' COMMAND_DESCRIPTION_ADMIN_DEBUG: Debug-Ausgaben umschalten. COMMAND_DESCRIPTION_ADMIN_DEL_WARP: Lösche einen Warp für eine Insel. COMMAND_DESCRIPTION_ADMIN_DEMOTE: Ein Mitglied auf der Insel eines anderen Spielers degradieren. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Geld auf die Inselbank eines anderen Spielers einzahlen. COMMAND_DESCRIPTION_ADMIN_DISBAND: Die Insel eines anderen Spielers dauerhaft auflösen. COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Gib einem Spieler Auflösungen. COMMAND_DESCRIPTION_ADMIN_IGNORE: Ignoriere eine Insel von den Top-Inseln. COMMAND_DESCRIPTION_ADMIN_JOIN: Treten Sie ohne Einladung einer Insel bei. COMMAND_DESCRIPTION_ADMIN_KICK: Kick einen Spieler von seiner Insel. COMMAND_DESCRIPTION_ADMIN_MODULES: Module des Plugins verwalten. COMMAND_DESCRIPTION_ADMIN_MISSION: Ändere den Status einer Mission für einen Spieler. COMMAND_DESCRIPTION_ADMIN_MSG: Sende einem Spieler eine Nachricht ohne Präfixe. COMMAND_DESCRIPTION_ADMIN_MSG_ALL: An alle Inselmitglieder eine Nachricht ohne Präfixe senden. COMMAND_DESCRIPTION_ADMIN_NAME: Ändere den Namen einer Insel. COMMAND_DESCRIPTION_ADMIN_OPEN: Öffne eine Insel für die Öffentlichkeit. COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Öffne ein benutzerdefiniertes Menü für einen Spieler. COMMAND_DESCRIPTION_ADMIN_PROMOTE: Ein Mitglied auf der Insel eines anderen Spielers befördern. COMMAND_DESCRIPTION_ADMIN_PURGE: Inseln säubern. COMMAND_DESCRIPTION_ADMIN_RANKUP: Rang ein Upgrade für eine Insel auf. COMMAND_DESCRIPTION_ADMIN_RECALC: Berechnet den Wert einer Insel neu. COMMAND_DESCRIPTION_ADMIN_RELOAD: Alle Konfigurationen und Aufgaben des Plugins neu laden. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Entferne ein Blocklimit von einer Insel. COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Alle Bewertungen eines Spielers entfernen. COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Setze eine Welt für eine Insel zurück. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Schaltpläne für das Plugin erstellen. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Lege das Biom einer Insel fest. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Blockierungsbetrag an einem bestimmten Ort festlegen. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Blocklimit für die Insel eines anderen Spielers festlegen. COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Lege die Brustreihen für die Insel eines anderen Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Lege das Limit für Koop-Spieler für die Insel eines anderen Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Lege den Pflanzenwachstumsmultiplikator für die Insel eines anderen Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Bestimme die Anzahl der Inselauflösungen eines Spielers. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Lege die Inseleffektstufe der Insel eines anderen Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Entity-Limit für die Insel eines anderen Spielers festlegen. COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Übertrage eine Insel an jemand anderen. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Lege den Mob-Drop-Multiplikator für die Insel eines anderen Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Lege eine erforderliche Rolle für eine Berechtigung für alle Inseln fest. COMMAND_DESCRIPTION_ADMIN_SET_RATE: Lege die Wertung eines anderen Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: Rollenlimit für die Insel eines anderen Spielers festlegen. COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Einstellungen für eine bestimmte Insel umschalten. COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Prozentsatz eines Materials für den Kopfsteinpflaster-Generator ändern. COMMAND_DESCRIPTION_ADMIN_SET_SIZE: Die Inselgröße eines anderen Spielers ändern. COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Lege den Spawn-Standort des Servers fest. COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Lege den Spawner-Raten-Multiplikator für die Insel eines anderen Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Mitgliederlimit für die Insel eines anderen Spielers festlegen. COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Lege die Stufe eines Upgrades für die Insel eines anderen Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Lege das Warps-Limit einer Insel fest. COMMAND_DESCRIPTION_ADMIN_SETTINGS: Öffne den Plugin-Einstellungseditor. COMMAND_DESCRIPTION_ADMIN_SHOW: Informationen über eine Insel abrufen. COMMAND_DESCRIPTION_ADMIN_SPAWN: Teleport zum Spawn-Ort. COMMAND_DESCRIPTION_ADMIN_SPY: Chat-Spionagemodus umschalten COMMAND_DESCRIPTION_ADMIN_STATS: Statistiken über das Plugin anzeigen. COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Upgrade-Werte für eine Insel synchronisieren. COMMAND_DESCRIPTION_ADMIN_TELEPORT: Teleport zur anderen Inseln. COMMAND_DESCRIPTION_ADMIN_TITLE: Sende einem Spieler einen Titel. COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: An alle Inselmitglieder einen Titel senden. COMMAND_DESCRIPTION_ADMIN_UNIGNORE: Ignoriere eine Insel von den Top-Inseln. COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Schalte eine Welt für eine Insel frei. COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Geld von der Inselbank eines anderen Spielers abheben. COMMAND_DESCRIPTION_BALANCE: Überprüfe den Geldbetrag in der Bank einer Insel. COMMAND_DESCRIPTION_BAN: Banne einen Spieler von deiner Insel. COMMAND_DESCRIPTION_BANK: Öffne die Bank der Insel. COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Ändere das Biom der Insel. COMMAND_DESCRIPTION_BORDER: Ändere die Randfarbe der Inseln. COMMAND_DESCRIPTION_CHEST: Öffne die Truhe der Insel. COMMAND_DESCRIPTION_CLOSE: Schließe die Insel für die Öffentlichkeit. COMMAND_DESCRIPTION_COOP: Füge einen Spieler als Coop zu deiner Insel hinzu. COMMAND_DESCRIPTION_COOPS: Öffne das Coop-Menü. COMMAND_DESCRIPTION_COUNTS: Siehe Blockanzahlen auf deiner Insel. COMMAND_DESCRIPTION_CREATE: Erstelle eine neue Insel. COMMAND_DESCRIPTION_DEL_WARP: Einen Insel-Warp löschen. COMMAND_DESCRIPTION_DEMOTE: Ein Mitglied auf deiner Insel degradieren. COMMAND_DESCRIPTION_DEPOSIT: Zahle Geld von deinem persönlichen Konto auf die Bank der Insel ein. COMMAND_DESCRIPTION_DISBAND: Lösche deine Insel für immer. COMMAND_DESCRIPTION_EXPEL: Kick einen Besucher von deiner Insel. COMMAND_DESCRIPTION_FLY: Inselfliegen umschalten. COMMAND_DESCRIPTION_HELP: Liste aller Befehle. COMMAND_DESCRIPTION_INVITE: Lade einen Spieler auf Ihre Insel ein. COMMAND_DESCRIPTION_KICK: Kick einen Spieler von deiner Insel. COMMAND_DESCRIPTION_LANG: Ändere deine persönliche Sprache. COMMAND_DESCRIPTION_LEAVE: Verlasse deine Insel. COMMAND_DESCRIPTION_MEMBERS: Öffne das Mitgliedermenü. COMMAND_DESCRIPTION_MISSION: Beende eine Mission. COMMAND_DESCRIPTION_MISSIONS: Öffne das Missionsmenü. COMMAND_DESCRIPTION_NAME: Ändere den Namen deiner Insel. COMMAND_DESCRIPTION_OPEN: Öffne die Insel für die Öffentlichkeit. COMMAND_DESCRIPTION_PANEL: Insel-Panel öffnen. COMMAND_DESCRIPTION_PARDON: Bann einen Spieler von deiner Insel auf. COMMAND_DESCRIPTION_PERMISSIONS: Alle Berechtigungen für eine Inselrolle erhalten. COMMAND_DESCRIPTION_PROMOTE: Bewerbe ein Mitglied auf Ihrer Insel. COMMAND_DESCRIPTION_RANKUP: Ein Upgrade aufleveln. COMMAND_DESCRIPTION_RATE: Bewerte eine Insel. COMMAND_DESCRIPTION_RATINGS: Alle Inselbewertungen anzeigen. COMMAND_DESCRIPTION_SETTINGS: Öffne das Einstellungsmenü. COMMAND_DESCRIPTION_RECALC: Berechnet den Inselwert neu. COMMAND_DESCRIPTION_SET_DISCORD: Lege den Discord der Insel für Inselauszahlungen fest. COMMAND_DESCRIPTION_SET_PAYPAL: Lege die Paypal-E-Mail der Insel für Inselauszahlungen fest. COMMAND_DESCRIPTION_SET_ROLE: Ändere die Rolle eines Spielers auf deiner Insel. COMMAND_DESCRIPTION_SET_TELEPORT: Ändere den Teleportstandort deiner Insel. COMMAND_DESCRIPTION_SET_WARP: Erstelle einen neuen Insel-Warp. COMMAND_DESCRIPTION_SHOW: Erhalte Informationen über eine Insel. COMMAND_DESCRIPTION_TEAM: Erhalte Informationen über den Status der Inselmitglieder. COMMAND_DESCRIPTION_TEAM_CHAT: Team-Chat-Modus umschalten. COMMAND_DESCRIPTION_TELEPORT: Teleportiere dich zu deiner Insel. COMMAND_DESCRIPTION_TOGGLE: Inselgrenzen und Platzierung von gestapelten Blöcken umschalten. COMMAND_DESCRIPTION_TOP: Oberes Inselfenster öffnen. COMMAND_DESCRIPTION_TRANSFER: Übertrage die Führung deiner Insel. COMMAND_DESCRIPTION_UNCOOP: Entferne einen Spieler aus dem Koop auf deiner Insel. COMMAND_DESCRIPTION_UPGRADE: Upgrade-Panel öffnen. COMMAND_DESCRIPTION_VALUE: Erhalte den Wert eines Blocks. COMMAND_DESCRIPTION_VALUES: Öffne das Wertemenü. COMMAND_DESCRIPTION_VISIT: Teleport zum Besucherstandort einer Insel. COMMAND_DESCRIPTION_VISITORS: Öffne das Besuchermenü. COMMAND_DESCRIPTION_WARP: Warp zu einem Insel-Warp. COMMAND_DESCRIPTION_WARPS: Öffne das Warps-Menü. COMMAND_DESCRIPTION_WITHDRAW: Geld von der Bank deiner Insel auf dein persönliches Konto abheben. COMMAND_USAGE: '&cUsage: /{0}' COOP_ANNOUNCEMENT: '&e&lInsel | &7{0} hat {1} als Genossenschaftsmitglied hinzugefügt.' COOP_BANNED_PLAYER: '&c&lFehler | &7Dieser Spieler ist von der Insel gesperrt und kann nicht kooperiert werden.' COOP_LIMIT_EXCEED: '&c&lFehler | &7Du hast die maximale Anzahl an Koop-Spielern erreicht, die die Insel haben kann.' CREATE_ISLAND: '&e&lInsel | &7Neue Insel bei {0} in {1}ms erstellt.' CREATE_ISLAND_FAILURE: '&c&lError | &7Beim Erstellen deiner Insel ist ein Fehler aufgetreten. Bitte wende dich an den Administrator, um das Problem zu untersuchen.' CREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.' DEBUG_MODE_DISABLED: '&e&lDebug | &7Debug-Modus umgeschaltet &cOFF&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7Debug-Modus &aON&7 umgeschaltet.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.' DELETE_WARP: '&e&lInsel | &7Du hast den Warp {0} gelöscht.' DELETE_WARP_SIGN_BROKE: '&7&oEs gab ein Zeichen für diesen Warp, er ist gebrochen...' DEMOTE_LEADER: '&c&lError | &7Du kannst keine Inselanführer degradieren.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lFehler | &7Du kannst nur Spieler mit einer niedrigeren Inselrolle als deiner degradieren.' DEMOTED_MEMBER: '&e&lInsel | &7Du hast {0} auf seiner Insel zu einem {1} degradiert.' DEPOSIT_ANNOUNCEMENT: '&e&lBank | &7{0} hat ${1} auf die Inselbank eingezahlt!' DEPOSIT_ERROR: '&c&lError | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lError | &7Du darfst nicht außerhalb deiner Border abbauen.' DISBAND_ANNOUNCEMENT: '&e&lInsel | &7Deine Insel wurde von {0} aufgelöst.' DISBAND_GIVE: '&e&lInsel | &7Du hast {0} Auflösungen erhalten.' DISBAND_GIVE_ALL: '&e&lInsel | &7Du hast {0} allen Spielern aufgelöst.' DISBAND_GIVE_OTHER: '&e&lInsel | &7Du hast {1} {0} aufgelöst.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oDeine Insel wurde aufgelöst und ${0} Dollar wurden deinem Konto von der Inselbank zurückerstattet' DISBAND_SET: '&e&lInsel | &7Deine Auflösungsanzahl wurde auf {0} gesetzt.' DISBAND_SET_ALL: '&e&lInsel | &7Du hast die Auflösungsanzahl aller Spieler auf {0} gesetzt.' DISBAND_SET_OTHER: '&e&lInsel | &7Du hast den Auflösungszähler von {0} auf {1} gesetzt.' DISBANDED_ISLAND: '&e&lInsel | &7Du hast deine Insel aufgelöst.' DISBANDED_ISLAND_OTHER: '&e&lInsel | &7Du hast die Insel von {0} aufgelöst.' DISBANDED_ISLAND_OTHER_NAME: '&e&lInsel | &7Sie haben die Insel {0} aufgelöst.' ENTER_PVP_ISLAND: '&7&oDu wurdest auf eine Insel mit aktiviertem PVP teleportiert. Du bist für die nächsten 10 Sekunden immun gegen PVP...' EXPELLED_PLAYER: '&e&lInsel | &7{0} wurde von der Insel vertrieben.' FORMAT_QUAD: Q FORMAT_TRILLION: T FORMAT_BILLION: B FORMAT_MILLION: M FORMAT_THOUSANDS: K FORMAT_SECONDS_NAME: Sekunden FORMAT_SECOND_NAME: zweite FORMAT_MINUTES_NAME: Minuten FORMAT_MINUTE_NAME: Minute FORMAT_HOURS_NAME: Stunden FORMAT_HOUR_NAME: Stunde FORMAT_DAYS_NAME: Tage FORMAT_DAY_NAME: Tag GENERATOR_CLEARED: '&e&lInsel | &7Die Generator Anzahl für die Insel von {0} wurden erfolgreich gelöscht.' GENERATOR_CLEARED_NAME: '&e&lInsel | &7Die Generator Anzahl für die Insel {0} wurden erfolgreich ausgeglichen.' GENERATOR_CLEARED_ALL: '&e&lInsel | &7Erfolgreich die Generator Anzahl für alle Inseln gelöscht.' GENERATOR_UPDATED: '&e&lInsel | &7Der Generator Anzahl von {0} wurde erfolgreich auf die Insel von {1} aktualisiert.' GENERATOR_UPDATED_NAME: '&e&lInsel | &7Der Generator Anzahl von {0} wurde erfolgreich auf die Insel {1} ​​aktualisiert.' GENERATOR_UPDATED_ALL: '&e&lInsel | &7Die Generator Anzahl von {0} wurde erfolgreich auf alle Inseln aktualisiert.' GLOBAL_COMMAND_EXECUTED: '&e&lInsel | &7Der Befehl wurde erfolgreich auf den Inselelementen von {0} ausgeführt!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lInsel | &7Der Befehl wurde erfolgreich auf den Inselmitgliedern von {0} ausgeführt!' GLOBAL_MESSAGE_SENT: '&e&lInsel | &7Die Nachricht wurde erfolgreich an die Inselmitglieder von {0} gesendet!' GLOBAL_MESSAGE_SENT_NAME: '&e&lInsel | &7Die Nachricht wurde erfolgreich an die Inselmitglieder von {0} gesendet!' GLOBAL_TITLE_SENT: '&e&lInsel | &7Der Titel wurde erfolgreich an die Inselmitglieder von {0} gesendet!' GLOBAL_TITLE_SENT_NAME: '&e&lInsel | &7Der Titel wurde erfolgreich an die Inselmitglieder von {0} gesendet!' GOT_BANNED: '&e&lInsel | &7Du wurdest von {0}´s Insel GEBANNT.' GOT_DEMOTED: '&e&lIsland | &7Du wurdest auf dieser Insel zu einem {0} degradiert.' GOT_EXPELLED: '&e&lIsland | &7&oDu wurdest von {0} von der Insel vertrieben.' GOT_INVITE: '&e&lInsel | &7{0} hat dich auf seine Insel eingeladen.' GOT_INVITE_TOOLTIP: '&7Klicke auf die Nachricht, um die Einladung anzunehmen.' GOT_KICKED: '&e&lInsel | &7Du wurdest von {0} von seiner Insel geworfen.' GOT_PROMOTED: '&e&lInsel | &7Du wurdest auf seiner Insel zu einem {0} befördert.' GOT_REVOKED: '&e&lInsel | &7{0} hat deine Einladung zu dieser Insel widerrufen.' GOT_UNBANNED: '&e&lInsel | &7Du wurdest von {0}´s Insel ENTBANNT.' HIT_ISLAND_MEMBER: '&c&lError | &7Du kannst deine Inselmitglieder nicht treffen.' HIT_PLAYER_IN_ISLAND: '&c&lError | &7Du kannst keine Spieler innerhalb von Inseln treffen.' IGNORED_ISLAND: '&e&lInsel | Die Insel von &7{0} wird jetzt von den oberen Inseln ignoriert.' IGNORED_ISLAND_NAME: '&e&lInsel | &7Die Insel {0} wird jetzt von den oberen Inseln ignoriert.' INTERACT_OUTSIDE_ISLAND: '&c&lError | &7Du kannst außerhalb der Border nicht interagieren.' INVALID_AMOUNT: '&c&lError | &7Ungültiger Betrag {0}.' INVALID_BIOME: '&c&lError | &7Ungültiges Biom {0}.' INVALID_BLOCK: '&c&lError | &7Ungültige Blockposition {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lError | &7Ungültige Wirkung {0}.' INVALID_ENTITY: '&c&lError | &7Ungültige Entität {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lError | &7Du hast keine Insel.' INVALID_ISLAND_LOCATION: '&c&lError | &7An deinem Standort gibt es keine Insel.' INVALID_ISLAND_OTHER: '&c&lError | &7{0} hat keine Insel.' INVALID_ISLAND_OTHER_NAME: '&c&lFehler | &7Es gibt keine Insel mit dem Namen {0}.' INVALID_ISLAND_PERMISSION: |- &c&lFehler | &7Die Inselberechtigung {0} konnte nicht gefunden werden. &c&lFehler | &7Inselberechtigungen: {1} INVALID_LEVEL: '&c&lError | &7Ungültige Ebene {0}.' INVALID_LIMIT: '&c&lError | &7Ungültiges Limit {0}.' INVALID_MATERIAL: '&c&lError | &7Ungültiges Material {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Ungültige Materialdaten {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Ungültige Mission {0}.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Ungültiges Modul {0}.' INVALID_MULTIPLIER: '&c&lError | &7Ungültiger Multiplikator {0}.' INVALID_PAGE: '&c&lError | &7Ungültige Seite {0}.' INVALID_PERCENTAGE: '&c&lError | &7Der Prozentsatz muss zwischen 0 und 100 liegen.' INVALID_PLAYER: '&c&lError | &7Kann keinen Spieler namens {0} finden' INVALID_RATE: |- &c&lFehler | &7Keine Bewertung mit dem Namen {0} gefunden. &c&lFehler | &7Inselbewertungen: {1} INVALID_ROWS: '&c&lError | &7Ungültige Anzahl von Zeilen: {0}' INVALID_ROLE: |- &c&lFehler | &7Die Inselrolle {0} konnte nicht gefunden werden. &c&lFehler | &7Inselrollen: {1} INVALID_SCHEMATIC: '&c&lError | &7Die Shematic mit dem Namen {0} konnte nicht gefunden werden.' INVALID_SETTINGS: |- &c&lFehler | &7Die Inseleinstellungen {0} konnten nicht gefunden werden. &c&lFehler | &7Inseleinstellungen: {1} INVALID_SIZE: '&c&lError | &7Ungültige Größe {0}.' INVALID_SLOT: '&c&lError | &7Ungültiger Slot {0}.' INVALID_TITLE: '&c&lError | &7Ungültigen Titel eingegeben.' INVALID_TOGGLE_MODE: '&c&lFehler | &7Kann {0} nicht umschalten.' INVALID_UPGRADE: |- &c&lFehler | &7Ein Upgrade namens {0} konnte nicht gefunden werden. &c&lFehler | &7Upgrades: {1} INVALID_VISIT_LOCATION: '&c&lFehler | &7Diese Insel hat keinen Besucherstandort.' INVALID_VISIT_LOCATION_BYPASS: '&7&oDu hast den Bypass-Modus, der dich auf die Insel teleportiert...' INVALID_WARP: '&c&lError | &7Ungültiger Warp {0}.' INVALID_WORLD: '&c&lError | &7Ungültige Welt {0}.' INVITE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat {1} auf die Insel eingeladen.' INVITE_BANNED_PLAYER: '&c&lError | &7Dieser Spieler ist von der Insel gesperrt und kann nicht eingeladen werden.' INVITE_TO_FULL_ISLAND: '&c&lError | &7Du kannst keine weiteren Mitglieder auf Ihre Insel einladen.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lError | &7Eine Insel mit diesem Namen existiert bereits.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBank | &7Inselbank ist leer.' ISLAND_BANK_SHOW: '&e&lBank | &7Deine Insel hat ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBank | Die Insel von &7{0} hat ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBank | &7Die Insel {0} hat ${1}.' ISLAND_BEING_CALCULATED: '&c&lError | &7Du kannst nicht mit Blöcken interagieren, wenn die Insel neu berechnet wird!' ISLAND_CLOSED: '&e&lInsel | &7Die Insel wurde erfolgreich für die Öffentlichkeit geschlossen.' ISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7Du hast eine bereits laufende Inselerstellungsaufgabe.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lInsel | &7Deine Anfrage wird bearbeitet...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lFly | &7Inselflug wurde automatisch &cdeaktiviert&7.' ISLAND_FLY_ENABLED: '&e&lFly | &7Inselflug wurde automatisch &aktiviert&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lInsel | &7&oDu warst auf einer Insel, die aufgelöst wurde, also wurdest du zurück zum Spawn teleportiert...' ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lInsel | &7&oDu warst auf einer Insel, die PvP aktiviert hatte, also wurdest du zurück zum Spawnen teleportiert...' ISLAND_HELP_FOOTER: '&e&lSkyblock &7Entwickelt von einem Entwickler' ISLAND_HELP_HEADER: '&e&lSkyblock &7Befehlsliste [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Verwende /is help {0} für die nächste Seite.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lInsel | &7Banklimit: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: |- &e&lInsel | &7Blockgrenzen: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lInsel | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lInsel | &7Coop-Limit: {0}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lInsel | &7Crops-Multiplikator: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lInsel | &7Tropfen-Multiplikator: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: |- &e&lInsel | &7Inseleffekte: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lInsel | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: |- &e&lInsel | &7Entity Grenze: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lInsel | &7 {0}: {1}' ISLAND_INFO_ADMIN_GENERATOR_RATES: |- &e&lInsel | &7Generator Preise ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lInsel | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: |- &e&lInsel | &7Rollenbeschränkungen: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lInsel | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lInsel | &7Insel Größe: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lInsel | &7Spawner-Multiplikator: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lInsel | &7Teamlimit: {0}' ISLAND_INFO_ADMIN_UPGRADES: |- &e&lInsel | &7Upgrades: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lInsel | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lInsel | &7Warps-Limit: {0}' ISLAND_INFO_BANK: '&e&lInsel | &7Bank: {0}' ISLAND_INFO_BONUS: '&e&lInsel | &7Wert-Bonus: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lInsel | &7Level Bonus: {0}' ISLAND_INFO_CREATION_TIME: '&e&lInsel | &7Erstellungszeit: {0}' ISLAND_INFO_DISCORD: '&e&lInsel | &7Discord: {0}' ISLAND_INFO_FOOTER: Citycrafting ISLAND_INFO_HEADER: Servernetzwerk seit 2020 ISLAND_INFO_LAST_TIME_UPDATED: '&e&lInsel | &7Letzte Aktualisierung: vor {0}' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lInsel | &7Letzte Aktualisierung: &aDerzeit aktiv' ISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}' ISLAND_INFO_LOCATION: '&e&lInsel | &7Heimat: {0}' ISLAND_INFO_NAME: '&e&lInsel | &7Name: {0}' ISLAND_INFO_OWNER: '&e&lIsland | &7Besitzer: {0}' ISLAND_INFO_PAYPAL: '&e&lInsel | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lInsel | &7 - {0}' ISLAND_INFO_RATE: '&e&lInsel | &7Rate: {0} &7({1}/5) - {2} Gesamtbewertungen.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: ✦ ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: |- &e&lInsel | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lInsel | &7Besucheranzahl: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lInsel | &7Wert: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsland | &7Die Insel wurde erfolgreich der Öffentlichkeit zugänglich gemacht.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVorschau | &7Du hast sich zu weit entfernt und befindest dich nicht mehr im Vorschaumodus.' ISLAND_PREVIEW_CANCEL: '&e&lVorschau | &7Du hast den Vorschaumodus abgebrochen.' ISLAND_PREVIEW_CONFIRM_TEXT: 'BESTÄTIGEN' ISLAND_PREVIEW_CANCEL_TEXT: 'ABBRECHEN' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lVorschau | &7Du hast den Vorschaumodus für den Schaltplan {0} gestartet. &e&lVorschau | &7Gebe &a&lBESTÄTIGEN &7 ein, um eine neue Insel zu erstellen, oder &c&lABBRECHEN &7, um den Vorschaumodus abzubrechen. &e&lVorschau | &7Du kannst das Inselgebiet nicht verlassen, sonst wird der Vorschaumodus automatisch abgebrochen. ISLAND_PROTECTED: '&c&lError | &7Diese Insel ist geschützt.' ISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lInsel | &7Mitglieder von {0}´s Insel &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)' ISLAND_TEAM_STATUS_ONLINE: '&a(Online)' ISLAND_TEAM_STATUS_ROLES: '&e&lInsel | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Offline)' ISLAND_TOP_STATUS_ONLINE: '&a(Online)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Privat]' ISLAND_WAS_CLOSED: '&e&lInsel | &7&oDie Insel, auf der du warst, wurde geschlossen und du wurdest zurück zum Spawnen teleportiert...' ISLAND_WORTH_ERROR: '&c&lError | &7Bei der Berechnung Ihrer Insel ist ein unerwarteter Fehler aufgetreten. Wende dich an die Administratoren, wenn das Problem weiterhin besteht.' ISLAND_WORTH_RESULT: '&e&lInsel | &7Dein Inselwert ist {0} [Level {1}]' ISLAND_WORTH_TIME_OUT: '&c&lFehler | &7Die Berechnungstask ist abgelaufen. Versuche es später noch einmal...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lInsel | &7{0} ist deiner Insel beigetreten.' JOIN_ANNOUNCEMENT: '&e&lInsel | &7{0} ist deiner Insel beigetreten.' JOIN_FULL_ISLAND: '&c&lError | &7Diese Insel hat die maximal zulässige Anzahl von Mitgliedern erreicht.' JOIN_WHILE_IN_ISLAND: '&c&lError | &7Du befindest dich bereits auf einer Insel.' JOINED_ISLAND: '&e&lInsel | &7Du bist der Insel von {0} beigetreten.' JOINED_ISLAND_NAME: '&e&lInsel | &7Sie sind der Insel {0} beigetreten.' JOINED_ISLAND_AS_COOP: '&e&lIsland | &7Du bist jetzt ein Koop-Mitglied auf der Insel von {0}.' JOINED_ISLAND_AS_COOP_NAME: '&e&lInsel | &7Du bist jetzt ein Koop-Mitglied der Insel {0}.' KICK_ANNOUNCEMENT: '&e&lInsel | &7{0} wurde von {1} von der Insel geworfen.' KICK_ISLAND_LEADER: '&c&lError | &7Du kannst den Besitzer der Insel nicht kicken, verwende stattdessen /is admin disband.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Du kannst nur Spieler mit einer niedrigeren Inselrolle als deiner kicken.' LACK_CHANGE_PERMISSION: '&c&lError | &7Du musst diese Berechtigung haben, um sie in andere Rollen zu ändern.' LAST_ROLE_DEMOTE: '&c&lError | &7Du kannst diesen Spieler nicht mehr zurückstufen.' LAST_ROLE_PROMOTE: '&c&lError | &7Du kannst diesen Spieler nicht mehr befördern.' LEAVE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat die Insel verlassen.' LEAVE_ISLAND_AS_LEADER: |- &c&lFehler | &7Du kannst deine Insel nicht verlassen, wenn sie dir gehört. &c&lFehler | &7Du kannst das Eigentum mit /is transfer übertragen. LEFT_ISLAND: '&e&lInsel | &7Du hast deine Insel verlassen.' LEFT_ISLAND_COOP: '&e&lInsel | &7Du bist kein Koop-Mitglied mehr auf der Insel von {0}.' LEFT_ISLAND_COOP_NAME: '&e&lInsel | &7Du bist kein Genossenschaftsmitglied der Insel {0} mehr.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lError | &7Du musst festes Material bereitstellen.' MAXIMUM_LEVEL: '&c&lError | &7Die maximale Stufe für dieses Upgrade ist {0}.' MESSAGE_SENT: '&e&lIsland | &7Die Nachricht wurde erfolgreich an {0} gesendet!' MISSION_CANNOT_COMPLETE: '&c&lError | &7Du kannst diese Mission noch nicht abschließen.' MISSION_NO_AUTO_REWARD: '&e&lMission | &7Du hast alle erforderlichen Materialien, um {0} abzuschließen - verwende /is missions, um sie abzuschließen!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lError | &7Du musst {0} abschließen, bevor du diese Mission abschließen kannst.' MISSION_STATUS_COMPLETE: '&e&lMission | &7Der Status der Mission {0} wurde für {1} in "Abgeschlossen" geändert.' MISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Der Status aller Missionen wurde auf abgeschlossen für {0} geändert.' MISSION_STATUS_RESET: '&e&lMission | &7Setze den Status der Mission {0} für {1} zurück.' MISSION_STATUS_RESET_ALL: '&e&lMission | &7Setze den Status aller Missionen für {0} zurück.' MODULE_ALREADY_INITIALIZED: '&e&lModule | &7Dieses Modul ist bereits geladen.' MODULE_INFO: |- &e&lModul | &7{0} von {1} &e&lModul | &7&m-------------------- &e&lModul | &7{2} MODULE_LOADED_SUCCESS: '&e&lModule | &7Das Modul {0} wurde erfolgreich geladen.' MODULE_LOADED_FAILURE: '&e&lModule | &7Das Modul {0} konnte nicht geladen werden. Weitere Informationen finden Sie in der Konsole.' MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Das Modul wurde erfolgreich entladen.' MODULES_LIST: '&fModule ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lInsel | &7{0} hat seinen Inselnamen in {1}&7 geändert.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lError | &7Du kannst diesen Namen nicht verwenden.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lFehler | &7Du kannst keine Spielernamen als Inselnamen verwenden.' NAME_TOO_LONG: '&c&lError | &7Inselnamen dürfen nicht länger als {0} Zeichen sein.' NAME_TOO_SHORT: '&c&lError | &7Inselnamen dürfen nicht kürzer als {0} Zeichen sein.' NO_BAN_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler zu bannen.' NO_CLOSE_BYPASS: '&c&lError | &7Diese Insel ist nicht für die Öffentlichkeit zugänglich.' NO_CLOSE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Insel für die Öffentlichkeit zu schließen.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler als Koop-Mitglieder hinzuzufügen.' NO_DELETE_WARP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Warps zu löschen.' NO_DEMOTE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler herabstufen zu können.' NO_DEPOSIT_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Geld auf die Inselbank einzuzahlen.' NO_DISBAND_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Ihre Insel aufzulösen.' NO_EXPEL_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler von deiner Insel zu vertreiben.' NO_INVITE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler einzuladen.' NO_ISLAND_CHEST_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um auf die Truhe der Insel zugreifen zu können.' NO_ISLAND_INVITE: '&c&lError | &7Es konnten keine Einladungen von dieser Insel gefunden werden.' NO_ISLANDS_TO_PURGE: '&c&lError | &7Es gab keine Inseln zum Säubern.' NO_KICK_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler zu kicken.' NO_MORE_DISBANDS: '&c&lError | &7Du kannst keine Inseln mehr auflösen.' NO_MORE_WARPS: '&c&lError | &7Ihre Insel kann keine Warps mehr haben.' NO_NAME_PERMISSION: '&c&lError | &7Sie können den Namen Ihrer Insel nicht ändern.' NO_OPEN_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Insel für die Öffentlichkeit zugänglich zu machen.' NO_PERMISSION_CHECK_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Informationen über Berechtigungen zu erhalten.' NO_PROMOTE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler zu befördern.' NO_RANKUP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Upgrades aufzuwerten.' NO_RATINGS_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Bewertungen zu überprüfen.' NO_SET_BIOME_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um das Inselbiom zu ändern.' NO_SET_DISCORD_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Inseldisharmonie zu ändern.' NO_SET_HOME_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um den Teleportort der Insel festzulegen.' NO_SET_PAYPAL_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Paypal-E-Mail-Adresse der Insel zu ändern.' NO_SET_ROLE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Rollen für Spieler festzulegen.' NO_SET_SETTINGS_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Inseleinstellungen zu ändern.' NO_SET_WARP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Island Warps zu setzen.' NO_TRANSFER_PERMISSION: '&c&lError | &7Du musst der Anführer der Insel sein, um die Führung zu übertragen.' NO_UNCOOP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler aus Koop-Mitgliedern zu entfernen.' NO_UPGRADE_PERMISSION: '&c&lError | &7Sie haben nicht die Berechtigung zum Upgrade auf eine andere Ebene.' NO_WITHDRAW_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Geld von der Inselbank abzuheben.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lError | &7Du hast nicht genug Geld, um {0} Dollar auf die Bank Ihrer Insel einzuzahlen.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lError | &7Du hast nicht genug Geld.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7Du hast nicht genug Geld, um Island Warps zu benutzen.' OPEN_MENU_WHILE_SLEEPING: '&7&oDu´ bist zu müde, um mit Menüs zu interagieren, findest du nicht auch?' PANEL_TOGGLE_OFF: |- &e&lPanel | &7Inselpanel umgeschaltet &cOFF&7. &e&lPanel | &7Das Ausführen von /is wird dich zur Insel teleportieren. PANEL_TOGGLE_ON: |- &e&lPanel | &7Inselpanel umgeschaltet &aON&7. &e&lPanel | &7Ausführen von /is öffnet das GUI. PERMISSION_CHANGED: '&e&lInsel | &7Die Berechtigung {0} der Insel von {1} wurde erfolgreich aktualisiert.' PERMISSION_CHANGED_NAME: '&e&lInsel | &7Die Berechtigung {0} der Insel {1} ​​wurde erfolgreich aktualisiert.' PERMISSION_CHANGED_ALL: '&e&lInsel | &7Die Berechtigung {0} für alle Inseln erfolgreich aktualisiert.' PERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.' PERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lInsel | &7Alle Berechtigungen für {0} erfolgreich auf Standardwerte zurückgesetzt!' PERMISSIONS_RESET_ROLES: '&e&lInsel | &7Alle Berechtigungen der Insel erfolgreich auf Standardwerte zurücksetzen!' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Yes' PLAYER_ALREADY_BANNED: '&c&lFehler | &7Dieser Spieler ist bereits gesperrt.' PLAYER_ALREADY_COOP: '&c&lError | &7Dieser Spieler ist bereits kooperativ.' PLAYER_ALREADY_IN_ISLAND: '&c&lError | &7Dieser Spieler befindet sich bereits auf einer Insel.' PLAYER_ALREADY_IN_ROLE: '&c&lFehler | &7{0} ist bereits ein {1}.' PLAYER_EXPEL_BYPASS: '&c&lError | &7Dieser Benutzer kann nicht von der Insel ausgeschlossen werden.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lIsland | &7{0} ist dem Server beigetreten.' PLAYER_NOT_BANNED: '&c&lFehler | &7Dieser Spieler ist nicht gesperrt.' PLAYER_NOT_COOP: '&c&lError | &7Dieser Spieler ist nicht kooperativ.' PLAYER_NOT_INSIDE_ISLAND: '&c&lError | &7Dieser Spieler befindet sich nicht auf deiner Insel.' PLAYER_NOT_ONLINE: '&c&lError | &7Dieser Spieler ist nicht online!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lInsel | &7{0} hat den Server verlassen.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lFehler | &7Du kannst nur Spieler befördern, die eine niedrigere Inselrolle als deine haben.' PROMOTED_MEMBER: '&e&lIsland | &7Du hast {0} zu einem {1} auf seiner Insel befördert.' PURGE_CLEAR: '&e&lIsland | &7Alle Inseln in der Warteschlange zum Löschen erfolgreich gelöscht.' PURGED_ISLANDS: |- &e&lIsland | &7{0} islands will be purged when server restarts. &e&lIsland | &7You can cancel it anytime using /is admin purge cancel. RANKUP_SUCCESS: '&e&lIsland | &7Das Upgrade-Level {0} für die Insel von {1} wurde erfolgreich aktualisiert.' RANKUP_SUCCESS_ALL: '&e&lInsel | &7Das Upgrade-Level {0} für alle Inseln erfolgreich aktualisiert.' RANKUP_SUCCESS_NAME: '&e&lInsel | &7Die Aktualisierungsstufe {0} für {1} wurde erfolgreich aktualisiert.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat deine Insel mit {1} von 5 Punkten bewertet!.' RATE_CHANGE_OTHER: '&e&lInsel | &7Du hast die Bewertung von {0} in {1} geändert.' RATE_OWN_ISLAND: '&c&lError | &7Du kannst deine eigene Insel nicht bewerten.' RATE_REMOVE_ALL: '&e&lInsel | &7Alle Bewertungen von {0} wurden erfolgreich entfernt.' RATE_REMOVE_ALL_ISLANDS: '&e&lInsel | &7Alle Bewertungen aller Inseln wurden erfolgreich entfernt.' RATE_SUCCESS: '&e&lInsel | &7Du hast diese Insel mit {0} Sternen bewertet!' REACHED_BLOCK_LIMIT: '&e&lUpgrades | &7Du hast das Limit der Insel für {0} Block erreicht.' REACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.' RECALC_ALREADY_RUNNING: '&c&lError | &7Deine Insel wird bereits neu berechnet.' RECALC_ALREADY_RUNNING_OTHER: '&c&lFehler | &7Diese Insel wird bereits neu berechnet.' RECALC_ALL_ISLANDS: '&e&lInsel | &7Alle Inseln neu berechnen...' RECALC_ALL_ISLANDS_DONE: '&e&lInsel | &7Neuberechnung aller Inseln erfolgreich abgeschlossen.' RECALC_PROCCESS_REQUEST: '&e&lInsel | &7Deine Anfrage wird bearbeitet...' RELOAD_COMPLETED: '&e&lInsel | &7Neuladen ist beendet!' RELOAD_PROCCESS_REQUEST: '&e&lInsel | &7Starte das Neuladen von Konfigurationen...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat die Einladung von {1} auf die Insel widerrufen.' RESET_WORLD_SUCCEED: '&e&lInsel | &7Die Welt {0} für die Insel von {1} erfolgreich zurückgesetzt.' RESET_WORLD_SUCCEED_ALL: '&e&lInsel | &7Die Welt {0} für alle Inseln erfolgreich zurückgesetzt.' RESET_WORLD_SUCCEED_NAME: '&e&lInsel | &7Die Welt {0} für {1} erfolgreich zurückgesetzt.' SAME_NAME_CHANGE: '&c&lError | &7Du musst einen anderen Namen als dein aktuellen Inselnamen eingeben.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Ausgewählte Position #2 ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lError | &7Du hast keine zwei Stellen ausgewählt.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Deine Anfrage wird bearbeitet...' SCHEMATIC_READY_TO_CREATE: | &e&lSchematics | &7You have selected two positions. Run /is admin schematic to create a new schematic. &e&lSchematics | &7Make sure you stand at the teleportion location when executing the command. SCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Ausgewählte Position Nr. 1 ({0})' SCHEMATIC_SAVED: '&e&lSchematics | &7Schaltplan erfolgreich gespeichert!' SELF_ROLE_CHANGE: '&c&lError | &7Du kannst deine Rolle nicht ändern.' SET_UPGRADE_LEVEL: '&e&lUpgrades | &7Die Ebene von {0} für die Insel von {1} wurde erfolgreich aktualisiert.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Die Ebene von {0} für {1} wurde erfolgreich aktualisiert.' SET_WARP: '&e&lInsel | &7Erzeugt erfolgreich einen neuen Warp am {0}.' SET_WARP_OUTSIDE: '&c&lError | &7Du kannst keine Warps außerhalb Ihrer Insel setzen.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich auf die Insel von {1} aktualisiert.' SETTINGS_UPDATED_NAME: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich auf die Insel {1} ​​aktualisiert.' SETTINGS_UPDATED_ALL: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich für alle Inseln aktualisiert.' SIZE_BIGGER_MAX: '&c&lError | &7Du kannst keine Größe festlegen, die größer als die maximale Inselgröße ist.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Erfolgreich teleportiert {0} zum Spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Der Spawn-Speicherort wurde erfolgreich auf {0} aktualisiert.' SPY_TEAM_CHAT_FORMAT: '&7[Spion] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lUpgrades | &7Alle Upgrade-Werte der Insel von {0} wurden erfolgreich synchronisiert.' SYNC_UPGRADES_ALL: '&e&lUpgrades | &7Alle Upgrade-Werte aller Inseln erfolgreich synchronisiert.' SYNC_UPGRADES_NAME: '&e&lUpgrades | &7Alle Upgrade-Werte von {0} wurden erfolgreich synchronisiert.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lError | &7Du befindest dich nicht auf deiner Insel.' TELEPORT_OUTSIDE_ISLAND: '&c&lError | &7Du kannst dich nicht außerhalb Ihres Schutzbereichs teleportieren.' TELEPORT_WARMUP: '&7&oDu wirst in {0} teleportiert... Nicht bewegen!' TELEPORT_WARMUP_CANCEL: '&7&oDu bist umgezogen und deshalb wurde die Teleportation abgebrochen.' TITLE_SENT: '&e&lIsland | &7Der Titel wurde erfolgreich an {0} gesendet!' TELEPORTED_FAILED: '&e&lIsland | &7Anscheinend hat diese Insel keine sicheren Blöcke. Bitte wenden dich an einen Supporter.' TELEPORTED_SUCCESS: '&e&lIsland | &7Du wurdest auf deine Insel teleportiert.' TELEPORTED_TO_WARP: '&e&lInsel | &7Erfolgreich zu diesem Inselwarp teleportiert.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lInsel | &7Der Spieler {0} hat sich zum Inselwarp {1} teleportiert.' TOGGLED_BYPASS_OFF: '&e&lBypass | &7Umgehungsmodus &cOFF&7 umgeschaltet.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Umgehungsmodus &aON&7 umgeschaltet.' TOGGLED_FLY_OFF: '&e&lFly | &7Inselflug umgeschaltet &cOFF&7.' TOGGLED_FLY_ON: '&e&lFly | &7Inselflug umgeschaltet &aON&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Schematicsmodus &cOFF&7 umschalten.' TOGGLED_SCHEMATIC_ON: |- &e&lSchaltpläne | &7Schematicsmodus umschalten &aON&7. &e&lSchaltpläne | &7Wähle einen Bereich mit einer goldenen Axt aus. TOGGLED_SPY_OFF: '&e&lSpy | &7Spionage-Chat umgeschaltet &cOFF&7.' TOGGLED_SPY_ON: '&e&lSpy | &7Spionage-Chat umgeschaltet &aON&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Blöcke Stacker &cOFF&7 umschalten.' TOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Blöcke Stacker &aON&7 umschalten.' TOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Teamchat umschalten &cOFF&7.' TOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Teamchat umschalten &aON&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lGrenze | &7Umschalten der Weltgrenze &cOFF&7.' TOGGLED_WORLD_BORDER_ON: '&e&lGrenze | &7Umschalten der Weltgrenze &aON&7.' TRANSFER_ADMIN: '&e&lInsel | &7Du hast die Führung von {0} an {1} übertragen.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lError | &7{0} ist bereits der Anführer seiner Insel.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lError | &7Diese Spieler sind nicht auf den selben Inseln.' TRANSFER_ADMIN_NOT_LEADER: '&c&lError | &7Dieser Spieler ist kein Anführer einer Insel.' TRANSFER_ALREADY_LEADER: '&c&lError | &7Du bist bereits der Anführer dieser Insel.' TRANSFER_BROADCAST: '&e&lInsel | &7Die Führung der Insel wurde auf {0} übertragen.' UNBAN_ANNOUNCEMENT: '&e&lInsel | &7{0} wurde von {1} von der Insel ENTFERNT.' UNCOOP_ANNOUNCEMENT: '&e&lInsel | &7{0} hat {1} als Genossenschaftsmitglied entfernt.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lInsel | &7{0} hat das Spiel verlassen und ist kein Koop-Mitglied mehr.' UNIGNORED_ISLAND: '&e&lInsel | Die Insel von &7{0} wird jetzt nicht mehr von den Top-Inseln ignoriert.' UNIGNORED_ISLAND_NAME: '&e&lInsel | &7Die Insel {0} wird jetzt von den Top-Inseln nicht mehr ignoriert.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lInsel | &7&oAnscheinend ist dieser Warp unsicher. Bitte versuche es mit einem anderen Warp.' UPDATED_PERMISSION: '&e&lInsel | &7Aktualisierte Berechtigungen für {0}.' UPDATED_SETTINGS: '&e&lInsel | &7Die Inseleinstellungen {0} aktualisiert.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7Du kannst erst in {0} erneut ein Upgrade durchführen.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lError | &7Du kannst diesen Befehl nicht auf anderen Inseln verwenden.' WARP_ALREADY_EXIST: '&c&lError | &7Es existiert bereits ein Warp mit diesem Namen.' WARP_CATEGORY_ICON_NEW_LORE: |- &e&lWarps | &7Gebe eine neue Beschreibung ein (Gebe "-cancel" ein, um abzubrechen): &e&lWarps | &7Du kannst Zeilen mit "\n" trennen. WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Gebe einen Namen ein (gebe "-cancel" ein, um abzubrechen):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Gebe eine neue Materialart ein (Gebe "-cancel" ein, um abzubrechen):' WARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Das Symbol der Kategorie wurde erfolgreich aktualisiert.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lFehler | &7Du kannst nur alphabetische Buchstaben, Zahlen und ''_'' für Warp-Kategorienamen verwenden.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.' WARP_CATEGORY_SLOT: '&e&lWarps | &7Gebe einen neuen Slot ein (Gebe "-cancel" ein, um abzubrechen):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lFehler | &7Dieser Slot ist bereits von einer anderen Kategorie belegt.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Der Slot der Kategorie wurde erfolgreich in {0} geändert.' WARP_CATEGORY_RENAME: '&e&lWarps | &7Gebe einen neuen Namen ein (gebe zum Abbrechen "-cancel" ein):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lFehler | &7Dieser Name wird bereits von einer anderen Kategorie verwendet.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Die Kategorie wurde erfolgreich in {0} umbenannt.' WARP_ICON_NEW_LORE: | &e&lWarps | &7Gebe eine neue Beschreibung ein (Gebe "-cancel" ein, um abzubrechen): &e&lWarps | &7Du kannst Zeilen mit "\n" trennen. WARP_ICON_NEW_NAME: '&e&lWarps | &7Gebe einen Namen ein (gebe "-cancel" ein, um abzubrechen):' WARP_ICON_NEW_TYPE: '&e&lWarps | &7Gebe eine neue Materialart ein (Gebe "-cancel" ein, um abzubrechen):' WARP_ICON_UPDATED: '&e&lWarps | &7Das Warp-Icon wurde erfolgreich aktualisiert.' WARP_ILLEGAL_NAME: '&c&lError | &7Du kannst nur alphabetische Buchstaben, Zahlen und ''_'' für Warp-Namen verwenden.' WARP_LOCATION_UPDATE: '&e&lWarps | &7Der Standort des Warps wurde erfolgreich auf deinen Standort aktualisiert.' WARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.' WARP_PUBLIC_UPDATE: '&e&lWarps | &7Der Warp wurde erfolgreich für die Öffentlichkeit geöffnet.' WARP_PRIVATE_UPDATE: '&e&lWarps | &7Der Warp wurde erfolgreich für die Öffentlichkeit geschlossen.' WARP_RENAME: '&e&lWarps | &7Gebe einen neuen Namen ein (gebe zum Abbrechen "-cancel" ein):' WARP_RENAME_ALREADY_EXIST: '&c&lFehler | &7Dieser Name wird bereits von einem anderen Warp verwendet.' WARP_RENAME_SUCCESS: '&e&lWarps | &7Der Warp wurde erfolgreich in {0} umbenannt.' WITHDRAW_ALL_MONEY: |- &e&lBank | &7Insel Bank hat nur {0} Dollar drin. &e&lBank | &7&oAlles Geld abheben..." WITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} withdrawn ${1} from the island bank!' WITHDRAW_ERROR: '&c&lError | &7{0}.' WITHDRAWN_MONEY: '&e&lBank | &7You withdrawn ${0} from {1}''s island bank!' WITHDRAWN_MONEY_NAME: '&e&lBank | &7Du hast ${0} von der Inselbank von {1} abgehoben!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lWorlds | &7Die Welt {0} ist noch nicht freigeschaltet!' ================================================ FILE: src/main/resources/lang/en-US.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # You can find a tutorial about configuring messages here: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lIsland | &7Successfully added the player {0} to {1}''s island.' ADMIN_ADD_PLAYER_NAME: '&e&lIsland | &7Successfully added the player {0} to the island {1}.' ADMIN_DEPOSIT_MONEY: '&e&lBank | &7You deposited ${0} into {1}''s island bank.' ADMIN_DEPOSIT_MONEY_NAME: '&e&lBank | &7You deposited ${0} into the bank of the island {1}.' ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Developed by Ome_R' ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Admin Commands List [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Use /is admin {0} for the next page.' ALREADY_IN_ISLAND: '&c&lError | &7You are already in an island.' ALREADY_IN_ISLAND_OTHER: '&c&lError | &7This player is already a member of your island.' BAN_ANNOUNCEMENT: '&e&lIsland | &7{0} was BANNED from the island by {1}.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7You can only ban players with a lower island role than yours.' BANK_DEPOSIT_CUSTOM: '&e&lBank | &7Type the amount you want to deposit:' BANK_DEPOSIT_COMPLETED: 'Deposit Completed' BANK_LIMIT_EXCEED: '&c&lError | &7You have exceeded your bank limit.' BANK_WITHDRAW_CUSTOM: '&e&lBank | &7Type the amount you want to withdraw:' BANK_WITHDRAW_COMPLETED: 'Withdraw Completed' BANNED_FROM_ISLAND: '&c&lError | &7You are banned from this island.' BLOCK_COUNT_CHECK: '&e&lIsland | &7This island has x{0} {1}.' BLOCK_COUNTS_CHECK: | &e&lIsland | &7This island has the following blocks: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lIsland | &7This island has no tracked blocks.' BLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}' BLOCK_LEVEL: '&e&lLevel | &7The block {0}''s level is {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7The block {0} is worthless.' BLOCK_VALUE: '&e&lWorth | &7The block {0} worth {1}.' BLOCK_VALUE_WORTHLESS: '&e&lWorth | &7The block {0} is worthless.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Blue' BORDER_PLAYER_COLOR_NAME_RED: 'Red' BORDER_PLAYER_COLOR_NAME_GREEN: 'Green' BORDER_PLAYER_COLOR_UPDATED: '&e&lBorder | &7Successfully changed your personal border color to {0}.' BUILD_OUTSIDE_ISLAND: '&c&lError | &7You cannot build outside of your protection range.' CANNOT_SET_ROLE: '&c&lError | &7You cannot set the player''s role to {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lError | &7You can only change permissions to lower island role than yours.' CHANGED_BANK_LIMIT: '&e&lUpgrades | &7Successfully updated the bank limit of {0}''s island.' CHANGED_BANK_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the bank limit of all the islands.' CHANGED_BANK_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the bank limit of {0}.' CHANGED_BIOME: '&e&lIsland | &7Successfully changed biome to {0}. You might need to reconnect to the server to see changes.' CHANGED_BIOME_ALL: '&e&lIsland | &7Successfully changed biome to {0} for all the islands.' CHANGED_BIOME_NAME: '&e&lIsland | &7Successfully changed biome to {0} for the island {1}.' CHANGED_BIOME_OTHER: '&e&lIsland | &7Successfully changed biome to {0} for {1}''s island.' CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Successfully changed the block amount at {0} to {1}.' CHANGED_BLOCK_LIMIT: '&e&lUpgrades | &7Successfully updated the {0} Block limit of {1}''s island.' CHANGED_BLOCK_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the {0} Block limit of all the islands.' CHANGED_BLOCK_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the {0} Block limit of {1}.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}''s island.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for all the islands.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}.' CHANGED_COOP_LIMIT: '&e&lUpgrades | &7Successfully updated the coop players limit of {0}''s island.' CHANGED_COOP_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the coop players limit of all the islands.' CHANGED_COOP_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the coop players limit of {0}.' CHANGED_CROP_GROWTH: '&e&lUpgrades | &7Successfully updated the crop growth multiplier of {0}''s island.' CHANGED_CROP_GROWTH_ALL: '&e&lUpgrades | &7Successfully updated the crop growth multiplier of all the islands.' CHANGED_CROP_GROWTH_NAME: '&e&lUpgrades | &7Successfully updated the crop growth multiplier of {0}.' CHANGED_DISCORD: '&e&lIsland | &7Successfully changed island discord to {0}.' CHANGED_ENTITY_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for {1}''s island.' CHANGED_ENTITY_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for all the islands.' CHANGED_ENTITY_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for {1}.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for {1}''s island.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for all the islands.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for {1}.' CHANGED_ISLAND_SIZE: '&e&lUpgrades | &7Successfully updated the island size of {0}''s island.' CHANGED_ISLAND_SIZE_ALL: '&e&lUpgrades | &7Successfully updated the island size of all the islands.' CHANGED_ISLAND_SIZE_NAME: '&e&lUpgrades | &7Successfully updated the island size of {0}.' CHANGED_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.' CHANGED_LANGUAGE: '&e&lLanguage | &7Successfully changed your language to English.' CHANGED_MOB_DROPS: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of {0}''s island.' CHANGED_MOB_DROPS_ALL: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of all the islands.' CHANGED_MOB_DROPS_NAME: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of {0}.' CHANGED_NAME: '&e&lIsland | &7You changed your island''s name to {0}&7.' CHANGED_NAME_OTHER: '&e&lIsland | &7You changed the {0} island''s name to {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lIsland | &7You changed the name of {0}&7 to {1}&7.' CHANGED_PAYPAL: '&e&lIsland | &7Successfully changed island paypal to {0}.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.' CHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}.' CHANGED_SPAWNER_RATES: '&e&lUpgrades | &7Successfully updated the spawner rates multiplier of {0}''s island.' CHANGED_SPAWNER_RATES_ALL: '&e&lUpgrades | &7Successfully updated the spawner rates multiplier of all the islands.' CHANGED_SPAWNER_RATES_NAME: '&e&lUpgrades | &7Successfully updated the spawner rates multiplier of {0}.' CHANGED_TEAM_LIMIT: '&e&lUpgrades | &7Successfully updated the team limit of {0}''s island.' CHANGED_TEAM_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the team limit of all the islands.' CHANGED_TEAM_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the team limit of {0}.' CHANGED_TELEPORT_LOCATION: '&e&lIsland | &7Successfully updated teleport location.' CHANGED_WARPS_LIMIT: '&e&lUpgrades | &7Successfully updated the warps limit of {0}''s island.' CHANGED_WARPS_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the warps limit of all the islands.' CHANGED_WARPS_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the warps limit of {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'amount' COMMAND_ARGUMENT_BIOME: 'biome' COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'command...' COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: 'potion-effect' COMMAND_ARGUMENT_EMAIL: 'email' COMMAND_ARGUMENT_ENTITY: 'entity' COMMAND_ARGUMENT_ISLAND_NAME: 'island-name' COMMAND_ARGUMENT_ISLAND_ROLE: 'island-role' COMMAND_ARGUMENT_LEADER: 'leader' COMMAND_ARGUMENT_LEVEL: 'level' COMMAND_ARGUMENT_LIMIT: 'limit' COMMAND_ARGUMENT_MATERIAL: 'material' COMMAND_ARGUMENT_MENU: 'menu-name' COMMAND_ARGUMENT_MESSAGE: 'message...' COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: 'mission-name' COMMAND_ARGUMENT_MODULE_NAME: 'module-name' COMMAND_ARGUMENT_MULTIPLIER: 'multiplier' COMMAND_ARGUMENT_NAME: 'name' COMMAND_ARGUMENT_NEW_LEADER: 'new-leader' COMMAND_ARGUMENT_PAGE: 'page' COMMAND_ARGUMENT_PATH: 'path' COMMAND_ARGUMENT_PERMISSION: 'permission' COMMAND_ARGUMENT_PLAYER_NAME: 'player-name' COMMAND_ARGUMENT_PRIVATE: 'private' COMMAND_ARGUMENT_RATING: 'rating' COMMAND_ARGUMENT_ROWS: 'rows' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'schematic-name' COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'settings' COMMAND_ARGUMENT_SIZE: 'size' COMMAND_ARGUMENT_TIME: 'time' COMMAND_ARGUMENT_TITLE_DURATION: 'duration' COMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in' COMMAND_ARGUMENT_TITLE_FADE_OUT: 'fade-out' COMMAND_ARGUMENT_UPGRADE_NAME: 'upgrade-name' COMMAND_ARGUMENT_VALUE: 'value' COMMAND_ARGUMENT_WARP_NAME: 'warp-name' COMMAND_ARGUMENT_WARP_CATEGORY: 'warp-category' COMMAND_ARGUMENT_WORLD: 'world' COMMAND_COOLDOWN_FORMAT: '&c&lError | &7You may only use the command in {0}.' COMMAND_DESCRIPTION_ACCEPT: 'Accept an invitation from a player.' COMMAND_DESCRIPTION_ADMIN: 'Use the admin commands.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Add a user to an island.' COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Increase block limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Add a bonus to a player.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Increase coop players limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Increase the crop growth multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Add an island effect for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Increase entity limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Add percentage of a material for the cobblestone generator.' COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Increase the mob drops multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expand another player''s island size.' COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Increase the spawner rates multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Increase members limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Increase the warps limit of an island.' COMMAND_DESCRIPTION_ADMIN_BONUS: 'Grant a bonus to a player.' COMMAND_DESCRIPTION_ADMIN_BYPASS: 'Toggle bypass mode.' COMMAND_DESCRIPTION_ADMIN_CHEST: 'Open island''s chest of another island.' COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Clear generator rates for a specific island.' COMMAND_DESCRIPTION_ADMIN_CLOSE: 'Close an island to the public.' COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Execute a command for all members of islands.' COMMAND_DESCRIPTION_ADMIN_COUNT: 'Check a block count on a specific island.' COMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.' COMMAND_DESCRIPTION_ADMIN_DEBUG: 'Toggle debug outputs.' COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Delete a warp for an island.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Demote a member in another player''s island.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Deposit money into another player''s island bank.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Disband another player''s island permanently.' COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Give disbands to a player.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignore an island from top islands.' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Join an island without an invitation.' COMMAND_DESCRIPTION_ADMIN_KICK: 'Kick a player from his island.' COMMAND_DESCRIPTION_ADMIN_MODULES: 'Manage modules of the plugin.' COMMAND_DESCRIPTION_ADMIN_MISSION: 'Change the status of a mission for a player.' COMMAND_DESCRIPTION_ADMIN_MSG: 'Send a player a message without any prefixes.' COMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Send to all island members a message without any prefixes.' COMMAND_DESCRIPTION_ADMIN_NAME: 'Change the name of an island.' COMMAND_DESCRIPTION_ADMIN_OPEN: 'Open an island to the public.' COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Open a custom menu for a player.' COMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Promote a member in another player''s island.' COMMAND_DESCRIPTION_ADMIN_PURGE: 'Purge islands.' COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Rankup an upgrade for an island.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Re-calculates the worth of an island.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Reload all configurations and tasks of the plugin.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remove all ratings given by a player.' COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Create schematics for the plugin.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Set the biome of an island.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Set the block amount in a specific location.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Set block limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Set the chest rows for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Set coop players limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Set the crop growth multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Set a player''s amount of island disbands.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Set the island effect level of another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Set entity limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transfer an island to someone else.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Set the mob drops multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Set a required role for a permission for all the islands.' COMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Set the rating of another player.' COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Set role limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Toggle settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Change percentage of a material for the cobblestone generator.' COMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Change another player''s island size.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Set the spawn location of the server.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Set the spawner rates multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Set members limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Set the level of an upgrade for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Set the warps limit of an island.' COMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Open the plugin settings editor.' COMMAND_DESCRIPTION_ADMIN_SHOW: 'Get information about an island.' COMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teleport to the spawn location.' COMMAND_DESCRIPTION_ADMIN_SPY: 'Toggle chat spy mode' COMMAND_DESCRIPTION_ADMIN_STATS: 'Show stats about the plugin.' COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sync upgrade values for an island.' COMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teleport to other islands.' COMMAND_DESCRIPTION_ADMIN_TITLE: 'Send a player a title.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Send to all island members a title.' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Unignore an island from top islands.' COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Unlock a world for an island.' COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Withdraw money from another player''s island bank.' COMMAND_DESCRIPTION_BALANCE: 'Check the amount of money inside an island''s bank.' COMMAND_DESCRIPTION_BAN: 'Ban a player from your island.' COMMAND_DESCRIPTION_BANK: 'Open the island''s bank.' COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: 'Change the biome of the island.' COMMAND_DESCRIPTION_BORDER: 'Change the border color of the islands.' COMMAND_DESCRIPTION_CHEST: 'Open the island''s chest.' COMMAND_DESCRIPTION_CLOSE: 'Close the island to the public.' COMMAND_DESCRIPTION_COOP: 'Add a player as a co-op to your island.' COMMAND_DESCRIPTION_COOPS: 'Open the coops menu.' COMMAND_DESCRIPTION_COUNTS: 'See block counts in your island.' COMMAND_DESCRIPTION_CREATE: 'Create a new island.' COMMAND_DESCRIPTION_DEL_WARP: 'Delete an island warp.' COMMAND_DESCRIPTION_DEMOTE: 'Demote a member in your island.' COMMAND_DESCRIPTION_DEPOSIT: 'Deposit money from your personal account into the island''s bank.' COMMAND_DESCRIPTION_DISBAND: 'Disband your island permanently.' COMMAND_DESCRIPTION_EXPEL: 'Kick a visitor from your island.' COMMAND_DESCRIPTION_FLY: 'Toggle island fly.' COMMAND_DESCRIPTION_HELP: 'List of all commands.' COMMAND_DESCRIPTION_INVITE: 'Invite a player to your island.' COMMAND_DESCRIPTION_KICK: 'Kick a player from your island.' COMMAND_DESCRIPTION_LANG: 'Change your personal language.' COMMAND_DESCRIPTION_LEAVE: 'Leave your island.' COMMAND_DESCRIPTION_MEMBERS: 'Open the members menu.' COMMAND_DESCRIPTION_MISSION: 'Complete a mission.' COMMAND_DESCRIPTION_MISSIONS: 'Open the missions menu.' COMMAND_DESCRIPTION_NAME: 'Change the name of your island.' COMMAND_DESCRIPTION_OPEN: 'Open the island to the public.' COMMAND_DESCRIPTION_PANEL: 'Open island panel.' COMMAND_DESCRIPTION_PARDON: 'Unban a player from your island.' COMMAND_DESCRIPTION_PERMISSIONS: 'Get all permissions for an island role.' COMMAND_DESCRIPTION_PROMOTE: 'Promote a member in your island.' COMMAND_DESCRIPTION_RANKUP: 'Level up an upgrade.' COMMAND_DESCRIPTION_RATE: 'Rate an island.' COMMAND_DESCRIPTION_RATINGS: 'Show all island ratings.' COMMAND_DESCRIPTION_SETTINGS: 'Open the settings menu.' COMMAND_DESCRIPTION_RECALC: 'Re-calculates the island worth.' COMMAND_DESCRIPTION_SET_DISCORD: 'Set the discord of the island for island payouts.' COMMAND_DESCRIPTION_SET_PAYPAL: 'Set the paypal email of the island for island payouts.' COMMAND_DESCRIPTION_SET_ROLE: 'Change the role of a player in your island.' COMMAND_DESCRIPTION_SET_TELEPORT: 'Change the teleport location of your island.' COMMAND_DESCRIPTION_SET_WARP: 'Create a new island warp.' COMMAND_DESCRIPTION_SHOW: 'Get information about an island.' COMMAND_DESCRIPTION_TEAM: 'Get information about island members status.' COMMAND_DESCRIPTION_TEAM_CHAT: 'Toggle team chat mode.' COMMAND_DESCRIPTION_TELEPORT: 'Teleport to your island.' COMMAND_DESCRIPTION_TOGGLE: 'Toggle island borders and stacked blocks placements.' COMMAND_DESCRIPTION_TOP: 'Open top islands panel.' COMMAND_DESCRIPTION_TRANSFER: 'Transfer your island''s leadership.' COMMAND_DESCRIPTION_UNCOOP: 'Remove a player from being a co-op in your island.' COMMAND_DESCRIPTION_UPGRADE: 'Open upgrades panel.' COMMAND_DESCRIPTION_VALUE: 'Get the worth value of a block.' COMMAND_DESCRIPTION_VALUES: 'Open the values menu.' COMMAND_DESCRIPTION_VISIT: 'Teleport to the visitors location of an island.' COMMAND_DESCRIPTION_VISITORS: 'Open the visitors menu.' COMMAND_DESCRIPTION_WARP: 'Warp to an island warp.' COMMAND_DESCRIPTION_WARPS: 'Open the warps menu.' COMMAND_DESCRIPTION_WITHDRAW: 'Withdraw money from your island''s bank into your personal account.' COMMAND_USAGE: '&cUsage: /{0}' COOP_ANNOUNCEMENT: '&e&lIsland | &7{0} added {1} as a co-op member.' COOP_BANNED_PLAYER: '&c&lError | &7This player is banned from the island and cannot be coop.' COOP_LIMIT_EXCEED: '&c&lError | &7You reached the maximum amount of coop players the island can have.' CREATE_ISLAND: '&e&lIsland | &7Created a new island at {0} in {1}ms.' CREATE_ISLAND_FAILURE: '&c&lError | &7An error occurred while creating your island. Please contact the administrator to investigate the issue.' CREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.' DEBUG_MODE_DISABLED: '&e&lDebug | &7Toggled debug mode &cOFF&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7Toggled debug mode &aON&7.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.' DELETE_WARP: '&e&lIsland | &7You deleted the warp {0}.' DELETE_WARP_SIGN_BROKE: '&7&oThere was a sign for that warp, it got broken...' DEMOTE_LEADER: '&c&lError | &7You cannot demote island leaders.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7You can only demote players with a lower island role than yours.' DEMOTED_MEMBER: '&e&lIsland | &7You demoted {0} to a {1} in his island.' DEPOSIT_ANNOUNCEMENT: '&e&lBank | &7{0} deposited ${1} into the island bank!' DEPOSIT_ERROR: '&c&lError | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lError | &7You cannot destroy outside of your protection range.' DISBAND_ANNOUNCEMENT: '&e&lIsland | &7Your island was disbanded by {0}.' DISBAND_GIVE: '&e&lIsland | &7You received {0} disbands.' DISBAND_GIVE_ALL: '&e&lIsland | &7You gave {0} disbands to all players.' DISBAND_GIVE_OTHER: '&e&lIsland | &7You gave {0} disbands to {1}.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oYour island was disbanded and ${0} dollars were refunded to your account from the island bank' DISBAND_SET: '&e&lIsland | &7Your disband count was set to {0}.' DISBAND_SET_ALL: '&e&lIsland | &7You set the disband count of all players to {0}.' DISBAND_SET_OTHER: '&e&lIsland | &7You set {0}''s disband count to {1}.' DISBANDED_ISLAND: '&e&lIsland | &7You disbanded your island.' DISBANDED_ISLAND_OTHER: '&e&lIsland | &7You disbanded {0}''s island.' DISBANDED_ISLAND_OTHER_NAME: '&e&lIsland | &7You disbanded the island {0}.' ENTER_PVP_ISLAND: '&7&oYou were teleported into an island that has PVP enabled. You are immuned to PVP for the next 10 seconds...' EXPELLED_PLAYER: '&e&lIsland | &7{0} was expelled from the island.' FORMAT_QUAD: 'Q' FORMAT_TRILLION: 'T' FORMAT_BILLION: 'B' FORMAT_MILLION: 'M' FORMAT_THOUSANDS: 'K' FORMAT_SECONDS_NAME: 'seconds' FORMAT_SECOND_NAME: 'second' FORMAT_MINUTES_NAME: 'minutes' FORMAT_MINUTE_NAME: 'minute' FORMAT_HOURS_NAME: 'hours' FORMAT_HOUR_NAME: 'hour' FORMAT_DAYS_NAME: 'days' FORMAT_DAY_NAME: 'day' GENERATOR_CLEARED: '&e&lIsland | &7Successfully cleared the generator amounts for {0}''s island.' GENERATOR_CLEARED_NAME: '&e&lIsland | &7Successfully cleared the generator amounts for the island of {0}.' GENERATOR_CLEARED_ALL: '&e&lIsland | &7Successfully cleared the generator amounts for all the islands.' GENERATOR_UPDATED: '&e&lIsland | &7Successfully updated the generator amount of {0} to {1}''s island.' GENERATOR_UPDATED_NAME: '&e&lIsland | &7Successfully updated the generator amount of {0} to the island of {1}.' GENERATOR_UPDATED_ALL: '&e&lIsland | &7Successfully updated the generator amount of {0} to all the islands.' GLOBAL_COMMAND_EXECUTED: '&e&lIsland | &7Successfully executed the command on {0}''s island members!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lIsland | &7Successfully executed the command on the island members of {0}!' GLOBAL_MESSAGE_SENT: '&e&lIsland | &7Successfully sent to {0}''s island members the message!' GLOBAL_MESSAGE_SENT_NAME: '&e&lIsland | &7Successfully sent to the island members of {0} the message!' GLOBAL_TITLE_SENT: '&e&lIsland | &7Successfully sent to {0}''s island members the title!' GLOBAL_TITLE_SENT_NAME: '&e&lIsland | &7Successfully sent to the island members of {0} the title!' GOT_BANNED: '&e&lIsland | &7You were BANNED from {0}''s island.' GOT_DEMOTED: '&e&lIsland | &7You were demoted to a {0} in your island.' GOT_EXPELLED: '&e&lIsland | &7&oYou were expelled from the island by {0}.' GOT_INVITE: '&e&lIsland | &7{0} invited you to his island.' GOT_INVITE_TOOLTIP: '&7Click the message in order to accept the invite.' GOT_KICKED: '&e&lIsland | &7You were kicked from your island by {0}.' GOT_PROMOTED: '&e&lIsland | &7You were promoted to a {0} in your island.' GOT_REVOKED: '&e&lIsland | &7{0} revoked your invitation to his island.' GOT_UNBANNED: '&e&lIsland | &7You were UNBANNED from {0}''s island.' HIT_ISLAND_MEMBER: '&c&lError | &7You cannot hit your island members.' HIT_PLAYER_IN_ISLAND: '&c&lError | &7You cannot hit players inside islands.' IGNORED_ISLAND: '&e&lIsland | &7{0}''s island is now ignored from top islands.' IGNORED_ISLAND_NAME: '&e&lIsland | &7The island {0} is now ignored from top islands.' INTERACT_OUTSIDE_ISLAND: '&c&lError | &7You cannot interact outside of your protection range.' INVALID_AMOUNT: '&c&lError | &7Invalid amount {0}.' INVALID_BIOME: '&c&lError | &7Invalid biome {0}.' INVALID_BLOCK: '&c&lError | &7Invalid block location {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lError | &7Invalid effect {0}.' INVALID_ENTITY: '&c&lError | &7Invalid entity {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lError | &7You don''t have an island.' INVALID_ISLAND_LOCATION: '&c&lError | &7There is no island in your location.' INVALID_ISLAND_OTHER: '&c&lError | &7{0} doesn''t have an island.' INVALID_ISLAND_OTHER_NAME: '&c&lError | &7There is no island with the name {0}.' INVALID_ISLAND_PERMISSION: | &c&lError | &7Couldn't find the island permission {0}. &c&lError | &7Island Permissions: {1} INVALID_LEVEL: '&c&lError | &7Invalid level {0}.' INVALID_LIMIT: '&c&lError | &7Invalid limit {0}.' INVALID_MATERIAL: '&c&lError | &7Invalid material {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Invalid mission {0}.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lError | &7Invalid multiplier {0}.' INVALID_PAGE: '&c&lError | &7Invalid page {0}.' INVALID_PERCENTAGE: '&c&lError | &7Percentage must be between 0 and 100.' INVALID_PLAYER: '&c&lError | &7Cannot find a player called {0}' INVALID_RATE: | &c&lError | &7Couldn't find a rating with the name {0}. &c&lError | &7Island Ratings: {1} INVALID_ROWS: '&c&lError | &7Invalid amount of rows: {0}' INVALID_ROLE: | &c&lError | &7Couldn't find the island role {0}. &c&lError | &7Island Roles: {1} INVALID_SCHEMATIC: '&c&lError | &7Couldn''t find a schematic with the name {0}.' INVALID_SETTINGS: | &c&lError | &7Couldn't find the island settings {0}. &c&lError | &7Island Settings: {1} INVALID_SIZE: '&c&lError | &7Invalid size {0}.' INVALID_SLOT: '&c&lError | &7Invalid slot {0}.' INVALID_TITLE: '&c&lError | &7Invalid title entered.' INVALID_TOGGLE_MODE: '&c&lError | &7Cannot toggle {0}.' INVALID_UPGRADE: | &c&lError | &7Couldn't find an upgrade called {0}. &c&lError | &7Upgrades: {1} INVALID_VISIT_LOCATION: '&c&lError | &7This island has no visitors location.' INVALID_VISIT_LOCATION_BYPASS: '&7&oYou have bypass mode, teleporting you to the island...' INVALID_WARP: '&c&lError | &7Invalid warp {0}.' INVALID_WORLD: '&c&lError | &7Invalid world {0}.' INVITE_ANNOUNCEMENT: '&e&lIsland | &7{0} invited {1} to the island.' INVITE_BANNED_PLAYER: '&c&lError | &7This player is banned from the island and cannot get invited.' INVITE_TO_FULL_ISLAND: '&c&lError | &7You cannot invite more members to your island.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lError | &7An island with that name already exists.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBank | &7Island bank is empty.' ISLAND_BANK_SHOW: '&e&lBank | &7Your island has ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBank | &7{0}''s island has ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBank | &7The island {0} has ${1}.' ISLAND_BEING_CALCULATED: '&c&lError | &7You cannot interact with blocks when island is being recalculated!' ISLAND_CLOSED: '&e&lIsland | &7Successfully closed the island to the public.' ISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7You have an already ongoing island creation task.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsland | &7Processing your request...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lFly | &7Island fly was automatically &cdisabled&7.' ISLAND_FLY_ENABLED: '&e&lFly | &7Island fly was automatically &aenabled&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIsland | &7&oYou had been inside an island that been disbanded, so you were teleported back to spawn...' ISLAND_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...' ISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Developed by Ome_R' ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Commands List [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Use /is help {0} for the next page.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIsland | &7Bank Limit: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lIsland | &7Blocks Limits: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIsland | &7Coop Limit: {0}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIsland | &7Crops Multiplier: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIsland | &7Drops Multiplier: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lIsland | &7Island Effects: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lIsland | &7Entities Limits: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lIsland | &7Generator Rates ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIsland | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lIsland | &7Role Limits: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lIsland | &7Border Size: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIsland | &7Spawners Multiplier: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIsland | &7Team Limit: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lIsland | &7Upgrades: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIsland | &7Warps Limit: {0}' ISLAND_INFO_BANK: '&e&lIsland | &7Bank: {0}' ISLAND_INFO_BONUS: '&e&lIsland | &7Worth Bonus: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lIsland | &7Level Bonus: {0}' ISLAND_INFO_CREATION_TIME: '&e&lIsland | &7Creation Time: {0}' ISLAND_INFO_DISCORD: '&e&lIsland | &7Discord: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lIsland | &7Last Time Updated: {0} ago' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIsland | &7Last Time Updated: &aCurrently Active' ISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}' ISLAND_INFO_LOCATION: '&e&lIsland | &7Home: {0}' ISLAND_INFO_NAME: '&e&lIsland | &7Name: {0}' ISLAND_INFO_OWNER: '&e&lIsland | &7Leader: {0}' ISLAND_INFO_PAYPAL: '&e&lIsland | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lIsland | &7 - {0}' ISLAND_INFO_RATE: '&e&lIsland | &7Rate: {0} &7({1}/5) - {2} total ratings.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: '✦' ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIsland | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIsland | &7Visitors Count: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIsland | &7Worth: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsland | &7Successfully opened the island to the public.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you are no longer in preview mode.' ISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' ISLAND_PREVIEW_CANCEL_TEXT: 'CANCEL' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lPreview | &7You started the preview mode for the schematic {0}. &e&lPreview | &7Type &a&lCONFIRM &7to create a new island, or &c&lCANCEL &7to cancel the preview mode. &e&lPreview | &7You cannot leave the area of the island, otherwise the preview mode will be cancelled automatically. ISLAND_PROTECTED: '&c&lError | &7This island is protected.' ISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lIsland | &7Members of {0}''s Island &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)' ISLAND_TEAM_STATUS_ONLINE: '&a(Online)' ISLAND_TEAM_STATUS_ROLES: '&e&lIsland | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Offline)' ISLAND_TOP_STATUS_ONLINE: '&a(Online)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Private]' ISLAND_WAS_CLOSED: '&e&lIsland | &7&oThe island you were in was closed and you were teleported back to spawn...' ISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.' ISLAND_WORTH_RESULT: '&e&lIsland | &7Your island worth is {0} [Level {1}]' ISLAND_WORTH_TIME_OUT: '&c&lError | &7The calculation task has timed out. Try again later...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lIsland | &7{0} has joined your island.' JOIN_ANNOUNCEMENT: '&e&lIsland | &7{0} has joined your island.' JOIN_FULL_ISLAND: '&c&lError | &7This island reached the maximum amount of allowed members.' JOIN_WHILE_IN_ISLAND: '&c&lError | &7You are already inside an island.' JOINED_ISLAND: '&e&lIsland | &7You joined {0}''s island.' JOINED_ISLAND_NAME: '&e&lIsland | &7You joined the island {0}.' JOINED_ISLAND_AS_COOP: '&e&lIsland | &7You are now a co-op member of {0}''s island.' JOINED_ISLAND_AS_COOP_NAME: '&e&lIsland | &7You are now a co-op member of the island {0}.' KICK_ANNOUNCEMENT: '&e&lIsland | &7{0} was kicked from the island by {1}.' KICK_ISLAND_LEADER: '&c&lError | &7You cannot kick the leader of the island, use /is admin disband instead.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7You can only kick players with a lower island role than yours.' LACK_CHANGE_PERMISSION: '&c&lError | &7You must have this permission in order to change it to other roles.' LAST_ROLE_DEMOTE: '&c&lError | &7You cannot demote this player anymore.' LAST_ROLE_PROMOTE: '&c&lError | &7You cannot promote this player anymore.' LEAVE_ANNOUNCEMENT: '&e&lIsland | &7{0} left the island.' LEAVE_ISLAND_AS_LEADER: |- &c&lError | &7You cannot leave your island when you own it. &c&lError | &7You can transfer the ownership using /is transfer. LEFT_ISLAND: '&e&lIsland | &7You left your island.' LEFT_ISLAND_COOP: '&e&lIsland | &7You are no longer a co-op member of {0}''s island.' LEFT_ISLAND_COOP_NAME: '&e&lIsland | &7You are no longer a co-op member of the island {0}.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lError | &7You must provide a solid material.' MAXIMUM_LEVEL: '&c&lError | &7The maximum level for this upgrade is {0}.' MESSAGE_SENT: '&e&lIsland | &7Successfully sent {0} the message!' MISSION_CANNOT_COMPLETE: '&c&lError | &7You cannot complete this mission yet.' MISSION_NO_AUTO_REWARD: '&e&lMission | &7You have all the required materials to finish {0} - use /is missions to complete!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lError | &7You must complete {0} before completing this mission.' MISSION_STATUS_COMPLETE: '&e&lMission | &7Changed the status of the mission {0} to completed for {1}.' MISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Changed the status of all the missions to completed for {0}.' MISSION_STATUS_RESET: '&e&lMission | &7Reset the status of the mission {0} for {1}.' MISSION_STATUS_RESET_ALL: '&e&lMission | &7Reset the status of all the missions for {0}.' MODULE_ALREADY_INITIALIZED: '&e&lModule | &7This module is already loaded.' MODULE_INFO: | &e&lModule | &7{0} by {1} &e&lModule | &7&m-------------------- &e&lModule | &7{2} MODULE_LOADED_SUCCESS: '&e&lModule | &7Successfully loaded the module {0}.' MODULE_LOADED_FAILURE: '&e&lModule | &7Couldn''t load the module {0}. Check out the console for more information.' MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lIsland | &7{0} changed his island name to {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lError | &7You cannot use that name.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lError | &7You cannot use player names as island names.' NAME_TOO_LONG: '&c&lError | &7Island names cannot be more than {0} chars long.' NAME_TOO_SHORT: '&c&lError | &7Island names cannot be less than {0} chars long.' NO_BAN_PERMISSION: '&c&lError | &7You must be at least {0} in order to ban players.' NO_CLOSE_BYPASS: '&c&lError | &7This island is not opened to the public.' NO_CLOSE_PERMISSION: '&c&lError | &7You must be at least {0} in order to close the island to the public.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lError | &7You must be at least {0} in order to add players as co-op members.' NO_DELETE_WARP_PERMISSION: '&c&lError | &7You must be at least {0} in order to delete warps.' NO_DEMOTE_PERMISSION: '&c&lError | &7You must be at least {0} in order to demote players.' NO_DEPOSIT_PERMISSION: '&c&lError | &7You must be at least {0} in order to deposit money to island bank.' NO_DISBAND_PERMISSION: '&c&lError | &7You must be at least {0} in order to disband your island.' NO_EXPEL_PERMISSION: '&c&lError | &7You must be at least {0} in order to expel players from your island.' NO_INVITE_PERMISSION: '&c&lError | &7You must be at least {0} in order to invite players.' NO_ISLAND_CHEST_PERMISSION: '&c&lError | &7You must be at least {0} in order to access the island''s chest.' NO_ISLAND_INVITE: '&c&lError | &7Could not find any invites from this island.' NO_ISLANDS_TO_PURGE: '&c&lError | &7There were no islands to purge.' NO_KICK_PERMISSION: '&c&lError | &7You must be at least {0} in order to kick players.' NO_MORE_DISBANDS: '&c&lError | &7You can''t disband any more islands.' NO_MORE_WARPS: '&c&lError | &7Your island can''t have any more warps.' NO_NAME_PERMISSION: '&c&lError | &7You cannot change the name of your island.' NO_OPEN_PERMISSION: '&c&lError | &7You must be at least {0} in order to open the island to the public.' NO_PERMISSION_CHECK_PERMISSION: '&c&lError | &7You must be at least {0} in order to get information about permissions.' NO_PROMOTE_PERMISSION: '&c&lError | &7You must be at least {0} in order to promote players.' NO_RANKUP_PERMISSION: '&c&lError | &7You must be at least {0} in order to rankup upgrades.' NO_RATINGS_PERMISSION: '&c&lError | &7You must be at least {0} in order to check ratings.' NO_SET_BIOME_PERMISSION: '&c&lError | &7You must be at least {0} in order to change island biome.' NO_SET_DISCORD_PERMISSION: '&c&lError | &7You must be at least {0} in order to change island discord.' NO_SET_HOME_PERMISSION: '&c&lError | &7You must be at least {0} in order to set the teleport location of the island.' NO_SET_PAYPAL_PERMISSION: '&c&lError | &7You must be at least {0} in order to change island paypal email.' NO_SET_ROLE_PERMISSION: '&c&lError | &7You must be at least {0} in order to set roles for players.' NO_SET_SETTINGS_PERMISSION: '&c&lError | &7You must be at least {0} in order to change island settings.' NO_SET_WARP_PERMISSION: '&c&lError | &7You must be at least {0} in order to set island warps.' NO_TRANSFER_PERMISSION: '&c&lError | &7You must be the island''s leader in order to transfer the leadership.' NO_UNCOOP_PERMISSION: '&c&lError | &7You must be at least {0} in order to remove players from being co-op members.' NO_UPGRADE_PERMISSION: '&c&lError | &7You are lacking the permission to upgrade into another level.' NO_WITHDRAW_PERMISSION: '&c&lError | &7You must be at least {0} in order to withdraw money from island bank.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lError | &7You don''t have enough money to deposit {0} dollars into your island''s bank.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lError | &7You don''t have enough money.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7You don''t have enough money to use island warps.' OPEN_MENU_WHILE_SLEEPING: '&7&oYou''re too tired to interact with menus, don''t you think?' PANEL_TOGGLE_OFF: |- &e&lPanel | &7Toggled island panel &cOFF&7. &e&lPanel | &7Running /is will teleport you to the island. PANEL_TOGGLE_ON: |- &e&lPanel | &7Toggled island panel &aON&7. &e&lPanel | &7Running /is will open the panel for you. PERMISSION_CHANGED: '&e&lIsland | &7Successfully updated the permission {0} of {1}''s island.' PERMISSION_CHANGED_NAME: '&e&lIsland | &7Successfully updated the permission {0} of the island {1}.' PERMISSION_CHANGED_ALL: '&e&lIsland | &7Successfully updated the permission {0} for all the islands.' PERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.' PERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIsland | &7Successfully reset all the permissions for {0} to default values!' PERMISSIONS_RESET_ROLES: '&e&lIsland | &7Successfully reset all the permissions of the island to default values!' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Yes' PLAYER_ALREADY_BANNED: '&c&lError | &7This player is already banned.' PLAYER_ALREADY_COOP: '&c&lError | &7This player is already coop.' PLAYER_ALREADY_IN_ISLAND: '&c&lError | &7This player is already inside an island.' PLAYER_ALREADY_IN_ROLE: '&c&lError | &7{0} is already a {1}.' PLAYER_EXPEL_BYPASS: '&c&lError | &7This user cannot be expelled from the island.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lIsland | &7{0} joined the server.' PLAYER_NOT_BANNED: '&c&lError | &7This player is not banned.' PLAYER_NOT_COOP: '&c&lError | &7This player is not co-op.' PLAYER_NOT_INSIDE_ISLAND: '&c&lError | &7This player is not inside your island.' PLAYER_NOT_ONLINE: '&c&lError | &7This player is not online!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lIsland | &7{0} left the server.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7You can only promote players with a lower island role than yours.' PROMOTED_MEMBER: '&e&lIsland | &7You promoted {0} to a {1} in his island.' PURGE_CLEAR: '&e&lIsland | &7Successfully cleared all the queued islands to be purged.' PURGED_ISLANDS: |- &e&lIsland | &7{0} islands will be purged when server restarts. &e&lIsland | &7You can cancel it anytime using /is admin purge cancel. RANKUP_SUCCESS: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}''s island.' RANKUP_SUCCESS_ALL: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for all the islands.' RANKUP_SUCCESS_NAME: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIsland | &7{0} has rated your island {1} out of 5!.' RATE_CHANGE_OTHER: '&e&lIsland | &7You changed the rating of {0} to {1}.' RATE_OWN_ISLAND: '&c&lError | &7You can''t rate your own island.' RATE_REMOVE_ALL: '&e&lIsland | &7Successfully removed all ratings of {0}.' RATE_REMOVE_ALL_ISLANDS: '&e&lIsland | &7Successfully removed all ratings of all the islands.' RATE_SUCCESS: '&e&lIsland | &7You rated this island with {0} stars!' REACHED_BLOCK_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for {0} Block.' REACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.' RECALC_ALREADY_RUNNING: '&c&lError | &7Your island is already being recalculated.' RECALC_ALREADY_RUNNING_OTHER: '&c&lError | &7This island is already being recalculated.' RECALC_ALL_ISLANDS: '&e&lIsland | &7Recalculating all islands...' RECALC_ALL_ISLANDS_DONE: '&e&lIsland | &7Successfully finished recalculating all islands.' RECALC_PROCCESS_REQUEST: '&e&lIsland | &7Processing your request...' RELOAD_COMPLETED: '&e&lIsland | &7Reload is finished!' RELOAD_PROCCESS_REQUEST: '&e&lIsland | &7Starting to reload configurations...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lIsland | &7{0} revoked the invitation of {1} to the island.' RESET_SETTINGS: '&e&lIsland | &7Successfully reset island settings for {0}''s island.' RESET_SETTINGS_ALL: '&e&lIsland | &7Successfully reset island settings for all the islands.' RESET_SETTINGS_NAME: '&e&lIsland | &7Successfully reset island settings for all the islands.' RESET_WORLD_SUCCEED: '&e&lIsland | &7Successfully reset the world {0} for {1}''s island.' RESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for all the islands.' RESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.' SAME_NAME_CHANGE: '&c&lError | &7You must enter a different name from your current island name.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Selected position #2 ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lError | &7You haven''t selected two positions.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Processing your request...' SCHEMATIC_READY_TO_CREATE: | &e&lSchematics | &7You have selected two positions. Run /is admin schematic to create a new schematic. &e&lSchematics | &7Make sure you stand at the teleportation location when executing the command. SCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Selected position #1 ({0})' SCHEMATIC_SAVED: '&e&lSchematics | &7Successfully saved schematic!' SELF_ROLE_CHANGE: '&c&lError | &7You cannot change the role of yourself.' SET_UPGRADE_LEVEL: '&e&lUpgrades | &7Successfully updated the level of {0} for {1}''s island.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of {0} for {1}.' SET_WARP: '&e&lIsland | &7Successfully created a new warp at {0}.' SET_WARP_OUTSIDE: '&c&lError | &7You cannot set warps outside your island.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsland | &7Successfully updated the settings {0} to {1}''s island.' SETTINGS_UPDATED_NAME: '&e&lIsland | &7Successfully updated the settings {0} to the island {1}.' SETTINGS_UPDATED_ALL: '&e&lIsland | &7Successfully updated the settings {0} to all the islands.' SIZE_BIGGER_MAX: '&c&lError | &7You cannot set a size bigger than the max island size.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Successfully teleported {0} to spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Successfully updated the spawn location to {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lUpgrades | &7Successfully synced all upgrade values of {0}''s island.' SYNC_UPGRADES_ALL: '&e&lUpgrades | &7Successfully synced all upgrade values of all the islands.' SYNC_UPGRADES_NAME: '&e&lUpgrades | &7Successfully synced all upgrade values of {0}.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lError | &7You are not inside your island.' TELEPORT_OUTSIDE_ISLAND: '&c&lError | &7You cannot teleport outside of your protection range.' TELEPORT_WARMUP: '&7&oYou will be teleported in {0}... Do not move!' TELEPORT_WARMUP_CANCEL: '&7&oYou moved and so the teleportation was cancelled.' TITLE_SENT: '&e&lIsland | &7Successfully sent {0} the title!' TELEPORTED_FAILED: '&e&lIsland | &7It seems like this island has no safe blocks. Please contact a staff member.' TELEPORTED_SUCCESS: '&e&lIsland | &7You were teleported to your island.' TELEPORTED_TO_WARP: '&e&lIsland | &7Successfully teleported to this island warp.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIsland | &7The player {0} teleported to the island warp {1}.' TOGGLED_BYPASS_OFF: '&e&lBypass | &7Toggled bypass mode &cOFF&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Toggled bypass mode &aON&7.' TOGGLED_FLY_OFF: '&e&lFly | &7Toggled island fly &cOFF&7.' TOGGLED_FLY_ON: '&e&lFly | &7Toggled island fly &aON&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Toggling schematic mode &cOFF&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchematics | &7Toggling schematic mode &aON&7. &e&lSchematics | &7Select an area using a golden axe. TOGGLED_SPY_OFF: '&e&lSpy | &7Toggled spy chat &cOFF&7.' TOGGLED_SPY_ON: '&e&lSpy | &7Toggled spy chat &aON&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Toggling blocks stacker &cOFF&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Toggling blocks stacker &aON&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Toggling team chat &cOFF&7.' TOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Toggling team chat &aON&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lBorder | &7Toggling world border &cOFF&7.' TOGGLED_WORLD_BORDER_ON: '&e&lBorder | &7Toggling world border &aON&7.' TRANSFER_ADMIN: '&e&lIsland | &7You transferred {0}''s leadership to {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lError | &7{0} is already the leader of his island.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lError | &7These players are not in the same islands.' TRANSFER_ADMIN_NOT_LEADER: '&c&lError | &7This player is not a leader of any islands.' TRANSFER_ALREADY_LEADER: '&c&lError | &7You''re already the leader of this island.' TRANSFER_BROADCAST: '&e&lIsland | &7The island''s leadership has been transferred to {0}.' UNBAN_ANNOUNCEMENT: '&e&lIsland | &7{0} was UNBANNED from the island by {1}.' UNCOOP_ANNOUNCEMENT: '&e&lIsland | &7{0} removed {1} from being a co-op member.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsland | &7{0} left the game and is no longer a co-op member.' UNIGNORED_ISLAND: '&e&lIsland | &7{0}''s island is now un-ignored from top islands.' UNIGNORED_ISLAND_NAME: '&e&lIsland | &7The island {0} is now un-ignored from top islands.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIsland | &7&oLooks like this warp is unsafe. Please try another warp.' UPDATED_PERMISSION: '&e&lIsland | &7Updated permissions for {0}.' UPDATED_SETTINGS: '&e&lIsland | &7Updated the island settings {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lError | &7You cannot use that command on other islands.' WARP_ALREADY_EXIST: '&c&lError | &7There is already a warp with this name.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lWarps | &7Enter a new lore (Type "-cancel" to cancel): &e&lWarps | &7You can separate lines by using "\n". WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type "-cancel" to cancel):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type "-cancel" to cancel):' WARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Successfully updated the category''s icon.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lError | &7Warp category names cannot be empty.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.' WARP_CATEGORY_SLOT: '&e&lWarps | &7Enter a new slot (Type "-cancel" to cancel):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lError | &7This slot is already taken by another category.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Successfully changed the category''s slot to {0}.' WARP_CATEGORY_RENAME: '&e&lWarps | &7Enter a new name (Type "-cancel" to cancel):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another category.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the category to {0}.' WARP_ICON_NEW_LORE: | &e&lWarps | &7Enter a new lore (Type "-cancel" to cancel): &e&lWarps | &7You can separate lines by using "\n". WARP_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type "-cancel" to cancel):' WARP_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type "-cancel" to cancel):' WARP_ICON_UPDATED: '&e&lWarps | &7Successfully updated the warp''s icon.' WARP_ILLEGAL_NAME: '&c&lError | &7Warp names cannot be empty.' WARP_LOCATION_UPDATE: '&e&lWarps | &7Successfully updated the warp''s location to your location.' WARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.' WARP_PUBLIC_UPDATE: '&e&lWarps | &7Successfully opened the warp to the public.' WARP_PRIVATE_UPDATE: '&e&lWarps | &7Successfully closed the warp to the public.' WARP_RENAME: '&e&lWarps | &7Enter a new name (Type "-cancel" to cancel):' WARP_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another warp.' WARP_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the warp to {0}.' WITHDRAW_ALL_MONEY: |- &e&lBank | &7Island bank has only {0} dollars inside it. &e&lBank | &7&oWithdrawing all money..." WITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} withdrawn ${1} from the island bank!' WITHDRAW_ERROR: '&c&lError | &7{0}.' WITHDRAWN_MONEY: '&e&lBank | &7You withdrawn ${0} from {1}''s island bank!' WITHDRAWN_MONEY_NAME: '&e&lBank | &7You withdrawn ${0} from the island bank of {1}!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lWorlds | &7The {0} world is not unlocked yet!' ================================================ FILE: src/main/resources/lang/es-ES.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Desarrollado por Ome_R ## ## Traducido por Aymac ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # You can find a tutorial about configuring messages here: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lIsla | &7Añadiste al jugador {0} a la isala de {1}' ADMIN_ADD_PLAYER_NAME: '&e&lIsla | &7Añadiste al jugador {0} a la isala de {1}.' ADMIN_DEPOSIT_MONEY: '&e&lBanco | &7Has depositado ${0} en el banco de la isla de {1}' ADMIN_DEPOSIT_MONEY_NAME: '&e&lBanco | &7Has depositado${0} en el banco de la isla de {1}.' ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Desarrollado por Ome_R - Traducido al español por: Aymac' ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista de comandos de administrador [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Usa /is admin {0} para la página siguiente.' ALREADY_IN_ISLAND: '&c&lError | &7Ya estas en una isla.' ALREADY_IN_ISLAND_OTHER: '&c&lError | &7Este jugador ya es miembro de tu isla.' BAN_ANNOUNCEMENT: '&e&lIsla | &7{0} fue baneado de la isla por: {1}.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Solo puedes banear jugadores con un rol de isla más bajo que el tuyo.' BANK_DEPOSIT_CUSTOM: '&e&lBanco | &7Escriba la cantidad que desea depositar:' BANK_DEPOSIT_COMPLETED: 'Depósito completado' BANK_LIMIT_EXCEED: '&c&lError | &7Has excedido tu límite bancario.' BANK_WITHDRAW_CUSTOM: '&e&lBanco | &7Escriba la cantidad que desea retirar:' BANK_WITHDRAW_COMPLETED: 'Retiro completado' BANNED_FROM_ISLAND: '&c&lError | &7Estás prohibido en esta isla.' BLOCK_COUNT_CHECK: '&e&lIsla | &7Esta isla tiene x{0} {1}.' BLOCK_COUNTS_CHECK: | &e&lIsla | &7Esta isla tiene los siguientes bloques: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lIsla | &7Esta isla no tiene bloques comprobados.' BLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}' BLOCK_LEVEL: '&e&lNivel | &7El nivel del bloque {0} es {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lNivel | &7El bloque {0} no tiene valor.' BLOCK_VALUE: '&e&lValor | &7El bloque {0} vale {1}.' BLOCK_VALUE_WORTHLESS: '&e&lValor | &7El bloque {0} no tiene valor.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Blue' BORDER_PLAYER_COLOR_NAME_RED: 'Red' BORDER_PLAYER_COLOR_NAME_GREEN: 'Green' BORDER_PLAYER_COLOR_UPDATED: '&e&lBorde | &7Cambió con éxito el color de su borde personal a {0}.' BUILD_OUTSIDE_ISLAND: '&c&lError | &7No puede construir fuera de su rango de protección.' CANNOT_SET_ROLE: '&c&lError | &7No puedes establecer el rol del jugador en {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lError | &7Solo puedes cambiar los permisos a un rol de isla más bajo que el suyo.' CHANGED_BANK_LIMIT: '&e&lMejoras| &7Se actualizó correctamente el límite bancario de la isla de {0} ' CHANGED_BANK_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite bancario de todas las islas.' CHANGED_BANK_LIMIT_NAME: '&e&lMejoras| &7Se actualizó con éxito el límite bancario de {0}.' CHANGED_BIOME: '&e&lIsla | &7Bioma cambiado correctamente a {0}. Es posible que deba volver a conectarse al servidor para ver los cambios.' CHANGED_BIOME_ALL: '&e&lIsla | &7Se cambió correctamente el bioma a {0} para todas las islas.' CHANGED_BIOME_NAME: '&e&lIsla | &7Se cambió correctamente el bioma a {0} para la isla {1}.' CHANGED_BIOME_OTHER: '&e&lIsla | &7Se cambió correctamente el bioma a {0} para la isla de {1}.' CHANGED_BLOCK_AMOUNT: '&e&lBloques | &7Cambió correctamente la cantidad de bloques en {0} a {1}.' CHANGED_BLOCK_LIMIT: '&e&lMejoras| &Se actualizó correctamente el límitede bloques de {1} a {0}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lMejoras| &7Se actualizó correctamente el límitede bloques de todas las islas a {0}.' CHANGED_BLOCK_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de bloques de {1} a {0}.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para la isla de {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para todas las islas.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para {2}.' CHANGED_COOP_LIMIT: '&e&lMejoras| &7Se actualizó con éxito el límite de jugadores cooperativos de la isla de {0}.' CHANGED_COOP_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite de jugadores cooperativos de todas las islas.' CHANGED_COOP_LIMIT_NAME: '&e&lMejoras| &7Se actualizó con éxito el límite de jugadores cooperativos de {0}.' CHANGED_CROP_GROWTH: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de crecimiento de cultivos de la isla de {0}.' CHANGED_CROP_GROWTH_ALL: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de crecimiento de cultivos de todas las islas.' CHANGED_CROP_GROWTH_NAME: '&e&lMejoras| &7Se actualizó correctamente el multiplicador de crecimiento de cultivos de {0}.' CHANGED_DISCORD: '&e&lIsla | &7Se cambió la discord de la isla a {0}.' CHANGED_ENTITY_LIMIT: '&e&lMejoras| &7Se actualizó correctamente el límite de {0} entidades para la isla de {1}.' CHANGED_ENTITY_LIMIT_ALL: '&e&lMejoras| &7Se actualizó correctamente el límite de {0} entidades para todas las islas.' CHANGED_ENTITY_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de {0} entidades para {1}.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lMejoras| &7Se actualizó con éxito el nivel del efecto de isla {0} para la isla de {1}.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lMejoras| &7Se actualizó con éxito el nivel del efecto de isla {0} para todas las islas.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lMejoras| &7Se actualizó correctamente el nivel del efecto isla {0} para {1}.' CHANGED_ISLAND_SIZE: '&e&lMejoras| &7Se actualizó correctamente el tamaño de la isla de {0}.' CHANGED_ISLAND_SIZE_ALL: '&e&lMejoras| &7Se actualizó con éxito el tamaño de la isla de todas las islas.' CHANGED_ISLAND_SIZE_NAME: '&e&lMejoras| &7Se actualizó correctamente el tamaño de la isla de {0}.' CHANGED_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.' CHANGED_LANGUAGE: '&e&lIdioma/Language | &7Cambió correctamente su idioma al inglés/Successfully changed your language to English.' CHANGED_MOB_DROPS: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de la isla de {0}.' CHANGED_MOB_DROPS_ALL: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de todas las islas.' CHANGED_MOB_DROPS_NAME: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de {0}.' CHANGED_NAME: '&e&lIsla | &7Cambiaste el nombre de tu isla a {0}&7.' CHANGED_NAME_OTHER: '&e&lIsla | &7Cambiaste el nombre de la {0} isla a {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lIsla | &7Cambiaste el nombre de {0}&7 a {1}&7.' CHANGED_PAYPAL: '&e&lIsla | &7Se cambió el PayPal de la isla {0}.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.' CHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}.' CHANGED_SPAWNER_RATES: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de tasas de spawn de la isla de {0}.' CHANGED_SPAWNER_RATES_ALL: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de tasas de spawn de todas las islas.' CHANGED_SPAWNER_RATES_NAME: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de tasas de spawn de {0}.' CHANGED_TEAM_LIMIT: '&e&lMejoras| &7Se actualizó con éxito el límite de equipo de la isla de {0}.' CHANGED_TEAM_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite de equipo de todas las islas..' CHANGED_TEAM_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de equipo de {0}.' CHANGED_TELEPORT_LOCATION: '&e&lIsla | &7Ubicación de teletransporte actualizada con éxito.' CHANGED_WARPS_LIMIT: '&e&lMejoras| &7Se actualizó con éxito el límite de warps de la isla de {0}.' CHANGED_WARPS_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite de warps de todas las islas.' CHANGED_WARPS_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de warps de {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'cantidad' COMMAND_ARGUMENT_BIOME: 'bioma' COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'command...' COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: 'pefecto-de-poción' COMMAND_ARGUMENT_EMAIL: 'email' COMMAND_ARGUMENT_ENTITY: 'entidad' COMMAND_ARGUMENT_ISLAND_NAME: 'nombre-de-isla' COMMAND_ARGUMENT_ISLAND_ROLE: 'rol-de-isla' COMMAND_ARGUMENT_LEADER: 'líder' COMMAND_ARGUMENT_LEVEL: 'nivel' COMMAND_ARGUMENT_LIMIT: 'límite' COMMAND_ARGUMENT_MATERIAL: 'material' COMMAND_ARGUMENT_MENU: 'nombre-del-menu' COMMAND_ARGUMENT_MESSAGE: 'mensaje...' COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: 'nombre-de-misión' COMMAND_ARGUMENT_MODULE_NAME: 'module-name' COMMAND_ARGUMENT_MULTIPLIER: 'multiplicador' COMMAND_ARGUMENT_NAME: 'nombre' COMMAND_ARGUMENT_NEW_LEADER: 'nuevo-lider' COMMAND_ARGUMENT_PAGE: 'página' COMMAND_ARGUMENT_PATH: 'path' COMMAND_ARGUMENT_PERMISSION: 'permiso' COMMAND_ARGUMENT_PLAYER_NAME: 'nombre-de-jugador' COMMAND_ARGUMENT_PRIVATE: 'privado' COMMAND_ARGUMENT_RATING: 'clasificacion' COMMAND_ARGUMENT_ROWS: 'fila' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'nombre-schematic' COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'configuracion' COMMAND_ARGUMENT_SIZE: 'tamaño' COMMAND_ARGUMENT_TIME: 'tiempo' COMMAND_ARGUMENT_TITLE_DURATION: 'duration' COMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in' COMMAND_ARGUMENT_TITLE_FADE_OUT: 'fade-out' COMMAND_ARGUMENT_UPGRADE_NAME: 'nombre-de-mejora' COMMAND_ARGUMENT_VALUE: 'valor' COMMAND_ARGUMENT_WARP_NAME: 'nombre-delwarp' COMMAND_ARGUMENT_WARP_CATEGORY: 'warp-category' COMMAND_ARGUMENT_WORLD: 'mundo' COMMAND_COOLDOWN_FORMAT: '&c&lError | &7Solo puede usar el comando en {0}.' COMMAND_DESCRIPTION_ACCEPT: 'Aceptar una invitación de un jugador.' COMMAND_DESCRIPTION_ADMIN: 'Utilice los comandos de administrador.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Añadir un usuario a una isla.' COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Aumenta el límite de bloques para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Añadir un bono a un jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Aumentar el límite de jugadores cooperativos para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Aumenta el multiplicador de crecimiento de cultivos para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Agrega un efecto de isla para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Aumentar el límite de entidades para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Agregue porcentaje de un material para el generador de adoquines.' COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Aumenta el multiplicador de drop de los mobs para la isla de otro jugador..' COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expande el tamaño de la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Aumenta el multiplicador de las tasas de spawn de la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Aumentar el límite de miembros para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Aumentar el límite de warps de una isla.' COMMAND_DESCRIPTION_ADMIN_BONUS: 'Otorga una bonificación a un jugador.' COMMAND_DESCRIPTION_ADMIN_BYPASS: 'Alternar el modo de bypass' COMMAND_DESCRIPTION_ADMIN_CHEST: 'Cofre de isla abierta de otra isla.' COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Limpia las tasas de spawn para una isla específica.' COMMAND_DESCRIPTION_ADMIN_CLOSE: 'Cerrar una isla al público.' COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Execute a command for all members of islands.' COMMAND_DESCRIPTION_ADMIN_COUNT: 'Verifique un recuento de bloques en una isla específica.' COMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.' COMMAND_DESCRIPTION_ADMIN_DEBUG: 'Alternar debug outputs.' COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Elimina un warp de una isla' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Degradar a un miembro en la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Deposite dinero en el banco de la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Borra la isla de otro jugador de forma permanente.' COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Permite que un jugador borre la isla.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Hace que la isla ingnore el Top Islas' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Únete a una isla sin invitación.' COMMAND_DESCRIPTION_ADMIN_KICK: 'Echa a un jugador de su isla' COMMAND_DESCRIPTION_ADMIN_MODULES: 'Manage modules of the plugin.' COMMAND_DESCRIPTION_ADMIN_MISSION: 'Cambiar el estado de una misión para un jugador.' COMMAND_DESCRIPTION_ADMIN_MSG: 'Envía un mensaje a un jugador sin prefijos/prefix.' COMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Envíe a todos los miembros de la isla un mensaje sin prefijos/prefixes.' COMMAND_DESCRIPTION_ADMIN_NAME: 'Cambia el nombre de una isla.' COMMAND_DESCRIPTION_ADMIN_OPEN: 'Abrir una isla al público.' COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Abre un menú personalizado para un jugador..' COMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Promocionar a un miembro en la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_PURGE: 'Purgar islas &7(&cCuidado!&7)' COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Subir de rango una mejora para una isla.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Vuelve a calcular el valor de una isla.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarga todas las configuraciones y tareas del plugin/complemento.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Eliminar el límite de bloques de una isla.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Eliminar todas las calificaciones dadas por un jugador.' COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Cree schematics para el plugin.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Establecer el bioma de una isla.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Establece una cantidad de bloques en una ubicación específica.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Establecer límite de bloques para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Establece las filas de los cofres para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Establece un límite de jugadores cooperativos para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Establezca el multiplicador de crecimiento de cultivos para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Establece la cantidad de islas disueltas de un jugador.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Establece el nivel de efecto de isla de la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Establece límite de entidades para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transfiere una isla a otra persona.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Establece el multiplicador de drop de los mobs para la isla de otro jugador' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Establezca un rol obligatorio para obtener un permiso para todas las islas.' COMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Establece la calificación de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Set role limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Alternar la configuración de una isla específica.' COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Cambiar el porcentaje de un material para el generador de adoquines.' COMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Cambia el tamaño de la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Establezca la ubicación de spawn del servidor.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Establezca el multiplicador de tasas de spawn para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Establecer límite de miembros para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Establece el nivel de una mejora para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Establece el límite de warps de una isla.' COMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Abra el editor de configuración del plugin' COMMAND_DESCRIPTION_ADMIN_SHOW: 'Obtén información sobre una isla.' COMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teletransportarse a la ubicación de spawn' COMMAND_DESCRIPTION_ADMIN_SPY: 'Alternar el modo espía de chat' COMMAND_DESCRIPTION_ADMIN_STATS: 'Mostrar estadísticas sobre el plugin.' COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sincronizar valores de actualización para una isla.' COMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teletransportarse a otras islas.' COMMAND_DESCRIPTION_ADMIN_TITLE: 'Send a player a title.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Send to all island members a title.' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Ignora una isla de las islas superiores.' COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Desbloquea un mundo para una isla.' COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Retirar dinero del banco de la isla de otro jugador.' COMMAND_DESCRIPTION_BALANCE: 'Verifique la cantidad de dinero dentro del banco de una isla.' COMMAND_DESCRIPTION_BAN: 'Prohibir a un jugador de tu isla.' COMMAND_DESCRIPTION_BANK: 'Abre el banco de la isla.' COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: 'Cambia el bioma de la isla.' COMMAND_DESCRIPTION_BORDER: 'Cambia el color del borde de las islas.' COMMAND_DESCRIPTION_CHEST: 'Abre el cofre de la isla.' COMMAND_DESCRIPTION_CLOSE: 'Cerrar la isla al público.' COMMAND_DESCRIPTION_COOP: 'Agrega un jugador como cooperativo a tu isla.' COMMAND_DESCRIPTION_COOPS: 'Abre el menú cooperativo.' COMMAND_DESCRIPTION_COUNTS: 'Ver la cantidad de bloques de tu isla.' COMMAND_DESCRIPTION_CREATE: 'Crea una nueva isla.' COMMAND_DESCRIPTION_DEL_WARP: 'Elimina un warp de la isla' COMMAND_DESCRIPTION_DEMOTE: 'Degradar a un miembro en tu isla.' COMMAND_DESCRIPTION_DEPOSIT: 'Deposite dinero de su cuenta personal en el banco de la isla.' COMMAND_DESCRIPTION_DISBAND: 'Disuelve tu isla de forma permanente.' COMMAND_DESCRIPTION_EXPEL: 'Echa un visitante de tu isla.' COMMAND_DESCRIPTION_FLY: 'Alternar el vuelo dentro de la isla.' COMMAND_DESCRIPTION_HELP: 'Lista de todos los comandos.' COMMAND_DESCRIPTION_INVITE: 'Invita a un jugador a tu isla.' COMMAND_DESCRIPTION_KICK: 'Echa un jugador de tu isla.' COMMAND_DESCRIPTION_LANG: 'Cambia tu idioma personal.' COMMAND_DESCRIPTION_LEAVE: 'Deja tu isla.' COMMAND_DESCRIPTION_MEMBERS: 'Abra el menú de miembros.' COMMAND_DESCRIPTION_MISSION: 'Completa una misión.' COMMAND_DESCRIPTION_MISSIONS: 'Abre el menú de misiones' COMMAND_DESCRIPTION_NAME: 'Cambia el nombre de tu isla.' COMMAND_DESCRIPTION_OPEN: 'Abra la isla al público.' COMMAND_DESCRIPTION_PANEL: 'Abre el panel de la isla.' COMMAND_DESCRIPTION_PARDON: 'Elimina la prohibición de un jugador de tu isla.' COMMAND_DESCRIPTION_PERMISSIONS: 'Obtenga todos los permisos para un rol de isla.' COMMAND_DESCRIPTION_PROMOTE: 'Asciende a un miembro en tu isla.' COMMAND_DESCRIPTION_RANKUP: 'Sube de nivel una mejora.' COMMAND_DESCRIPTION_RATE: 'Califica una isla.' COMMAND_DESCRIPTION_RATINGS: 'Mostrar todas las clasificaciones de islas.' COMMAND_DESCRIPTION_SETTINGS: 'Abre el menú de configuración.' COMMAND_DESCRIPTION_RECALC: 'Vuelve a calcular el valor de la isla.' COMMAND_DESCRIPTION_SET_DISCORD: 'Establece el discord de la isla para los pagos.' COMMAND_DESCRIPTION_SET_PAYPAL: 'Configure el correo electrónico de PayPal de la isla para los pagos.' COMMAND_DESCRIPTION_SET_ROLE: 'Cambia el papel de un jugador en tu isla.' COMMAND_DESCRIPTION_SET_TELEPORT: 'Cambia la ubicación del teletransporte de tu isla.' COMMAND_DESCRIPTION_SET_WARP: 'Crea una nueva deformación de isla.' COMMAND_DESCRIPTION_SHOW: 'Obtén información sobre una isla.' COMMAND_DESCRIPTION_TEAM: 'Obtenga información sobre el estado de los miembros de la isla.' COMMAND_DESCRIPTION_TEAM_CHAT: 'Alternar el modo de chat de equipo.' COMMAND_DESCRIPTION_TELEPORT: 'Teletransportarse a su isla.' COMMAND_DESCRIPTION_TOGGLE: 'Alternar el borde de la isla y ubicaciones del apilador de bloques.' COMMAND_DESCRIPTION_TOP: 'Abre el panel de Top Islas.' COMMAND_DESCRIPTION_TRANSFER: 'Transfiera el liderazgo de su isla.' COMMAND_DESCRIPTION_UNCOOP: 'Elimina a un jugador cooperativo de tu isla.' COMMAND_DESCRIPTION_UPGRADE: 'Abre el panel de actualizaciones.' COMMAND_DESCRIPTION_VALUE: 'Obtenga el valor de un bloque.' COMMAND_DESCRIPTION_VALUES: 'Abrir el menú de valores.' COMMAND_DESCRIPTION_VISIT: 'Teletransportarse a la ubicación de los visitantes de una isla..' COMMAND_DESCRIPTION_VISITORS: 'Abrir el menú de visitantes.' COMMAND_DESCRIPTION_WARP: 'Teletransportarse al warp de una isla.' COMMAND_DESCRIPTION_WARPS: 'Abre el menu de warps' COMMAND_DESCRIPTION_WITHDRAW: 'Retire dinero del banco de su isla a su cuenta personal.' COMMAND_USAGE: '&cUsa: /{0}' COOP_ANNOUNCEMENT: '&e&lIsla | &7{0} agregado {1} como miembro de la cooperativa.' COOP_BANNED_PLAYER: '&c&lError | &7Este jugador está prohibido de la isla y no puede ser cooperativo.' COOP_LIMIT_EXCEED: '&c&lError | &7Alcanzaste la cantidad máxima de jugadores cooperativos que puede tener la isla.' CREATE_ISLAND: '&e&lIsla | &7Creó una nueva isla en {0} en {1}ms.' CREATE_ISLAND_FAILURE: '&c&lError | &7Se produjo un error al crear su isla. Comuníquese con el administrador para investigar el problema.' CREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.' DEBUG_MODE_DISABLED: '&e&lDebug | &7Modo de depuración &cAPAGADO&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7Modo de depuración &aENCENDIDO&7.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.' DELETE_WARP: '&e&lIsla | &7Eliminaste el warp {0}.' DELETE_WARP_SIGN_BROKE: '&7&oHabía un letrero para esa warp, pero se rompió...' DEMOTE_LEADER: '&c&lError | &7No se puede degradar a los líderes de las islas.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Solo puedes degradar a jugadores con un rol de isla más bajo que el tuyo.' DEMOTED_MEMBER: '&e&lIsla | &7Has degradado a {0} a {1} en su isla.' DEPOSIT_ANNOUNCEMENT: '&e&lBanco | &7{0} depositó $ {1} en el banco de la isla.' DEPOSIT_ERROR: '&c&lError | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lError | &7No puede destruir fuera de su rango de protección.' DISBAND_ANNOUNCEMENT: '&e&lIsla | &7Tu isla fue disuelta por {0}.' DISBAND_GIVE: '&e&lIsla | &7Recibiste {0} disoluciones.' DISBAND_GIVE_ALL: '&e&lIsla | &7Le diste {0} disoluciones a todos los jugadores.' DISBAND_GIVE_OTHER: '&e&lIsla | & 7Diste {0} disoluciones a {1}.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oYour island was disbanded and ${0} dollars were refunded to your account from the island bank' DISBAND_SET: '&e&lIsla | &7Su recuento de disoluciones se estableció en {0}.' DISBAND_SET_ALL: '&e&lIsla | &7Establece el recuento de disolución de todos los jugadores en {0}.' DISBAND_SET_OTHER: '&e&lIsla | &7Establece el recuento de disolución de {0} en {1}.' DISBANDED_ISLAND: '&e&lIsla | &7You disbanded your island.' DISBANDED_ISLAND_OTHER: '&e&lIsla | &7Disolviste la isla de {0}.' DISBANDED_ISLAND_OTHER_NAME: '&e&lIsla | &7Disolviste la isla {0}.' ENTER_PVP_ISLAND: '&7&oSeras teletransportado a una isla con PVP habilitado. Seras inmune por 10 segundos...' EXPELLED_PLAYER: '&e&lIsla | &7{0} fue expulsado de la isla.' FORMAT_QUAD: 'Q' FORMAT_TRILLION: 'T' FORMAT_BILLION: 'B' FORMAT_MILLION: 'M' FORMAT_THOUSANDS: 'K' FORMAT_SECONDS_NAME: 'segundos' FORMAT_SECOND_NAME: 'segundo' FORMAT_MINUTES_NAME: 'minutos' FORMAT_MINUTE_NAME: 'minuto' FORMAT_HOURS_NAME: 'horas' FORMAT_HOUR_NAME: 'hora' FORMAT_DAYS_NAME: 'dias' FORMAT_DAY_NAME: 'dia' GENERATOR_CLEARED: '&e&lIsla | &7Se borraron con éxito las cantidades del generador para la isla de {0}.' GENERATOR_CLEARED_NAME: '&e&lIsla | &7Borró con éxito las cantidades del generador para la isla de {0}.' GENERATOR_CLEARED_ALL: '&e&lIsla | &7Limpió con éxito las cantidades del generador para todas las islas.' GENERATOR_UPDATED: '&e&lIsla | &7Se actualizó correctamente la cantidad del generador de {0} a la isla de {1}.' GENERATOR_UPDATED_NAME: '&e&lIsla | &7Se actualizó correctamente la cantidad del generador de {0} a la isla de {1}.' GENERATOR_UPDATED_ALL: '&e&lIsla | &7Se actualizó correctamente la cantidad del generador de {0} en todas las islas.' GLOBAL_COMMAND_EXECUTED: '&e&lIsland | &7Successfully executed the command on {0}''s island members!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lIsland | &7Successfully executed the command on the island members of {0}!' GLOBAL_MESSAGE_SENT: '&e&lIsla | &7Se envió correctamente el mensaje a los miembros de la isla de {0}' GLOBAL_MESSAGE_SENT_NAME: '&e&lIsla | &7¡Se envió correctamente el mensaje a los miembros de la isla de {0}!' GLOBAL_TITLE_SENT: '&e&lIsland | &7Successfully sent to {0}''s island members the title!' GLOBAL_TITLE_SENT_NAME: '&e&lIsland | &7Successfully sent to the island members of {0} the title!' GOT_BANNED: '&e&lIsla | &7Fuiste PROHIBIDO de la isla de {0}.' GOT_DEMOTED: '&e&lIsla | &7Fuiste degradado a {0} en tu isla.' GOT_EXPELLED: '&e&lIsla | &7&o{0} te expulsó de la isla.' GOT_INVITE: '&e&lIsla | &7{0} te invitó a su isla.' GOT_INVITE_TOOLTIP: '&7Haga click en el mensaje para aceptar la invitación.' GOT_KICKED: '&e&lIsla | &7{0} te echó de tu isla.' GOT_PROMOTED: '&e&lIsla | &7Te ascendieron a {0} en tu isla.' GOT_REVOKED: '&e&lIsla | &7{0} revocó su invitación a su isla.' GOT_UNBANNED: '&e&lIsla | &7Estas PERMTIDO nuevamente en la isla de {0}.' HIT_ISLAND_MEMBER: '&c&lError | &7No puedes golpear a los miembros de tu isla.' HIT_PLAYER_IN_ISLAND: '&c&lError | &7No puedes golpear a los jugadores dentro de las islas.' IGNORED_ISLAND: '&e&lIsla | &7La isla de {0} ahora ignora el TOP ISLAS ' IGNORED_ISLAND_NAME: '&e&lIsla | &7La isla de {0} ahora ignora el TOP ISLAS' INTERACT_OUTSIDE_ISLAND: '&c&lError | &7No puede interactuar fuera de su rango de protección.' INVALID_AMOUNT: '&c&lError | &7Cantidad no válida {0}.' INVALID_BIOME: '&c&lError | &7Bioma no válido {0}.' INVALID_BLOCK: '&c&lError | &7Ubicación de bloque no válida {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lError | &7Efecto no válido {0}.' INVALID_ENTITY: '&c&lError | &7Entidad no válida {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lError | &7No tienes una isla.' INVALID_ISLAND_LOCATION: '&c&lError | &7No hay ninguna isla en tu ubicación.' INVALID_ISLAND_OTHER: '&c&lError | &7{0} no tiene una isla.' INVALID_ISLAND_OTHER_NAME: '&c&lError | &7No hay ninguna isla con el nombre {0}.' INVALID_ISLAND_PERMISSION: | &c&lError | &7No se pudo encontrar el permiso de la isla {0}. &c&lError | &7Permisos de la isla: {1} INVALID_LEVEL: '&c&lError | &7Nivel {0} no válido.' INVALID_LIMIT: '&c&lError | &7Límite no válido {0}.' INVALID_MATERIAL: '&c&lError | &7Material no válido {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Misión no válida {0}.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lError | &7Multiplicador no válido {0}.' INVALID_PAGE: '&c&lError | &7Página no válida {0}.' INVALID_PERCENTAGE: '&c&lError | &7El porcentaje debe estar entre 0 y 100.' INVALID_PLAYER: '&c&lError | &7No se puede encontrar un jugador llamado {0}' INVALID_RATE: | &c&lError | &7No pudimos encontrar un rating {0}. &c&lError | &7Rating de la isla: {1} INVALID_ROWS: '&c&lError | &7Cantidad de filas no válida: {0}' INVALID_ROLE: | &c&lError | &7No se pudo encontrar el rol {0}. &c&lError | &7Roles de la isla: {1} INVALID_SCHEMATIC: '&c&lError | &7No se pudo encontrar una esquematica/schematic con el nombre {0}.' INVALID_SETTINGS: | &c&lError | &7No se pudo encontrar la configuración de la isla {0}. &c&lError | &7Configuración de la isla: {1} INVALID_SIZE: '&c&lError | &7Tamaño no válido {0}.' INVALID_SLOT: '&c&lError | &7Invalid slot {0}.' INVALID_TITLE: '&c&lError | &7Invalid title entered.' INVALID_TOGGLE_MODE: '&c&lError | &7No se puede alternar {0}.' INVALID_UPGRADE: | &c&lError | &7No se pudo encontrar una mejora llamada {0}. &c&lError | &7Mejoras: {1} INVALID_VISIT_LOCATION: '&c&lError | &7Esta isla no tiene ubicación para visitantes.' INVALID_VISIT_LOCATION_BYPASS: '&7&oTienes modo bypass, teletransportándote a la isla...' INVALID_WARP: '&c&lError | &7Warp invalido {0}.' INVALID_WORLD: '&c&lError | &7Mundo invalido {0}.' INVITE_ANNOUNCEMENT: '&e&lIsla | &7{0} ha invitado a {1} a la isla.' INVITE_BANNED_PLAYER: '&c&lError | &7Este jugador está PROHIBIDO de la isla y no puede ser invitado.' INVITE_TO_FULL_ISLAND: '&c&lError | &7No puedes invitar a más miembros a tu isla.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lError | &7Ya existe una isla con ese nombre.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBanco | &7El banco de la isla está vacío.' ISLAND_BANK_SHOW: '&e&lBanco | &7Tu isla tiene ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBanco | &7La isla de {0} tiene ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanco | &7La isla {0} tiene ${1}.' ISLAND_BEING_CALCULATED: '&c&lError | &7¡No puedes interactuar con bloques cuando se calcula la isla!' ISLAND_CLOSED: '&e&lIsla | &7Cerró con éxito la isla al público.' ISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7Ya tienes una tarea de creación de islas en curso.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsla | &7Procesando su solicitud...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lVuelo | &7El vuelo de la isla fue automáticamente &cdesactivado&7.' ISLAND_FLY_ENABLED: '&e&lVuelo | &7El vuelo de la isla fue automáticamente &aactivado&7.' ISLAND_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...' ISLAND_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...' ISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Desarrollado por Ome_R - Traducido al español por: Aymac' ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista de comandos [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Usa /is help {0} para la siguiente pagina.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIsla | &7Límite bancario: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lIsla | &7Límites de bloques: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIsla | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIsla | &7Límite de juegadores coop: {0}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIsla | &7Multiplicador de cultivos: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIsla | &7Multiplicador de drops: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lIsla | &7Efectos de la isla: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIsla | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lIsla | &7Límites de entidades: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIsla | &7 {0}: {1}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lIsla | &7Tasas de generación ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIsla | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lIsland | &7Role Limits: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lIsla | &7Tamaño del borde: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIsla | &7Multiplicador de Spawners: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIsla | &7Límite de equipo: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lIsla | &7Mejoras: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIsla | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIsla | &7Limite de Warps: {0}' ISLAND_INFO_BANK: '&e&lIsla | &7Banco: {0}' ISLAND_INFO_BONUS: '&e&lIsla | &7Valor de Bonus: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lIsla | &7Nivel de Bonus: {0}' ISLAND_INFO_CREATION_TIME: '&e&lIsla | &7Tiempo de creación: {0}' ISLAND_INFO_DISCORD: '&e&lIsla | &7Discord: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lIsla | &7Última actualización: {0} ago' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIsla | &7Última actualización: &aActualmente activo' ISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}' ISLAND_INFO_LOCATION: '&e&lIsla | &7Casa: {0}' ISLAND_INFO_NAME: '&e&lIsla | &7Nombre: {0}' ISLAND_INFO_OWNER: '&e&lIsla | &7Lider: {0}' ISLAND_INFO_PAYPAL: '&e&lIsla | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lIsla | &7 - {0}' ISLAND_INFO_RATE: '&e&lIsla | &7Calificación: {0} &7({1}/5) - {2} calificaciones totales.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: '✦' ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIsla | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIsla | &7Número de visitantes: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIsla | &7Valor: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsla | &7Abrió con éxito la isla al público.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVista Previa | &7Fuiste demasiado lejos y ya no estás en modo de vista previa.' ISLAND_PREVIEW_CANCEL: '&e&lVista Previa | &7Cancelaste el modo de vista previa.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' ISLAND_PREVIEW_CANCEL_TEXT: 'CANCELAR' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lVista Previa | &7Ha iniciado el modo de vista previa de la esquematica/schematic {0}... &e&lVista Previa | &7Type &a&lCONFIRM &7para crear una nueva isla, o &c&lCANCELAR &7para cancelar el modo de vista previa. &e&lVista Previa | &7No puede salir del área de la isla, de lo contrario el modo de vista previa se cancelará automáticamente. ISLAND_PROTECTED: '&c&lError | &7Esta isla está protegida.' ISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lIsla | &7Miembros de la isla de {0} &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Desconectado)' ISLAND_TEAM_STATUS_ONLINE: '&a(En línea)' ISLAND_TEAM_STATUS_ROLES: '&e&lIsla | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Desconectado)' ISLAND_TOP_STATUS_ONLINE: '&a(En línea)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Privado]' ISLAND_WAS_CLOSED: '&e&lIsla | &7&oLa isla en la que estabas fue cerrada y te teletransportaron de regreso al spawn...' ISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.' ISLAND_WORTH_RESULT: '&e&lIsla | &7El valor de tu isla es {0} [Nivel {1}]' ISLAND_WORTH_TIME_OUT: '&c&lError | &7The calculation task has timed out. Try again later...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lIsla | &7{0} se ha unido a tu isla.' JOIN_ANNOUNCEMENT: '&e&lIsla | &7{0} se ha unido a tu isla.' JOIN_FULL_ISLAND: '&c&lError | &7Esta isla alcanzó la cantidad máxima de miembros permitidos.' JOIN_WHILE_IN_ISLAND: '&c&lError | &7Ya estás dentro de una isla.' JOINED_ISLAND: '&e&lIsla | &7Te uniste a la isla de {0}.' JOINED_ISLAND_NAME: '&e&lIsla | &7Te uniste a la isla {0}.' JOINED_ISLAND_AS_COOP: '&e&lIsla | &7Ahora eres un miembro cooperativo de la isla de {0}.' JOINED_ISLAND_AS_COOP_NAME: '&e&lIsla | &7Ahora eres miembro cooperativo de la isla {0}.' KICK_ANNOUNCEMENT: '&e&lIsla | &7{0} fue expulsado de la isla por {1}.' KICK_ISLAND_LEADER: '&c&lError | &7No puedes expulsar al líder de la isla.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Solo puedes expulsar a jugadores con un rol de isla más bajo que el tuyo.' LACK_CHANGE_PERMISSION: '&c&lError | &7Debe tener este permiso para poder cambiarlo a otros roles.' LAST_ROLE_DEMOTE: '&c&lError | &7Ya no puedes degradar a este jugador.' LAST_ROLE_PROMOTE: '&c&lError | &7Ya no puedes promocionar a este jugador.' LEAVE_ANNOUNCEMENT: '&e&lIsla | &7{0} abandonó la isla.' LEAVE_ISLAND_AS_LEADER: |- &c&lError | &7No puedes dejar tu isla cuando eres el lider. &c&lError | &7Puede transferir el lider utilizando /is transfer. LEFT_ISLAND: '&e&lIsla | &7Dejaste tu isla.' LEFT_ISLAND_COOP: '&e&lIsla | &7Ya no eres miembro cooperativo de la isla de {0}.' LEFT_ISLAND_COOP_NAME: '&e&lIsla | &7Ya no eres miembro cooperativo de la isla de {0}.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lError | &7Debe proporcionar un material sólido.' MAXIMUM_LEVEL: '&c&lError | &7El nivel máximo para esta actualización es {0}.' MESSAGE_SENT: '&e&lIsla | &7Se envió correctamente {0} el mensaje.!' MISSION_CANNOT_COMPLETE: '&c&lError | &7Aún no puedes completar esta misión.' MISSION_NO_AUTO_REWARD: '&e&lMisiones | &7Tienes todos los materiales necesarios para terminar la mision: {0}, usa /is missions para completar!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lError | &7Debes completar {0} antes de completar esta misión.' MISSION_STATUS_COMPLETE: '&e&lMisiones | &7Se cambió el estado de la misión {0} a completada para {1}.' MISSION_STATUS_COMPLETE_ALL: '&e&lMisiones | &7Se cambió el estado de todas las misiones a completadas para {0}.' MISSION_STATUS_RESET: '&e&lMisiones | &7Se restablecio el estado de la misión {0} para {1}.' MISSION_STATUS_RESET_ALL: '&e&lMisiones | &7Se restableció el estado de todas misiones para {0}.' MODULE_ALREADY_INITIALIZED: '&e&lModule | &7This module is already loaded.' MODULE_INFO: | &e&lModule | &7{0} by {1} &e&lModule | &7&m-------------------- &e&lModule | &7{2} MODULE_LOADED_SUCCESS: '&e&lModule | &7Successfully loaded the module {0}.' MODULE_LOADED_FAILURE: '&e&lModule | &7Couldn''t load the module {0}. Check out the console for more information.' MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lIsla | &7{0} cambió el nombre de su isla a {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lError | &7No puedes usar ese nombre.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lError | &7No puedes usar nombres de jugadores como nombres de islas.' NAME_TOO_LONG: '&c&lError | &7Los nombres de las islas no pueden tener más de {0} caracteres.' NAME_TOO_SHORT: '&c&lError | &7Los nombres de las islas no pueden tener menos de {0} caracteres.' NO_BAN_PERMISSION: '&c&lError | &7Debes ser al menos {0} para prohibir a los jugadores' NO_CLOSE_BYPASS: '&c&lError | &7Esta isla no está abierta al público.' NO_CLOSE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder cerrar la isla al público.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder agregar jugadores como miembros cooperativos.' NO_DELETE_WARP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para eliminar warps.' NO_DEMOTE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para degradar jugadores.' NO_DEPOSIT_PERMISSION: '&c&lError | &7Debe tener al menos {0} para depositar dinero en el banco de la isla.' NO_DISBAND_PERMISSION: '&c&lError | &7Debes tener al menos {0} para disolver tu isla.' NO_EXPEL_PERMISSION: '&c&lError | &7Debes tener al menos {0} para expulsar a los jugadores de tu isla.' NO_INVITE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder invitar jugadores.' NO_ISLAND_CHEST_PERMISSION: '&c&lError | &7Debes tener al menos {0} para acceder al cofre de la isla.' NO_ISLAND_INVITE: '&c&lError | &7No se pudieron encontrar invitaciones de esta isla.' NO_ISLANDS_TO_PURGE: '&c&lError | &7No había islas que purgar.' NO_KICK_PERMISSION: '&c&lError | &7Debes tener al menos {0} para patear a los jugadores.' NO_MORE_DISBANDS: '&c&lError | &7No puedes disolver más islas.' NO_MORE_WARPS: '&c&lError | &7Tu isla no puede tener más warps.' NO_NAME_PERMISSION: '&c&lError | &7No puedes cambiar el nombre de tu isla.' NO_OPEN_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder abrir la isla al público.' NO_PERMISSION_CHECK_PERMISSION: '&c&lError | &7Debe tener al menos {0} para obtener información sobre permisos.' NO_PROMOTE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para promocionar jugadores.' NO_RANKUP_PERMISSION: '&c&lError | &7Debe tener al menos {0} para poder subir de rango en las mejoras.' NO_RATINGS_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder verificar las calificaciones.' NO_SET_BIOME_PERMISSION: '&c&lError | &7Debes tener al menos {0} para cambiar el bioma de la isla.' NO_SET_DISCORD_PERMISSION: '&c&lError | &7Debes tener al menos {0} para cambiar el discord de la isla' NO_SET_HOME_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder establecer la ubicación de teletransporte de la isla.' NO_SET_PAYPAL_PERMISSION: '&c&lError | &7Debe tener al menos {0} para poder cambiar el correo electrónico de PayPal de la isla.' NO_SET_ROLE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder establecer roles para los jugadores.' NO_SET_SETTINGS_PERMISSION: '&c&lError | &7Debe tener al menos {0} para cambiar la configuración de la isla.' NO_SET_WARP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder establecer warps en la isla.' NO_TRANSFER_PERMISSION: '&c&lError | &7Debes ser el líder de la isla para transferir el liderazgo.' NO_UNCOOP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para remover jugadores cooperativos.' NO_UPGRADE_PERMISSION: '&c&lError | &7No tiene permiso para actualizar a otro nivel.' NO_WITHDRAW_PERMISSION: '&c&lError | &7Debe tener al menos {0} para poder retirar dinero del banco de la isla.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lError | &7No tienes suficiente dinero para depositar ${0} en el banco de tu isla.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lError | &7No tienes suficiente dinero.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7You don''t have enough money to use island warps.' OPEN_MENU_WHILE_SLEEPING: '&7&oEstás demasiado cansado para interactuar con los menús, ¿no crees?' PANEL_TOGGLE_OFF: |- &e&lPanel | &7Panel de la isla &cAPAGADO&7. &e&lPanel | &7Usa /is para teletransportarse a la isla. PANEL_TOGGLE_ON: |- &e&lPanel | &7Panel de la isla &aENCENDIDO&7. &e&lPanel | &7Usa /is para abrir el panel. PERMISSION_CHANGED: '&e&lIsla | &7Se actualizó correctamente el permiso {0} de la isla de {1}.' PERMISSION_CHANGED_NAME: '&e&lIsla | &7Se actualizó correctamente el permiso {0} de la isla {1}.' PERMISSION_CHANGED_ALL: '&e&lIsla | &7Se actualizó correctamente el permiso {0} para todas las islas.' PERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.' PERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIsla | &7¡Restableció correctamente todos los permisos de {0} a los valores predeterminados!' PERMISSIONS_RESET_ROLES: '&e&lIsla | &7¡Restableció con éxito todos los permisos de la isla a los valores predeterminados!' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Yes' PLAYER_ALREADY_BANNED: '&c&lError | &7Este jugador ya está prohibido.' PLAYER_ALREADY_COOP: '&c&lError | &7Este jugador ya es coop.' PLAYER_ALREADY_IN_ISLAND: '&c&lError | &7Este jugador ya está dentro de una isla.' PLAYER_ALREADY_IN_ROLE: '&c&lError | &7{0} ya es un {1}.' PLAYER_EXPEL_BYPASS: '&c&lError | &7Este usuario no puede ser expulsado de la isla.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lIsla | &7{0} se unió al servidor.' PLAYER_NOT_BANNED: '&c&lError | &7Este jugador no está prohibido.' PLAYER_NOT_COOP: '&c&lError | &7Este jugador no es cooperativo.' PLAYER_NOT_INSIDE_ISLAND: '&c&lError | &7Este jugador no está dentro de tu isla.' PLAYER_NOT_ONLINE: '&c&lError | &7Este jugador no está en línea!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lIsla | &7{0} abandonó el servidor.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lError | &7Solo puedes promover jugadores con un rol de isla menor que el tuyo.' PROMOTED_MEMBER: '&e&lIsla | &7Ascendiste a {0} a {1} en su isla.' PURGE_CLEAR: '&e&lIsla | &7Limpió con éxito todas las islas en cola para purgar.' PURGED_ISLANDS: |- &e&lIsla | &7{0} las islas se purgarán cuando se reinicie el servidor. &e&lIsla | &7Puede cancelarlo en cualquier momento usando /is admin purge cancel. RANKUP_SUCCESS: '&e&lIsla | &7Se actualizó correctamente el nivel de la mejora {0} para la isla de {1}.' RANKUP_SUCCESS_ALL: '&e&lIsla | &7e actualizó correctamente el nivel de la mejora {0} para todas las islas.' RANKUP_SUCCESS_NAME: '&e&lIsla | &7&7Se actualizó correctamente el nivel de la mejora {0} para la isla de {1}.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIsla | &7¡{0} ha calificado tu isla con un {1} de 5 !' RATE_CHANGE_OTHER: '&e&lIsla | &7Cambiaste la calificación de {0} a {1}.' RATE_OWN_ISLAND: '&c&lError | &7No puedes calificar tu propia isla.' RATE_REMOVE_ALL: '&e&lIsla | &7Se eliminaron con éxito todas las calificaciones de {0}.' RATE_REMOVE_ALL_ISLANDS: '&e&lIsland | &7Successfully removed all ratings of all the islands.' RATE_SUCCESS: '&e&lIsla | &7¡Calificaste esta isla con {0} estrellas!' REACHED_BLOCK_LIMIT: '&e&lMejoras| &7Has alcanzado el límite de {0} bloques de la isla.' REACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.' RECALC_ALREADY_RUNNING: '&c&lError | &7Tu isla ya está siendo calculada.' RECALC_ALREADY_RUNNING_OTHER: '&c&lError | &7Esta isla ya está siendo calculada.' RECALC_ALL_ISLANDS: '&e&lIsla | &7Volviendo a calcular todas las islas...' RECALC_ALL_ISLANDS_DONE: '&e&lIsla | &7Terminado con éxito de recalcular todas las islas.' RECALC_PROCCESS_REQUEST: '&e&lIsla | &7Procesando su solicitud...' RELOAD_COMPLETED: '&e&lIsla | &7Plugin recargado correctamente!' RELOAD_PROCCESS_REQUEST: '&e&lIsla | &7Empezando a recargar las configuraciones...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lIsla | &7{0} revocó la invitación de {1} a la isla.' RESET_WORLD_SUCCEED: '&e&lIsland | &7Successfully reset the world {0} for {1}''s island.' RESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for all the islands.' RESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.' SAME_NAME_CHANGE: '&c&lError | &7Debes ingresar un nombre diferente al nombre de tu isla actual.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Posición seleccionada #2 ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lError | &7No ha seleccionado dos posiciones.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Procesando su solicitud...' SCHEMATIC_READY_TO_CREATE: | &e&lSchematics | &7Ha seleccionado dos posiciones. Ejecute /is admin schematic para crear una nueva Schematic/Esquematica. &e&lSchematics | &7Asegúrese de estar parado en la ubicación de teletransportación al ejecutar el comando. SCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Posición seleccionada #1 ({0})' SCHEMATIC_SAVED: '&e&lSchematics | &7Schematic/Esquematica guardada correctamente!' SELF_ROLE_CHANGE: '&c&lError | &7No puedes cambiar tu rol.' SET_UPGRADE_LEVEL: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} para la isla de {1}.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} para {1}.' SET_WARP: '&e&lIsla | &7Se creó con éxito una nuevo warp en {0}.' SET_WARP_OUTSIDE: '&c&lError | &7No puedes establecer warps fuera de tu isla.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsla | &7Se actualizó correctamente la configuración {0} a la isla de {1}.' SETTINGS_UPDATED_NAME: '&e&lIsla | &7Se actualizó correctamente la configuración {0} de la isla {1}.' SETTINGS_UPDATED_ALL: '&e&lIsla | &7Se actualizó correctamente la configuración {0} en todas las islas.' SIZE_BIGGER_MAX: '&c&lError | &7No puede establecer un tamaño más grande que el tamaño máximo de la isla.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Teletransportado exitosamente a {0} al spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Se actualizó correctamente la ubicación de spawn a {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Espía] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lMejoras| &7Se sincronizaron correctamente todos los valores de actualización de la isla de {0}.' SYNC_UPGRADES_ALL: '&e&lMejoras| &7Se sincronizaron con éxito todos los valores de actualización de todas las islas.' SYNC_UPGRADES_NAME: '&e&lMejoras| &7Se sincronizaron correctamente todos los valores de actualización de {0}.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lError | &7No estás dentro de tu isla.' TELEPORT_OUTSIDE_ISLAND: '&c&lError | &7No puedes teletransportarte fuera de tu rango de protección.' TELEPORT_WARMUP: '&7&oSerás teletransportado en {0}... ¡No te muevas!' TELEPORT_WARMUP_CANCEL: '&7&oTe moviste y la teletransportación fue cancelada.' TITLE_SENT: '&e&lIsland | &7Successfully sent {0} the title!' TELEPORTED_FAILED: '&e&lIsla | &7Parece que esta isla no tiene seguridad bloqueada. Póngase en contacto con un miembro del staff.' TELEPORTED_SUCCESS: '&e&lIsla | &7Fuiste teletransportado a tu isla.' TELEPORTED_TO_WARP: '&e&lIsla | &7Teletransportado con éxito al warp de esta isla' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIsland | &7The player {0} teleported to the island warp {1}.' TOGGLED_BYPASS_OFF: '&e&lBypass | &7Modo de bypass &cAPAGADO&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Modo de bypass &aENCENDIDO&7.' TOGGLED_FLY_OFF: '&e&lVuelo | &7Vuelo en la isla &cAPAGADO&7.' TOGGLED_FLY_ON: '&e&lVuelo | &7Vuelo en la isla &aENCENDIDO&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Alternar el modo schematic/esquematica &cAPAGADO&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchematics | &7Alterna el modo schematic/esquematica a &aENCENDIDO&7. &e&lSchematics | &7Seleccione un área con un hacha de oro. TOGGLED_SPY_OFF: '&e&lEspía | &7Alternar Chat espía &cAPAGADO&7.' TOGGLED_SPY_ON: '&e&lEspía | &7Alternar Chat espía &aENCENDIDO&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lApilador | &7Alternar Apilador de bloques &cAPAGADO&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lApilador | &7Alternar Apilador de bloques &aENCENDIDO&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Alternar chat de equipo &cAPAGADO&7.' TOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Alternar chat de equipo &aENCENDIDO&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lBorde | &7Alternar borde de isla &cAPAGADO&7.' TOGGLED_WORLD_BORDER_ON: '&e&lBorde | &7Alternar borde de isla &aENCENDIDO&7.' TRANSFER_ADMIN: '&e&lIsla | &7Transfirió el liderazgo de {0} a {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lError | &7{0} ya es el líder de su isla.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lError | &7Estos jugadores no están en las mismas islas.' TRANSFER_ADMIN_NOT_LEADER: '&c&lError | &7Este jugador no es líder de ninguna isla.' TRANSFER_ALREADY_LEADER: '&c&lError | &7Ya eres el líder de esta isla.' TRANSFER_BROADCAST: '&e&lIsla | &7El liderazgo de la isla se ha transferido a {0}.' UNBAN_ANNOUNCEMENT: '&e&lIsla | &7{0} esta PERMITIDO nuevamente en la isla {1}.' UNCOOP_ANNOUNCEMENT: '&e&lIsla | &7{0} eliminado {1} de ser miembro cooperativo.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsla | &7{0} abandonó el juego y ya no es miembro cooperativo.' UNIGNORED_ISLAND: '&e&lIsla | &7La isla {0} dejo de ser ingnorada del TOP Islas' UNIGNORED_ISLAND_NAME: '&e&lIsla | &7La isla {0} dejo de ser ingnorada del TOP Islas' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIsla | &7&oParece que este warp no es seguro. Intente con otro warp.' UPDATED_PERMISSION: '&e&lIsla | &7Permisos actualizados para {0}.' UPDATED_SETTINGS: '&e&lIsla | &7Se actualizó la configuración de la isla {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lError | &7No puedes usar ese comando en otras islas.' WARP_ALREADY_EXIST: '&c&lError | &7Ya existe un warp con este nombre.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lWarps | &7Enter a new lore (Type "-cancel" to cancel): &e&lWarps | &7You can separate lines by using "\n". WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type "-cancel" to cancel):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type "-cancel" to cancel):' WARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Successfully updated the category''s icon.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lError | &7Warp category names cannot be empty.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.' WARP_CATEGORY_SLOT: '&e&lWarps | &7Enter a new slot (Type "-cancel" to cancel):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lError | &7This slot is already taken by another category.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Successfully changed the category''s slot to {0}.' WARP_CATEGORY_RENAME: '&e&lWarps | &7Enter a new name (Type "-cancel" to cancel):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another category.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the category to {0}.' WARP_ICON_NEW_LORE: | &e&lWarps | &7Enter a new lore (Type "-cancel" to cancel): &e&lWarps | &7You can separate lines by using "\n". WARP_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type "-cancel" to cancel):' WARP_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type "-cancel" to cancel):' WARP_ICON_UPDATED: '&e&lWarps | &7Successfully updated the warp''s icon.' WARP_ILLEGAL_NAME: '&c&lError | &7Warp names cannot be empty.' WARP_LOCATION_UPDATE: '&e&lWarps | &7Successfully updated the warp''s location to your location.' WARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.' WARP_PUBLIC_UPDATE: '&e&lWarps | &7Successfully opened the warp to the public.' WARP_PRIVATE_UPDATE: '&e&lWarps | &7Successfully closed the warp to the public.' WARP_RENAME: '&e&lWarps | &7Enter a new name (Type "-cancel" to cancel):' WARP_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another warp.' WARP_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the warp to {0}.' WITHDRAW_ALL_MONEY: |- &e&lBanco | &7El banco de la isla sólo tiene {0} dólares dentro. &e&lBanco | &7&oRetirando todo el dinero..." WITHDRAW_ANNOUNCEMENT: '&e&lBanco | &7{0} esta retirado ${1} del banco de la isla!' WITHDRAW_ERROR: '&c&lError | &7{0}.' WITHDRAWN_MONEY: '&e&lBanco | &7¡Retiraste ${0} del banco de la isla de {1}!' WITHDRAWN_MONEY_NAME: '&e&lBanco | &7¡Retiraste ${0} del banco de la isla de {1}!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lMundos | &7¡El mundo {0} aún no está desbloqueado!' ================================================ FILE: src/main/resources/lang/fr-FR.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Développé par Ome_R ## ## ## ###################################################### # Si vous souhaitez créer un nouveau fichier de langue, vous pouvez copier ce fichier, ou vous servir du fichier anglais. # Assurez-vous d'attribuer à votre fichier le nom correct en vous référant au lien ci-dessous. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # Un tutoriel sur la customisation des messages est disponnible à cette adresse : # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lIle | &7{0} a été ajouté à l''île de {1}.' ADMIN_ADD_PLAYER_NAME: '&e&lIle | &e{0} a été ajouté à l''île {1}.' ADMIN_DEPOSIT_MONEY: '&e&lBanque | &7Vous avez déposé {0}$ à la banque d''île de {1}.' ADMIN_DEPOSIT_MONEY_NAME: '&e&lBanque | &7Vous avez déposé {0}$ sur la banque de l''île {1}.' ADMIN_HELP_FOOTER: '&e&lSkyblock' ADMIN_HELP_HEADER: '&e&lSkyblock | &7Liste des Commandes Admin [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSkyblock | &7Utilisez /is admin {0} pour la page suivante.' ALREADY_IN_ISLAND: '&c&lErreur | &7Vous êtes déjà membre d''une île.' ALREADY_IN_ISLAND_OTHER: '&c&lErreur | &7Ce joueur est déjà membre de votre île.' BAN_ANNOUNCEMENT: '&e&lIle | &7{0} a été BANNI de l''île par {1}.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lErreur | &7Vous ne pouvez bannir que les joueurs d''un rôle d''île inférieur au votre.' BANK_DEPOSIT_CUSTOM: '&e&lBanque | &7Entrez le montant que vous souhaitez déposer:' BANK_DEPOSIT_COMPLETED: Dépot Effectué BANK_LIMIT_EXCEED: '&c&lErreur | &7Vous avez dépassé votre cota bancaire.' BANK_WITHDRAW_CUSTOM: '&e&lBanque | &7Entrez le montant que vous souhaitez retirer:' BANK_WITHDRAW_COMPLETED: Retrait Effectué BANNED_FROM_ISLAND: '&c&lErreur | &7Vous êtes banni de cette île.' BLOCK_COUNT_CHECK: '&e&lIle | &7Cette île possède x{0} {1}.' BLOCK_COUNTS_CHECK: | &e&lIle | &7Cette île possède les blocs suivants: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lIle | &7Cette île ne possède aucun bloc comptant dans les statistiques.' BLOCK_COUNTS_CHECK_MATERIAL: x{0} {1} BLOCK_LEVEL: '&e&lNiveau | &7Le le niveau du bloc {0} est de {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lNiveau | &7Le bloc {0} n''a pas de valeur.' BLOCK_VALUE: '&e&lValeur | &7La valeur du bloc {0} est de {1}.' BLOCK_VALUE_WORTHLESS: '&e&lValeur | &7Le bloc {0} n''a pas de valeur.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Bleue' BORDER_PLAYER_COLOR_NAME_RED: 'Rouge' BORDER_PLAYER_COLOR_NAME_GREEN: 'Verte' BORDER_PLAYER_COLOR_UPDATED: '&e&lBordure | &7Votre bordure d''île personnelle est désormais {0}.' BUILD_OUTSIDE_ISLAND: '&c&lErreur | &7Vous ne pouvez pas construire en dehors de votre zone de protection.' CANNOT_SET_ROLE: '&c&lErreur | &7Vous ne pouvez pas définir le rôle de ce joueur sur {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lErreur | &7Vous pouvez uniquement changer les permissions des rôles d''île inférieurs au votre.' CHANGED_BANK_LIMIT: '&e&lAméliorations | &7Mise à jour de la limite bancaire de l''île de {0}.' CHANGED_BANK_LIMIT_ALL: '&e&lAméliorations | &7Mise à jour de la limite bancaire de toutes les îles.' CHANGED_BANK_LIMIT_NAME: '&e&lAméliorations | &7Mise à jour de la limite bancaire de {0}.' CHANGED_BIOME: '&e&lIle | &7Le biome a été modifié sur {0}. Vous devez vous reconnecter au serveur afin de voir les modifications.' CHANGED_BIOME_ALL: '&e&lIle | &7Biome de toutes les îles défini sur {0}.' CHANGED_BIOME_NAME: '&e&lIle | &7Biome de l''île {1} défini sur {0}.' CHANGED_BIOME_OTHER: '&e&lIle | &7Biome de l''île de {1} défini sur {0}.' CHANGED_BLOCK_AMOUNT: '&e&lBlocs | &7La quantité de blocs aux coordonnées {0} a été modifiée pour {1}.' CHANGED_BLOCK_LIMIT: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour l''île de {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour toutes les îles.' CHANGED_BLOCK_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour {1}.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour l''île de {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour toutes les îles.' CHANGED_CHEST_SIZE_NAME: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour {2}.' CHANGED_COOP_LIMIT: '&e&lAméliorations | &7Mise à jour de la limite de coopérateurs pour l''île de {0}.' CHANGED_COOP_LIMIT_ALL: '&e&lAméliorations | &7Mise à jour de la limite de coopérateurs pour toutes les îles.' CHANGED_COOP_LIMIT_NAME: '&e&lAméliorations | &7Mise à jour de la limite de coopérateurs pour l''île {0}.' CHANGED_CROP_GROWTH: '&e&lAméliorations | &7Vous avez changé le multiplicateur de croissance des cultures de l''île de {0}.' CHANGED_CROP_GROWTH_ALL: '&e&lAméliorations | &7Vous avez changé le multiplicateur de croissance des cultures de toutes les îles.' CHANGED_CROP_GROWTH_NAME: '&e&lAméliorations | &7Vous avez changé le multiplicateur de croissance des cultures de {0}.' CHANGED_DISCORD: '&e&lIle | &7Vous avez changé le Discord de l''île sur {0}.' CHANGED_ENTITY_LIMIT: '&e&lAméliorations | &7Limite de {0} entities modifiée pour l''île de {1}.' CHANGED_ENTITY_LIMIT_ALL: '&e&lAméliorations | &7Limite de {0} modifiée pour toutes les îles.' CHANGED_ENTITY_LIMIT_NAME: '&e&lAméliorations | &7Limite de {0} modifiée pour l''île {1}.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lAméliorations | &7Mise à jour du niveau de l''effet d''île {0} pour l''île de {1}.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lAméliorations | &7Mise à jour du niveau de l''effet d''île {0} pour toutes les îles.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lAméliorations | &7Mise à jour du niveau de l''effet d''île {0} pour l''île {1}.' CHANGED_ISLAND_SIZE: '&e&lAméliorations | &7Vous avez changé la taille de l''île de {0}.' CHANGED_ISLAND_SIZE_ALL: '&e&lAméliorations | &7Vous avez changé la taille de toutes les îles.' CHANGED_ISLAND_SIZE_NAME: '&e&lAméliorations | &7Vous avez changé la taille de l''île {0}.' CHANGED_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.' CHANGED_LANGUAGE: '&e&lLangage | &7Langue définie sur: Français.' CHANGED_MOB_DROPS: '&e&lAméliorations | &7Vous avez changé le multiplicateur de drops des mobs de l''île de {0}.' CHANGED_MOB_DROPS_ALL: '&e&lAméliorations | &7Vous avez changé le multiplicateur de drops des mobs de toutes les îles.' CHANGED_MOB_DROPS_NAME: '&e&lAméliorations | &7Vous avez changé le multiplacteur de drops des mobs de {0}.' CHANGED_NAME: '&e&lIle | &7Vous avez changé le nom de votre île pour {0}&7.' CHANGED_NAME_OTHER: '&e&lIle | &7Vous avez changé le nom de l''île de {0} pour {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lIle | &7Vous avez changé le nom de {0}&7 pour {1}&7.' CHANGED_PAYPAL: '&e&lIle | &7Vous avez changé le paypal de l''île pour {0}.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.' CHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}.' CHANGED_SPAWNER_RATES: '&e&lAméliorations | &7Vous avez changé le multiplicateur de taux des spawners de l''île de {0}.' CHANGED_SPAWNER_RATES_ALL: '&e&lAméliorations | &7Vous avez changé le multiplicateur de taux des spawners de toutes les îles.' CHANGED_SPAWNER_RATES_NAME: '&e&lAméliorations | &7Vous avez changé le multiplicateur de taux des spawners de {0}.' CHANGED_TEAM_LIMIT: '&e&lAméliorations | &7Vous avez changé la limité de membres d''île pour l''île de {0}.' CHANGED_TEAM_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de membres d''île pour toutes les îles.' CHANGED_TEAM_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de membres d''île de {0}.' CHANGED_TELEPORT_LOCATION: '&e&lIle | &7Vous avez changé la position de téléportation de votre île.' CHANGED_WARPS_LIMIT: '&e&lAméliorations | &7Vous avez changé la limite de warps de l''île de {0}.' CHANGED_WARPS_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de warps de toutes les îles.' CHANGED_WARPS_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de warps d''île de {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: quantité COMMAND_ARGUMENT_BIOME: biome COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'commande...' COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: discord COMMAND_ARGUMENT_EFFECT: effet-de-potion COMMAND_ARGUMENT_EMAIL: email COMMAND_ARGUMENT_ENTITY: entité COMMAND_ARGUMENT_TIME: temps COMMAND_ARGUMENT_TITLE_DURATION: 'durée' COMMAND_ARGUMENT_TITLE_FADE_IN: 'apparition-graduelle' COMMAND_ARGUMENT_TITLE_FADE_OUT: 'disparition-graduelle' COMMAND_ARGUMENT_ISLAND_NAME: nom-de-l'ile COMMAND_ARGUMENT_ISLAND_ROLE: rôle-sur-l'île COMMAND_ARGUMENT_LEADER: chef COMMAND_ARGUMENT_LEVEL: niveau COMMAND_ARGUMENT_LIMIT: limite COMMAND_ARGUMENT_MATERIAL: matériau COMMAND_ARGUMENT_MENU: nom-du-menu COMMAND_ARGUMENT_MESSAGE: message COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: nom-de-la-mission COMMAND_ARGUMENT_MODULE_NAME: 'nom-du-module' COMMAND_ARGUMENT_MULTIPLIER: multiplicateur COMMAND_ARGUMENT_NAME: nom COMMAND_ARGUMENT_NEW_LEADER: nouveau-chef COMMAND_ARGUMENT_PAGE: page COMMAND_ARGUMENT_PATH: 'path' COMMAND_ARGUMENT_PERMISSION: permission COMMAND_ARGUMENT_PLAYER_NAME: nom-du-joueur COMMAND_ARGUMENT_PRIVATE: privé COMMAND_ARGUMENT_RATING: note COMMAND_ARGUMENT_ROWS: lignes COMMAND_ARGUMENT_SCHEMATIC_NAME: nom-du-schémas COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: paramètres COMMAND_ARGUMENT_SIZE: taille COMMAND_ARGUMENT_UPGRADE_NAME: nom-de-l'amélioration COMMAND_ARGUMENT_VALUE: valeur COMMAND_ARGUMENT_WARP_NAME: nom-du-warp COMMAND_ARGUMENT_WARP_CATEGORY: 'catégorie-de-warp' COMMAND_ARGUMENT_WORLD: monde COMMAND_COOLDOWN_FORMAT: '&c&lErreur | &7Vous devez patienter {0} avant de réutiliser cette commande.' COMMAND_DESCRIPTION_ADMIN_DEBUG: Activer ou désactiver les informations de débogage. COMMAND_DESCRIPTION_ADMIN_DEL_WARP: Delete a warp for an island. COMMAND_DESCRIPTION_ACCEPT: Accepter l'invitation d'un joueur. COMMAND_DESCRIPTION_ADMIN: Utiliser les commandes admin. COMMAND_DESCRIPTION_ADMIN_ADD: Ajouter un joueur comme membre d'une île. COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Augmenter la limite de blocs pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Attribuer un bonus au joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Augmenter la limite de coopérateurs pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Augmenter le multiplicateur de croissance des cultures pour le joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Ajouter un effet d'île à l'île du spécifiée. COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Augmenter la limite d'entités pour l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Ajouter un poucentage de chance pour un block au générateur de cobblestone. COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Augmenter le multiplicateur de butin des monstres pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Aggrandir l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Augmenter le multiplicateur de taux des spawners pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Augmenter la limite de membres pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Augmenter la limite de warps pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_TELEPORT: Se téléporter sur l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_TITLE: 'Envoyer un titre au joueur.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Envoyer un titre à tous les membres de l''île.' COMMAND_DESCRIPTION_ADMIN_PURGE: Purger les îles. COMMAND_DESCRIPTION_ADMIN_RANKUP: Augmenter une amélioration pour l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_BONUS: Octroyer un bonus à un joueur. COMMAND_DESCRIPTION_ADMIN_BYPASS: Activer/Désactiver le mode bypass. COMMAND_DESCRIPTION_ADMIN_CHEST: Ouvrir le stockage de l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Réinitialiser le taux des générateurs pour l'île spécifié. COMMAND_DESCRIPTION_ADMIN_CLOSE: Fermer une île au public. COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Executer une commande pour tous les membres d''une île.' COMMAND_DESCRIPTION_ADMIN_COUNT: Vérifier le nombre de blocs sur lîle spécifiée. COMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: Dégrader un membre de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Déposer de l'argent sur le compte de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_DISBAND: Supprimer l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Donner des suppressions d'île à un joueur. COMMAND_DESCRIPTION_ADMIN_IGNORE: Masquer une île du top des îles. COMMAND_DESCRIPTION_ADMIN_JOIN: Rejoindre une île sans invitation. COMMAND_DESCRIPTION_ADMIN_KICK: Éjecter un joueur de son île. COMMAND_DESCRIPTION_ADMIN_MODULES: 'Gérer les modules du plugin.' COMMAND_DESCRIPTION_ADMIN_MISSION: Changer le statut d'une mission pour un joueur. COMMAND_DESCRIPTION_ADMIN_MSG: Envoyer un message sans aucun préfixe au joueur. COMMAND_DESCRIPTION_ADMIN_MSG_ALL: Envoyer un message sans aucun préfixe à tous les membres de lîle. COMMAND_DESCRIPTION_ADMIN_NAME: Changer le nom d'une île. COMMAND_DESCRIPTION_ADMIN_OPEN: Ouvrir une île au public. COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Ouvrir un menu personnalisé au joueur spécifié. COMMAND_DESCRIPTION_ADMIN_PROMOTE: Promouvoir un membre d'une île. COMMAND_DESCRIPTION_ADMIN_RECALC: Re-calculer la valeur d'une île. COMMAND_DESCRIPTION_ADMIN_RELOAD: Recharger toutes les configurations du plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Retirer la limite de bloc d'une île. COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Suppimer toutes les notes attribuées par un joueur. COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Réinitialiser l'île d'un monde précis pour l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Créer des schematics pour le plugin. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Définir le biome de l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Définir la quantité de blocs sur une position spécifique. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Définir une limite de blocs pour l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Définir les lignes du stockage communautaire de l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Définir la limite de coopérateurs pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Définir le multiplicateur de croissance des cultures de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Définir le nombre de suppression d'îles d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Définir le niveau d'un effet d'île sur l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Définir la limite d'entités pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Transférer une île à quelqu'un d'autre. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Définir le multiplicateur de drops de mobs de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Définir un rôle nécéssaire à une permission pour toutes les îles. COMMAND_DESCRIPTION_ADMIN_SET_RATE: Définir une note à la place d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Set role limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Activer/Désactiver les paramètres pour une île spécifique. COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Changer le poucentage d'un matériau pour le générateur de cobble. COMMAND_DESCRIPTION_ADMIN_SET_SIZE: Changer la taille de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Définir l'emplacement de spawn du serveur. COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Définir le multiplicateur de taux des spawners pour l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Définir une limite de membres pour l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Définir le niveau d'une amélioration de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Définir la limite de warps d'une île. COMMAND_DESCRIPTION_ADMIN_SETTINGS: Ouvrir l'éditeur des options du plugin. COMMAND_DESCRIPTION_ADMIN_SHOW: Obtenir des informations sur une île. COMMAND_DESCRIPTION_ADMIN_SPAWN: Se téléporter à l'emplacement de spawn. COMMAND_DESCRIPTION_ADMIN_SPY: Activer/Désactiver le mode espion du chat COMMAND_DESCRIPTION_ADMIN_STATS: Afficher les statistiques du plugin. COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Synchroniser les valeurs des améliorations d'une île. COMMAND_DESCRIPTION_ADMIN_UNIGNORE: Réafficher une île dans le top des îles. COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Dévérouiller un mode pour une île. COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Retirer de l'argent de la banque d'île d'un joueur. COMMAND_DESCRIPTION_BALANCE: Vérifier la quantité d'argent dans le coffre de l'île spécifiée. COMMAND_DESCRIPTION_BAN: Bannir un joueur de votre île. COMMAND_DESCRIPTION_BANK: Ouvrir la banque de l'île. COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Changer le biome de l'île. COMMAND_DESCRIPTION_BORDER: Changer la couleur de la bordure de l'île. COMMAND_DESCRIPTION_CHEST: Ouvrir le stockage communautaire de l'île. COMMAND_DESCRIPTION_CLOSE: Fermer l'île au public. COMMAND_DESCRIPTION_COOP: Ajouter un joueur en tant que coopérateur de votre île. COMMAND_DESCRIPTION_COOPS: Ouvrir le menu des coopérateurs. COMMAND_DESCRIPTION_COUNTS: Afficher le compteur de blocs de votre île. COMMAND_DESCRIPTION_CREATE: Créer une nouvelle île. COMMAND_DESCRIPTION_DEL_WARP: Supprimer un warp de son île. COMMAND_DESCRIPTION_DEMOTE: Rétrograder un membre de votre île. COMMAND_DESCRIPTION_DEPOSIT: Déposer de l'argent de votre compte personnel sur le compte de l'île. COMMAND_DESCRIPTION_DISBAND: Supprimer votre île. COMMAND_DESCRIPTION_EXPEL: Éjecter un visiteur de votre île. COMMAND_DESCRIPTION_FLY: Activer/Désactiver le mode vol de l'île. COMMAND_DESCRIPTION_HELP: Liste de toutes les commandes. COMMAND_DESCRIPTION_INVITE: Inviter un joueur sur votre île. COMMAND_DESCRIPTION_KICK: Éjecter un membre de votre île. COMMAND_DESCRIPTION_LANG: Changer votre langue personnelle. COMMAND_DESCRIPTION_LEAVE: Quitter votre île. COMMAND_DESCRIPTION_MEMBERS: Ouvrir le menu des membres. COMMAND_DESCRIPTION_MISSION: Completer une mission. COMMAND_DESCRIPTION_MISSIONS: Ouvrir le menu des missions. COMMAND_DESCRIPTION_NAME: Changer le nom de votre île. COMMAND_DESCRIPTION_OPEN: Ouvrir votre île au public. COMMAND_DESCRIPTION_PANEL: Ouvrir le menu d'île. COMMAND_DESCRIPTION_PARDON: Débannir un joueur de votre île. COMMAND_DESCRIPTION_PERMISSIONS: Obtenir toutes les permissions d'un rôle d'île. COMMAND_DESCRIPTION_PROMOTE: Promouvoir un membre de votre île. COMMAND_DESCRIPTION_RANKUP: Augmenter une amélioration. COMMAND_DESCRIPTION_RATE: Noter une île. COMMAND_DESCRIPTION_RATINGS: Afficher toutes les notes d'une île. COMMAND_DESCRIPTION_SETTINGS: Ouvrir le menu des paramètres. COMMAND_DESCRIPTION_RECALC: Re-calculer la valeur d'une île. COMMAND_DESCRIPTION_SET_DISCORD: Définir le discord d'une île. COMMAND_DESCRIPTION_SET_PAYPAL: Définir le paypal d'une île. COMMAND_DESCRIPTION_SET_ROLE: Changer le rôle d'un membre de votre île. COMMAND_DESCRIPTION_SET_TELEPORT: Changer la position de téléportation de votre île. COMMAND_DESCRIPTION_SET_WARP: Créer un nouveau warp d'île. COMMAND_DESCRIPTION_SHOW: Obtenir des informations à propos d'une île. COMMAND_DESCRIPTION_TEAM: Obtenir des informations sur le status des membres de l'île. COMMAND_DESCRIPTION_TEAM_CHAT: Activer/Désactiver le mode de chat d'île. COMMAND_DESCRIPTION_TELEPORT: Se téléporter sur votre île. COMMAND_DESCRIPTION_TOGGLE: Activer/Désactiver les bordures d'île et les stack de blocs. COMMAND_DESCRIPTION_TOP: Ouvrir l'interface de top des îles. COMMAND_DESCRIPTION_TRANSFER: Transferer la direction de votre île. COMMAND_DESCRIPTION_UNCOOP: Supprimer un joueur coopérateur de votre île. COMMAND_DESCRIPTION_UPGRADE: Ouvrir le menu des améliorations. COMMAND_DESCRIPTION_VALUE: Obtenir la valeur d'une bloc. COMMAND_DESCRIPTION_VALUES: Ouvrir le menu des valeurs. COMMAND_DESCRIPTION_VISIT: Se téléporter sur la zone visiteurs d'une île. COMMAND_DESCRIPTION_VISITORS: Ouvrir le menu des visiteurs. COMMAND_DESCRIPTION_WARP: Se téléporter au warp d'une île. COMMAND_DESCRIPTION_WARPS: Ouvrir le menu des Warps. COMMAND_DESCRIPTION_WITHDRAW: Transférer de l'argent du compte de votre île à votre compte personnel. COMMAND_USAGE: '&cUtilisation: /{0}' COOP_ANNOUNCEMENT: '&e&lIle | &7{0} a ajouté {1} en tant que coopérateur.' COOP_BANNED_PLAYER: '&c&lErreur | &7Ce joueur est banni de l''île et ne peut pas être coopérateur.' COOP_LIMIT_EXCEED: '&c&lErreur | &7Vous avez atteint le nombre maximal de coopérateurs d''île.' CREATE_ISLAND: '&e&lIle | &7Création d''une nouvelle île aux coordonnées {0} en {1}ms.' CREATE_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.' CREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.' DEBUG_MODE_DISABLED: '&e&lDebug | &7Débogage &cDÉSACTIVÉ&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7Débogage &aACTIVÉ&7.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.' DELETE_WARP: '&e&lIle | &7Vous avez supprimé le warp {0}.' DELETE_WARP_SIGN_BROKE: '&7&oIl y avait une pancarte pour ce warp, mais elle a été détruite...' DEMOTE_LEADER: '&c&lErreur | &7Vous ne pouvez pas rétrograder le propriétaire de l''île.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErreur | &7Vous pouvez uniquement rétrograder des joueurs ayant un rôle d''île inférieur au votre.' DEMOTED_MEMBER: '&e&lIle | &7Vous avez rétrogradé {0} au rôle de {1} sur son île.' DEPOSIT_ANNOUNCEMENT: '&e&lBanque | &7{0} a déposé {1}$ sur le compte de l''île !' DEPOSIT_ERROR: '&c&lErreur | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lErreur | &7Vous ne pouvez rien casser en dehors de votre île.' DISBAND_ANNOUNCEMENT: '&e&lIle | &7Votre île a été supprimée par {0}.' DISBAND_GIVE: '&e&lIle | &7Vous avez reçu {0} suppressions d''île.' DISBAND_GIVE_ALL: '&e&lIle | &7Vous avez donné {0} suppressions d''île à tous les joueurs.' DISBAND_GIVE_OTHER: '&e&lIle | &7Vous avez donné {0} supressions d''île à {1}.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oYour island was disbanded and ${0} dollars were refunded to your account from the island bank' DISBAND_SET: '&e&lIle | &7Votre nombre de suppressions d''île a été défini sur {0}.' DISBAND_SET_ALL: '&e&lIle | &7Vous avez défini le nombre de suppressions d''île de tous les joueurs sur {0}.' DISBAND_SET_OTHER: '&e&lIle | &7Vous avez défini le nombre de suppressions d''île de {0} sur {1}.' DISBANDED_ISLAND: '&e&lIle | &7Vous avez supprimé votre île.' DISBANDED_ISLAND_OTHER: '&e&lIle | &7Vous avez supprimé l''île de {0}.' DISBANDED_ISLAND_OTHER_NAME: '&e&lIle | &7Vous avez supprimé l''île {0}.' ENTER_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...' EXPELLED_PLAYER: '&e&lIle | &7{0} a été exclu de l''île.' FORMAT_QUAD: Q FORMAT_TRILLION: T FORMAT_BILLION: B FORMAT_MILLION: M FORMAT_THOUSANDS: K FORMAT_SECONDS_NAME: secondes FORMAT_SECOND_NAME: seconde FORMAT_MINUTES_NAME: minutes FORMAT_MINUTE_NAME: minute FORMAT_HOURS_NAME: heures FORMAT_HOUR_NAME: heure FORMAT_DAYS_NAME: jours FORMAT_DAY_NAME: jour GENERATOR_CLEARED: '&e&lIle | &7Nettoyage des taux des générateurs pour l''île de {0}.' GENERATOR_CLEARED_NAME: '&e&lIle | &7Nettoyage des taux des générateurs pour l''île {0}.' GENERATOR_CLEARED_ALL: '&e&lIle | &7Nettoyage des taux des générateurs de toutes les îles.' GENERATOR_UPDATED: '&e&lIle | &7Taux du générateur modifié sur {0} pour l''île de {1}.' GENERATOR_UPDATED_NAME: '&e&lIle | &7Taux du générateur modifié sur {0} pour l''île de {1}.' GLOBAL_COMMAND_EXECUTED: '&e&lIle | &7Éxécution de la commande sur les membres de l''île de {0} !' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lIle | &7Éxécution de la commande sur les membres de : {0} !' GENERATOR_UPDATED_ALL: '&e&lIle | &7Taux du générateur modifié sur {0} pour toutes les îles.' GLOBAL_MESSAGE_SENT: '&e&lIle | &7Message envoyé à tous les membres de l''île de {0} !' GLOBAL_MESSAGE_SENT_NAME: '&e&lIle | &7Message envoyé à tous les membres de l''île {0} !' GLOBAL_TITLE_SENT: '&e&lIle | &7Envoi du titre aux membres de l''île de {0} !' GLOBAL_TITLE_SENT_NAME: '&e&lIle | &7Envoi du titre à tous les membres de l''île {0} !' GOT_BANNED: '&e&lIle | &7Vous avez été BANNI de l''île de {0}.' GOT_DEMOTED: '&e&lIle | &7Vous avez été rétrogradé au rôle de {0} sur votre île.' GOT_EXPELLED: '&e&lIle | &7&oVous avez été exclu de l''île par {0}.' GOT_INVITE: '&e&lIle | &7{0} vous a invité sur son île.' GOT_INVITE_TOOLTIP: '&7Cliquez sur ce message afin d''accepter l''invitation.' GOT_KICKED: '&e&lIle | &7Vous avez été éjecté de votre île par {0}.' GOT_PROMOTED: '&e&lIle | &7Vous avez été promu au rôle de {0} sur votre île.' GOT_REVOKED: '&e&lIle | &7{0} a révoqué votre invitation sur son île.' GOT_UNBANNED: '&e&lIle | &7Vous avez été DÉBANNI de l''île de {0}.' HIT_ISLAND_MEMBER: '&c&lErreur | &7Vous ne pouvez pas taper les membres de votre île.' HIT_PLAYER_IN_ISLAND: '&c&lErreur | &7Vous ne pouvez pas frapper les autres joueurs sur les îles.' IGNORED_ISLAND: '&e&lIle | &7L''île de {0} est désormais masquée du top des îles.' IGNORED_ISLAND_NAME: '&e&lIle | &7L''île {0} est désormais masquée du top des îles.' INTERACT_OUTSIDE_ISLAND: '&c&lErreur | &7Vous ne pouvez pas interagir en dehors de votre île.' INVALID_AMOUNT: '&c&lErreur | &7Nombre invalide {0}.' INVALID_BIOME: '&c&lErreur | &7Biome invalide {0}.' INVALID_BLOCK: '&c&lErreur | &7Emplacement {0} du bloc invalide.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lErreur | &7Effet invalide {0}.' INVALID_ENTITY: '&c&lErreur | &7Entité invalide {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_SCHEMATIC: '&c&lErreur | &7Il n''existe aucun schematic portant le nom {0}.' INVALID_INTERVAL: '&c&lErreur | &7Interval invalide {0}.' INVALID_ISLAND: '&c&lErreur | &7Vous n''avez pas d''île.' INVALID_ISLAND_LOCATION: '&c&lErreur | &7Il n''y a pas d''île sur votre position.' INVALID_ISLAND_OTHER: '&c&lErreur | &7{0} n''a pas d''île.' INVALID_ISLAND_OTHER_NAME: '&c&lErreur | &7Il n''y a pas d''île portant le nom {0}.' INVALID_ISLAND_PERMISSION: | &c&lErreur | &7La permission {0} nexiste pas. &c&lErreur | &7Permissions d'île: {1} INVALID_LEVEL: '&c&lErreur | &7Niveau invalide: {0}.' INVALID_LIMIT: '&c&lErreur | &7Limite invalide: {0}.' INVALID_MATERIAL: '&c&lErreur | &7Matériau invalide: {0}.' INVALID_MATERIAL_DATA: '&c&lErreur | &7Donnée de matériau {0} invalide.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErreur | &7Mission {0} invalide.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lErreur | &7Module {0} invalide.' INVALID_MULTIPLIER: '&c&lErreur | &7Multiplicateur invalide: {0}.' INVALID_PAGE: '&c&lErreur | &7Page {0} invalide.' INVALID_PERCENTAGE: '&c&lErreur | &7Le poucentage doit être compris entre 0 et 100.' INVALID_PLAYER: '&c&lErreur | &7Le joueur {0} n''existe pas.' INVALID_RATE: | &c&lErreur | &7Aucune note ne porte le nom: {0}. &c&lErreur | &7Notes de l'île: {1} INVALID_ROWS: '&c&lErreur | &7Nombre de lignes invalide: {0}' INVALID_ROLE: | &c&lErreur | &7Aucun rôle ne porte le nom: {0}. &c&lErreur | &7Rôles de l'île: {1} INVALID_SETTINGS: | &c&lErreur | &7Aucun paramètre ne porte le nom: {0}. &c&lErreur | &7Paramètres d'île: {1} INVALID_SIZE: '&c&lErreur | &7Taille invalide: {0}.' INVALID_SLOT: '&c&lErreur | &7Slot invalide {0}.' INVALID_TITLE: '&c&lErreur | &7Titre spécifié invalide.' INVALID_TOGGLE_MODE: '&c&lErreur | &7Impossible d''Activer/Désactiver: {0}.' INVALID_UPGRADE: | &c&lErreur | &7Aucune amélioration ne porte le nom {0}. &c&lErreur | &7Améliorations: {1} INVALID_VISIT_LOCATION: '&c&lErreur | &7Cette île ne possède aucune zone visiteurs.' INVALID_VISIT_LOCATION_BYPASS: '&7&oVous avez activé le mode bypass, téléportation sur l''île...' INVALID_WARP: '&c&lErreur | &7Warp invalide: {0}.' INVALID_WORLD: '&c&lErreur | &7Monde {0} invalide.' INVITE_ANNOUNCEMENT: '&e&lIle | &7{0} a invité {1} sur l''île.' INVITE_BANNED_PLAYER: '&c&lErreur | &7Ce joueur est banni de l''île et ne peut pas être invité.' INVITE_TO_FULL_ISLAND: '&c&lErreur | &7Vous ne pouvez pas inviter plus de membres sur l''île.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lErreur | &7Une île portant ce nom existe déjà.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBanque | &7La banque de l''île est vide.' ISLAND_BANK_SHOW: '&e&lBanque | &7Votre île possède {0} crystaux !' ISLAND_BANK_SHOW_OTHER: '&e&lBanque | &7L''île de {0} possède {1} crystaux !' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanque | &7L''île {0} possède {1} crystaux !' ISLAND_BEING_CALCULATED: '&c&lErreur | &7Vous ne pouvez pas interagir avec des blocs lorsque l''île est en train d''être recalculée !' ISLAND_CLOSED: '&e&lIle | &7L''île est désormais fermée au public.' ISLAND_CREATE_PROCESS_FAIL: '&c&lErreur | &7Votre île est déjà en cours de création.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIle | &7Requête en cours de traitement...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lVol | &7Le mode vol de l''île a été &cdésactivé &7automatiquement.' ISLAND_FLY_ENABLED: '&e&lVol | &7Le mode vol de l''île &aactivé &7automatiquement.' ISLAND_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...' ISLAND_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...' ISLAND_HELP_FOOTER: '&e&lSkyblock' ISLAND_HELP_HEADER: '&e&lSkyblock | &7Liste des Commandes [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSkyblock | &7Utilisez /is help {0} pour accéder à la page suivante.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIle | &7Limite Bancaire: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lIle | &7Limite de blocs: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIle | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIle | &7Limite de Coopérateurs: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lIle | &7Effets d'Île: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIle | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lIle | &7Limite d'Entitées: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIle | &7 {0}: {1}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIle | &7Multiplicateur de Cultures: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIle | &7Multiplicateur de Drops: {0}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lIle | &7Taux de Générateur: {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIle | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lIle | &7Limite de Roles: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIle | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lIle | &7Taille de la bordure: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIle | &7Multiplicateur de Spawners: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIle | &7Limite de membres: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lIle | &7Améliorations: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIle | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIle | &7Limite de Warps: {0}' ISLAND_INFO_BANK: '&e&lIle | &7Banque: {0}' ISLAND_INFO_BONUS: '&e&lIle | &7Bonus de Valeur: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lIle | &7Bonus de Niveau: {0}' ISLAND_INFO_DISCORD: '&e&lIle | &7Discord: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LOCATION: '&e&lIle | &7Accueil: {0}' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lIle | &7Dernière mise à jour: Il y à {0}' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIle | &7Dernière mise à jour: &aActuellement Active' ISLAND_INFO_LEVEL: '&e&lIle | &7Niveau: {0}' ISLAND_INFO_CREATION_TIME: '&e&lIle | &7Date de Création: {0}' ISLAND_INFO_NAME: '&e&lIle | &7Nom: {0}' ISLAND_INFO_OWNER: '&e&lIle | &7Chef: {0}' ISLAND_INFO_PAYPAL: '&e&lIle | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lIle | &7 - {0}' ISLAND_INFO_RATE: '&e&lIle | &7Note: &f&l{0} &7({1}/5) - {2} notes au total' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: ✦ ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIle | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIle | &7Nombre de visiteurs: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIle | &7Valeur: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIle | &7L''île est désormais ouverte au public.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPrévisualisation | &7Vous vous êtes trop éloigné(e). La prévisualisation à donc été désactivée.' ISLAND_PREVIEW_CANCEL: '&e&lPrévisualisation | &7Vous avez annulé(e) la prévisualisation.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMER' ISLAND_PREVIEW_CANCEL_TEXT: 'ANNULER' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lPrévisualisation | &7Vous avez débuté la prévisualisation de l'île {0}. &e&lPrévisualisation | &7Tapez &a&lCONFIRMER &7pour séléctionner cette île, ou &c&lANNULER &7pour annuler la prévisualisation. &e&lPrévisualisation | &7Si vous quittez la zone de l'île, la prévisualisation sera désactivée. ISLAND_PROTECTED: '&c&lErreur | &7Cette île est protégée.' ISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lIle | &7Membres de l''île de {0} &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Hors Ligne)' ISLAND_TEAM_STATUS_ONLINE: '&a(En Ligne)' ISLAND_TEAM_STATUS_ROLES: '&e&lIle | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Hors Ligne)' ISLAND_TOP_STATUS_ONLINE: '&a(En Ligne)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Privé]' ISLAND_WAS_CLOSED: '&e&lIle | &7&oL''île sur laquelle vous étiez a été fermée, vous avez donc été téléporté au spawn...' ISLAND_WORTH_ERROR: '&c&lErreur | &7Une erreur inattendue est survenue lors du calcul de votre île. Veuillez contacter un administrateur sur le problème persiste.' ISLAND_WORTH_RESULT: '&e&lIle | &7La valeur de votre île est {0} [Niveau {1}]' ISLAND_WORTH_TIME_OUT: '&c&lErreur | &7La tâche de calcul des îles a expiré. Veuillez réessayer ultérieurement...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lIle | &7{0} a rejoint votre île.' JOIN_ANNOUNCEMENT: '&e&lIle | &7{0} a rejoint votre île.' JOIN_FULL_ISLAND: '&c&lErreur | &7Cette île a déjà le nombre maximal de membres.' JOIN_WHILE_IN_ISLAND: '&c&lErreur | &7Vous êtes déjà membre d''une île.' JOINED_ISLAND: '&e&lIle | &7Vous avez rejoint l''île de {0}.' JOINED_ISLAND_NAME: '&e&lIle | &7Vous avez rejoint l''île {0}.' JOINED_ISLAND_AS_COOP: '&e&lIle | &7Vous êtes désormais un coopérateur de l''île de {0}.' JOINED_ISLAND_AS_COOP_NAME: '&e&lIle | &7Vous êtes désormais un coopérateur de l''île {0}.' KICK_ANNOUNCEMENT: '&e&lIle | &7{0} a été éjecté de l''île par {1}.' KICK_ISLAND_LEADER: '&c&lErreur | &7Vous ne pouvez pas éjecter le propriétaire d''une île, utilisez ''/isadmin disband'' à la place.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lErreur | &7Vous ne pouvez éjécter que les membres ayant un rôle d''île inférieur au votre.' LACK_CHANGE_PERMISSION: '&c&lErreur | &7Vous devez avoir cette permission afin de pouvoir la modifier pour les autres rôles.' LAST_ROLE_DEMOTE: '&c&lErreur | &7Vous ne pouvez plus rétrograder ce joueur.' LAST_ROLE_PROMOTE: '&c&lErreur | &7Vous ne pouvez plus promouvoir ce joueur.' LEAVE_ANNOUNCEMENT: '&e&lIle | &7{0} a quitté l''île.' LEAVE_ISLAND_AS_LEADER: |- &c&lErreur | &7Vous ne pouvez quitter une île vous appartenant. &c&lErreur | &7Vous pouvez transférer votre île à un joueur en tapant /is transfer. LEFT_ISLAND: '&e&lIle | &7Vous avez quitté votre île.' LEFT_ISLAND_COOP: '&e&lIle | &7Vous n''êtes plus un coopérateur de l''île de {0}.' LEFT_ISLAND_COOP_NAME: '&e&lIle | &7Vous n''êtes plus un coopérateur de l''île {0}.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lErreur | &7Vous devez fournir un matériau solide.' MAXIMUM_LEVEL: '&c&lErreur | &7Le niveau maximal pour cette amélioration est de {0}.' MESSAGE_SENT: '&e&lIle | &7Message envoyé a {0} !' MISSION_CANNOT_COMPLETE: '&c&lErreur | &7Vous ne pouvez compléter cette mission pour le moment.' MISSION_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 !' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lErreur | &7Vous devez compléter {0} avant de compléter cette mission.' MISSION_STATUS_COMPLETE: '&e&lMission | &7Le statut de la mission {0} a été complété sur {1}.' MISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Toutes les missions ont été completées pour {0}.' MISSION_STATUS_RESET: '&e&lMission | &7Le statut de la mission {0} a été réinitialisé sur {1}.' MISSION_STATUS_RESET_ALL: '&e&lMission | &7Réinitialisation du statut de toutes les missions pour {0}.' MODULE_ALREADY_INITIALIZED: '&e&lModule | &7Ce module est déjà chargé.' MODULE_INFO: | &e&lModule | &7{0} créé par {1} &e&lModule | &7&m-------------------- &e&lModule | &7{2} MODULE_LOADED_SUCCESS: '&e&lModule | &7Module {0} activé.' MODULE_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.' MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Module désactivé.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lIle | &7{0} a changé le nom de son île sur {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lErreur | &7Vous ne pouvez pas utiliser ce nom.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lErreur | &7Vous ne pouvez pas utiliser le pseudonyme d''un joueur comme nom d''île.' NAME_TOO_LONG: '&c&lErreur | &7Les noms d''îles ne peuvent pas contenir plus de {0} caractères.' NAME_TOO_SHORT: '&c&lErreur | &7Les noms d''îles ne peuvent pas contenir moins de {0} caractères.' NO_ISLANDS_TO_PURGE: '&c&lErreur | &7Il n''y a aucune îles à purger.' NO_BAN_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de bannir un joueur.' NO_CLOSE_BYPASS: '&c&lErreur | &7Cette île n''est pas ouverte au public.' NO_CLOSE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de fermer cette.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''ajouter des coopérateurs à l''île.' NO_DELETE_WARP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de supprimer des warps.' NO_DEMOTE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de rétrograder des joueurs.' NO_DEPOSIT_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de déposer de l''argent sur le compte de l''île.' NO_DISBAND_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de supprimervotre île.' NO_EXPEL_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''exclure des joueurs de l''île.' NO_INVITE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''inviter des joueurs sur l''île.' NO_ISLAND_CHEST_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''accéder au stockage de l''île.' NO_ISLAND_INVITE: '&c&lErreur | &7Vous n''avez aucune invitation provenant de cette île.' NO_KICK_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''éjécter des membres de l''île.' NO_MORE_DISBANDS: '&c&lErreur | &7Vous ne pouvez plus supprimer votre île.' NO_MORE_WARPS: '&c&lErreur | &7Votre île ne peut contenir plus de warps.' NO_NAME_PERMISSION: '&c&lErreur | &7Vous ne pouvez pas changer le nom de votre île.' NO_OPEN_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''ouvrir l''île au public.' NO_PERMISSION_CHECK_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''obtenir des informations sur les permissions.' NO_PROMOTE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de promouvoir des joueurs.' NO_RANKUP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''augmenter des améliorations.' NO_RATINGS_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de vérifier les notes.' NO_SET_BIOME_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de changer le biome de l''île.' NO_SET_DISCORD_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de changer le Discord de l''île.' NO_SET_HOME_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de définir me point de téléportation de l''île.' NO_SET_PAYPAL_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de changer le paypal de l''île.' NO_SET_ROLE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de définir les rôles de membres de l''île.' NO_SET_SETTINGS_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de modifier les paramètres de l''île.' NO_SET_WARP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de définir des warps d''île.' NO_TRANSFER_PERMISSION: '&c&lErreur | &7Vous devez être le chef de l''île afin de transférer l''île à un autre joueur.' NO_UNCOOP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de supprimer des coopérateurs de l''île.' NO_UPGRADE_PERMISSION: '&c&lErreur | &7Vous n''avez pas la permission d''augmenter l''amélioration à un autre niveau.' NO_WITHDRAW_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de retirer de l''argent du compte de l''île.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lErreur | &7Vous n''avez pas suffisamment d''argent pour déposer {0}$ sur le compte de vôtre île.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lErreur | &7Vous n''avez pas suffisamment d''argent.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lErreur | &7Vous n''avez pas suffisamment d''argent pour utiliser les warps d''île.' OPEN_MENU_WHILE_SLEEPING: '&7&oVous êtes trop fatigué pour interagir avec le menu vous ne pensez pas ?' PANEL_TOGGLE_OFF: |- &e&lPanel | &7Panel de gestion de l'île &cDÉSACTIVÉ&7. &e&lPanel | &7Tapez /is afin d'être téléporté sur votre île. PANEL_TOGGLE_ON: |- &e&lPanel | &7Panel de gestion de l'île &aACTIVÉ&7. &e&lPanel | &7Tapez /is afin d'ouvrir le panel de gestion. PERMISSION_CHANGED: '&e&lIle | &7Permission {0} de l''île de {1} mise à jour.' PERMISSION_CHANGED_NAME: '&e&lIle | &7Permission {0} de l''île {1} mise à jour.' PERMISSION_CHANGED_ALL: '&e&lIle | &7Permission {0} mise à jour pour toutes les îles.' PERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.' PERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIle | &7Réinitialisation de toutes les permissions de {0} !' PERMISSIONS_RESET_ROLES: '&e&lIle | &7Réinitialisation de toutes les permissions de l''île !' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Yes' PLAYER_ALREADY_BANNED: '&c&lErreur | &7Ce joueur est déjà banni.' PLAYER_ALREADY_COOP: '&c&lErreur | &7Ce joueur est déjà coopérateur.' PLAYER_ALREADY_IN_ISLAND: '&c&lErreur | &7Ce joueur est déjà membre d''une île.' PLAYER_ALREADY_IN_ROLE: '&c&lErreur | &7{0} est déjà {1}.' PLAYER_EXPEL_BYPASS: '&c&lErreur | &7Ce joueur ne peut pas être exclu de l''île.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lIle | &7{0} a rejoint le serveur.' PLAYER_NOT_BANNED: '&c&lErreur | &7Ce joueur n''est pas banni.' PLAYER_NOT_COOP: '&c&lErreur | &7Ce joueur n''est pas coopérateur.' PLAYER_NOT_INSIDE_ISLAND: '&c&lErreur | &7Ce joueur n''est pas sur votre île.' PLAYER_NOT_ONLINE: '&c&lErreur | &7Ce joueur n''est pas connecté !' PLAYER_QUIT_ANNOUNCEMENT: '&e&lIle | &7{0} a quitté le serveur.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErreur | &7Vous ne pouvez uniquement promouvoir les joueurs ayant un rôle inférieur au votre.' PROMOTED_MEMBER: '&e&lIle | &7Vous avez promu {0} {1} sur l''île.' PURGE_CLEAR: '&e&lIle | &7Toutes les îles en attente de purge ont été purgées.' PURGED_ISLANDS: |- &e&lIle | &7{0} île seront purgées au redémarrage du serveur. &e&lIle | &7Vous pouvez annuler ce processus à nimporte quel moment en tapant /is admin purge cancel. RANKUP_SUCCESS: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour l''île de {1}.' RANKUP_SUCCESS_ALL: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour toutes les îles.' RANKUP_SUCCESS_NAME: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour l''île {1}.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIle | &7{0} a noté votre île {1} / 5 !.' RATE_CHANGE_OTHER: '&e&lIle | &7Vous avez modifié la note de {0} sur {1}.' RATE_OWN_ISLAND: '&c&lErreur | &7Vous ne pouvez pas noter votre île.' RATE_REMOVE_ALL: '&e&lIle | &7Toutes les notes de {0} ont été supprimées.' RATE_REMOVE_ALL_ISLANDS: '&e&llIle | &7Suppression des notes de toutes les îles.' RATE_SUCCESS: '&e&lIle | &7Vous avez noté cette île {0} étoile(s) !' REACHED_BLOCK_LIMIT: '&e&lAméliorations | &7Vous avez atteint la limite de bloc d''île pour {0}.' REACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.' RECALC_ALREADY_RUNNING: '&c&lErreur | &7Votre île est déjà en cours de calcul.' RECALC_ALREADY_RUNNING_OTHER: '&c&lErreur | &7Cette île est déjà en cours de calcul.' RECALC_ALL_ISLANDS: '&e&lIle | &7Recalcul de toutes les îles...' RECALC_ALL_ISLANDS_DONE: '&e&lIle | &7Recalcul des îles effectué avec succès.' RECALC_PROCCESS_REQUEST: '&e&lIle | &7Début du recalcul des îles...' RELOAD_COMPLETED: '&e&lIle | &7Rechargement effectué !' RELOAD_PROCCESS_REQUEST: '&e&lIle | &7Début du rechargement des configurations...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lIle | &7{0} a révoqué l''inviation à rejoindre l''île de {1}.' RESET_WORLD_SUCCEED: '&e&lIle | &7Réinitialisation du monde {0} pour l''île de {1}.' RESET_WORLD_SUCCEED_ALL: '&e&lIle | &7Réinitialisation du monde {0} pour toutes les îles.' RESET_WORLD_SUCCEED_NAME: '&e&lIle | &7Réinitialisation du monde {0} pour l''île de {1}.' SAME_NAME_CHANGE: '&c&lErreur | &7Vous devez entrer un nom différent de celui actuel.' SCHEMATIC_LEFT_SELECT: '&e&lSchémas | &7Position #2 séléctionnée ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lErreur | &7Vous n''avez pas séléctionné deux positionss.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchémas | &7Traitement de votre requête...' SCHEMATIC_READY_TO_CREATE: | &e&lSchémas | &7Vous avez séléctionné deux positions. Tapez /is admin schematic afin de créer un schematic. &e&lSchémas | &7Assurez-vous de vous situer sur le point de téléportation lors de l'éxécution de la commande. SCHEMATIC_RIGHT_SELECT: '&e&lSchémas | &7Position #1 séléctionnée ({0})' SCHEMATIC_SAVED: '&e&lSchémas | &7Schematic sauvegardé !' SELF_ROLE_CHANGE: '&c&lErreur | &7Vous ne pouvez pas changer votre propre rôle.' SET_UPGRADE_LEVEL: '&e&lAméliorations | &7Niveau de {0} augmenté sur l''île de {1}.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lAméliorations | &7Niveau de {0} augmenté sur {1}.' SET_WARP: '&e&lIle | &7Nouveau warp crée au coordonnées {0}.' SET_WARP_OUTSIDE: '&c&lErreur | &7Vous ne pouvez pas définir de warps hors de votre île.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIle | &7Paramètre {0} mit à jour pour l''île de {1}.' SETTINGS_UPDATED_NAME: '&e&lIle | &7Paramètre {0} mit à jour pour l''île {1}.' SETTINGS_UPDATED_ALL: '&e&lIle | &7Paramètre {0} mit à jour pour toutes les îles.' SIZE_BIGGER_MAX: '&c&lErreur | &7Vous ne pouvez pas définir une taille d''île supérieure à la taille d''île maximale.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Téléporation de {0} au spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Mise à jour de la position du spawn sur {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Espion] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lAméliorations | &7Synchronisation des valeurs des améliorations de l''île de {0}.' SYNC_UPGRADES_ALL: '&e&lAméliorations | &7Synchronisation des valeurs des améliorations de toutes les îles.' SYNC_UPGRADES_NAME: '&e&lAméliorations | &7Synchronisation des valeurs des améliorations de l''île {0}.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lErreur | &7Vous n''êtes pas sûr votre île.' TELEPORT_OUTSIDE_ISLAND: '&c&lErreur | &7Vous ne pouvez pas vous téléporter en dehors de votre zone de protection.' TELEPORT_WARMUP: '&7&oVous serez téléporté dans {0}... Ne bougez pas !' TELEPORT_WARMUP_CANCEL: '&7&oVous vous êtes déplacé, la téléportation a donc été annulée.' TITLE_SENT: '&e&lIle | &7Envoie du titré {0} effectué !' TELEPORTED_FAILED: '&e&lIle | &7Il semblerait que cette île ne soit pas sécurisée. Veuillez contacter un Administrateur.' TELEPORTED_SUCCESS: '&e&lIle | &7Vous avez été téléporté sur votre île.' TELEPORTED_TO_WARP: '&e&lIle | &7Vous avez été télporté au warp de l''île.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIle | &7{0} s''est téléporté(e) au warp d''île {1}.' TOGGLED_BYPASS_OFF: '&e&lBypass | &7Mode bypass &cDÉSACTIVÉ&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Mode bypass &aACTIVÉ&7.' TOGGLED_FLY_OFF: '&e&lVol | &7Mode de fly d''île &cDÉSACTIVÉ&7.' TOGGLED_FLY_ON: '&e&lVol | &7Mode de fly d''île &aACTIVÉ&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchémas | &7Mode de création de schematics &cDÉSACTIVÉ&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchémas | &7Mode de création de schematics &aACTIVÉ&7. &e&lSchémas | &7Séléctionnez une zone en utilisant la hache en or. TOGGLED_SPY_OFF: '&e&lEspion | &7Mode espion du chat &cDÉSACTIVÉ&7.' TOGGLED_SPY_ON: '&e&lEspion | &7Mode espion du Chat &aACTIVÉ&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Stacker de blocs &cDÉSACTIVÉ&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Stacker de blocs &aACTIVÉ&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Chat de l''île &cDÉSACTIVÉ&7.' TOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Chat de l''île &aACTIVÉ&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lBordure | &7Bordure de l''île &cDÉSACTIÉE&7.' TOGGLED_WORLD_BORDER_ON: '&e&lBordure | &7Bordure de l''île &aACTIVÉE&7.' TRANSFER_ADMIN: '&e&lIle | &7Vous avez transféré le rôle de Chef de l''île de {0} à {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lErreur | &7{0} est déjà le Chef de cette île.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lErreur | &7Ces joueurs ne font pas parti de la même île.' TRANSFER_ADMIN_NOT_LEADER: '&c&lErreur | &7Ce joueur n''est chef d''aucune île.' TRANSFER_ALREADY_LEADER: '&c&lErreur | &7Vous êtes déjà le chef de l''île.' TRANSFER_BROADCAST: '&e&lIle | &7Le Chef de l''île est désormais {0}.' UNBAN_ANNOUNCEMENT: '&e&lIle | &7{0} a été DÉBANNI de l''île par {1}.' UNCOOP_ANNOUNCEMENT: '&e&lIle | &7{0} a retiré le rôle de coopérateur de {1}.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIle | &7{0} a quitté le jeu et n''est désormais plus un coopérateur.' UNIGNORED_ISLAND: '&e&lIle | &7L''île de {0} est désormais visible dans le top des îles.' UNIGNORED_ISLAND_NAME: '&e&lIle | &7L''île {0} n''est plus masquée dans le top des îles.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIle | &7&oIl semblerait que ce warp ne soit pas sécurisé. Veuillez en essayer un autre.' UPDATED_PERMISSION: '&e&lIle | &7Permission mise à jour pour {0}.' UPDATED_SETTINGS: '&e&lIle | &7Paramètre de l''île mit à jour {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lErreur | &7Vous devez patienter {0} afin d''effectuer une nouvelle amélioration.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lErreur | &7Vous ne pouvez pas utiliser cette commande sur d''autres îles.' WARP_ALREADY_EXIST: '&c&lErreur | &7Un warp portant ce nom éxiste déjà.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lWarps | &7Spécifiez un nouveau lore (Entrez "-cancel" to pour annuler) : &e&lWarps | &7Vous pouvez ajouter une nouvelle ligne en utilisant "\n". WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Spécifiez un nom (Entrez "-cancel" to pour annuler) :' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Spécifiez un nouveau matériau (Entrez "-cancel" to pour annuler) :' WARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Mise à jour de l''icone de la catégorie.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lErreur | &7Vous ne pouvez utiliser uniquement des lettres, nombres et ''_'' comme nom de catégorie de warp.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lErreur | &7Le nom d''une catégorie de warp ne peut dépasser 255 caractères.' WARP_CATEGORY_SLOT: '&e&lWarps | &7Spécifiez un nouvel emplacement (Entrez "-cancel" to pour annuler) :' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lErreur | &7Cet emplacement est déjà utilisé par une autre catégorie.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7L''emplacement de la catégorie est désormais {0}.' WARP_CATEGORY_RENAME: '&e&lWarps | &7Spécifiez un nom (Entrez "-cancel" to pour annuler) :' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lErreur | &7Ce nom est déjà utilisé par une autre catégorie.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Cette catégorie a été renommée en {0}.' WARP_ICON_NEW_LORE: | &e&lWarps | &7Spécifiez un nouveau lore (Entrez "-cancel" to pour annuler) : &e&lWarps | &7Vous pouvez ajouter une nouvelle ligne en utilisant "\n". WARP_ICON_NEW_NAME: '&e&lWarps | &7Spécifiez un nom (Entrez "-cancel" to pour annuler) :' WARP_ICON_NEW_TYPE: '&e&lWarps | &7Spécifiez un nouveau matériau (Entrez "-cancel" to pour annuler) :' WARP_ICON_UPDATED: '&e&lWarps | &7Mise à jour de l''icone du warp.' WARP_ILLEGAL_NAME: '&c&lErreur | &7Vous ne pouvez utiliser uniquement des lettres, nombres et ''_'' comme nom de warp.' WARP_LOCATION_UPDATE: '&e&lWarps | &7Mise à jour de la position de téléportation du warp sur votre emplacement actuel.' WARP_NAME_TOO_LONG: '&c&lErreur | &7Le nom d''un warp ne peut dépasser 255 caractères.' WARP_PUBLIC_UPDATE: '&e&lWarps | &7Le warp est désormais accessible au public.' WARP_PRIVATE_UPDATE: '&e&lWarps | &7Le warp n''est plus accessible au public.' WARP_RENAME: '&e&lWarps | &7Spécifiez un nouveau nom (Entrez "-cancel" to pour annuler) :' WARP_RENAME_ALREADY_EXIST: '&c&lErreur | &7Ce nom est déjà utilisé par un autre warp.' WARP_RENAME_SUCCESS: '&e&lWarps | &7Le warp a été renommé en {0}.' WITHDRAW_ALL_MONEY: |- &e&lBanque | &7Le compte de l'île ne contient que {0}$. &e&lBanque | &7&oRécupération de tout l'argent..." WITHDRAW_ANNOUNCEMENT: '&e&lBanque | &7{0} a retiré {1}$ du compte de l''île !' WITHDRAW_ERROR: '&c&lErreur | &7{0}.' WITHDRAWN_MONEY: '&e&lBanque | &7Vous avez retiré {0}$ du compte de l''île de {1} !' WITHDRAWN_MONEY_NAME: '&e&lBanque | &7Vous avez retiré {0}$ du compte de l''île {1} !' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lMondes | &7Le monde {0} n''a pas encore été dévérouillé !' ================================================ FILE: src/main/resources/lang/it-IT.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## Translated by xSavior_of_God ## ## ## ###################################################### # Se desideri creare un nuovo file di lingua, copia questo. # Assicurati di impostare come nome un nome di lingua corretto. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # Puoi trovare un tutorial sulla configurazione dei messaggi qui: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lIsola | &7Aggiunto correttamente il giocatore {0} all''isola di {1}.' ADMIN_ADD_PLAYER_NAME: '&e&lIsola | &7Aggiunto correttamente il giocatore {0} all''isola {1}.' ADMIN_DEPOSIT_MONEY: '&e&lBanca | &7Hai depositato ${0} nella banca dell''isola di {1}' ADMIN_DEPOSIT_MONEY_NAME: '&e&lBanca | &7Hai depositato &e${0}&f nella banca dell''isola &e{1}.' ADMIN_HELP_FOOTER: | &e&lSuperiorSkyblock &7Creato da Ome_R &e&lTradotto&7 in Italiano da xSavior_of_God ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Comandi di Amministrazione [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Usa /is admin {0} per vedere la prossima pagina.' ALREADY_IN_ISLAND: '&c&lErrore | &7Sei già dentro un''isola.' ALREADY_IN_ISLAND_OTHER: '&c&lErrore | &7Questo giocatore è già membro della tua isola.' BAN_ANNOUNCEMENT: '&e&lIsola | &7{0} è stato bannato dall''isola di {1}.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lErrore | &7Puoi bannare solo i giocatori aventi un ruolo inferiore al tuo.' BANK_DEPOSIT_CUSTOM: '&e&lBanca | &7Digita l''importo che desideri depositare:' BANK_DEPOSIT_COMPLETED: Deposito completato BANK_LIMIT_EXCEED: '&c&lErrore| &7Hai superato il limite della tua banca.' BANK_WITHDRAW_CUSTOM: '&e&lBanca | &7Digita l''importo che desideri prelevare:' BANK_WITHDRAW_COMPLETED: Ritiro completato BANNED_FROM_ISLAND: '&c&lErrore | &7Sei stato bannato da questa isola.' BLOCK_COUNT_CHECK: '&e&lIsola | &7Quest''isola ha x{0} {1}.' BLOCK_COUNTS_CHECK: | &e&lIsola | &7Quest'isola ha i seguenti blocchi: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lIsola | &7Quest''isola non ha blocchi tracciati.' BLOCK_COUNTS_CHECK_MATERIAL: x{0} {1} BLOCK_LEVEL: '&e&lLivello | &7Il blocco {0} vale {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lLivello | &7Il blocco {0} non ha valore.' BLOCK_VALUE: '&e&lWorth | &7Il blocco {0} vale {1}.' BLOCK_VALUE_WORTHLESS: '&e&lWorth | &7Il blocco {0} non ha valore.' BONUS_SYNC_ALL: '&e&lIsola | &7SAggiornato con successo il bonus a tutte le isole.' BONUS_SYNC_NAME: '&e&lIsola | &7Aggiornato con successo il bonus per l''isola di {0}.' BONUS_SYNC: '&e&lIsola | &7Aggiornato con successo il bonus per l''isola di {0}.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Blu' BORDER_PLAYER_COLOR_NAME_RED: 'Rosso' BORDER_PLAYER_COLOR_NAME_GREEN: 'Verde' BORDER_PLAYER_COLOR_UPDATED: '&e&lBordo | &7Modificato con successo il colore del bordo personale in {0}.' BUILD_OUTSIDE_ISLAND: '&c&lErrore | &7Non puoi costruire al di fuori del tuo raggio di protezione.' CANNOT_SET_ROLE: '&c&lErrore | &7Non puoi impostare il ruolo del giocatore su {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lErrore | &7Puoi modificare le autorizzazioni solo per i ruoli dell''isola inferiori rispetto al tuo.' CHANGED_BANK_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite bancario dell''isola di {0}.' CHANGED_BANK_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornato con successo il limite bancario di tutte le isole.' CHANGED_BANK_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il limite bancario di {0}.' CHANGED_BIOME: '&e&lIsola | &7Bioma modificato con successo in {0}. Potrebbe essere necessario riconnettersi al server per vedere le modifiche.' CHANGED_BIOME_ALL: '&e&lIsola | &7Aggiornato con successo il bioma su {0} per tutte le isole.' CHANGED_BIOME_NAME: '&e&Isola | &7Aggiornato con successo il bioma su {0} per l''isola {1}.' CHANGED_BIOME_OTHER: '&e&lIsola | &7Aggiornato con successo il bioma su {0} per l''isola di {1}.' CHANGED_BLOCK_AMOUNT: '&e&lBlocchi | &7Aggiornato con successo il numero di blocchi di {0} a {1}.' CHANGED_BLOCK_LIMIT: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} dell''isola {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} in tutte le isole.' CHANGED_BLOCK_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} nell''isola di {1}.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per l''isola di {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per tutte le isole.' CHANGED_CHEST_SIZE_NAME: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per {2}.' CHANGED_COOP_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite di giocatori coop per l''isola di {0}.' CHANGED_COOP_LIMIT_ALL: '&e&lAggiornamenti | &7SAggiornato con successo il limite di giocatori coop per tutte le isole.' CHANGED_COOP_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il limite di giocatori coop di {0}.' CHANGED_CROP_GROWTH: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore della crescita delle colture dell'' isola di {0}.' CHANGED_CROP_GROWTH_ALL: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore della crescita delle colture di tutte le isole.' CHANGED_CROP_GROWTH_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore della crescita delle colture dell''isola di {0}.' CHANGED_DISCORD: '&e&lIsola | &7Discord dell''isola cambiata con successo in {0}.' CHANGED_ENTITY_LIMIT: '&e&lMiglioramenti | &7Aggiornato con successo il limite delle entità di {0} per l''isola di {1}.' CHANGED_ENTITY_LIMIT_ALL: '&e&lMiglioramenti | &7Aggiornato con successo il limite delle entità di {0} per tutte le isola.' CHANGED_ENTITY_LIMIT_NAME: '&e&lMiglioramenti | &7Aggiornato con successo il limite delle entità di {0} per l''isola {1}.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lAggiornamenti | &7Aggiornato con successo il livello dell''effetto {0} per l''isola di {1}.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lAggiornamenti | &7Aggiornato con successo il livello dell''effetto {0} per tutte le isole.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il livello dell''effetto {0} per l''isola {1}.' CHANGED_ISLAND_SIZE: '&e&lAggiornamenti | &7Aggiornata correttamente la dimensione dell''isola di {0}.' CHANGED_ISLAND_SIZE_ALL: '&e&lAggiornamenti | &7Aggiornata con successo la dimensione di tutte le isole.' CHANGED_ISLAND_SIZE_NAME: '&e&lAggiornamenti | &7Aggiornato con successo la dimensione dell''isola di {0}.' CHANGED_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.' CHANGED_LANGUAGE: '&e&lLanguage | &7Lingua cambiata in Italiano.' CHANGED_MOB_DROPS: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob nell''isola di {0}.' CHANGED_MOB_DROPS_ALL: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob in tutte le isole.' CHANGED_MOB_DROPS_NAME: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob di {0}.' CHANGED_NAME: '&e&lIsola | &7Hai cambiato il nome della tua isola in {0}&7.' CHANGED_NAME_OTHER: '&e&lIsola | &7Hai cambiato il nome della tua isola da {0} a {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lIsola | &7Hai cambiato il nome dell''isola di {0}&7 a {1}&7.' CHANGED_PAYPAL: '&e&lIsola | &7Paypal dell''isola cambiato con successo in {0}.' CHANGED_ROLE_LIMIT: '&e&lAggiornamenti | &7Aggiornata con successo il limite per il ruolo {0} per l''isola di {1}.' CHANGED_ROLE_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornata con successo il limite per il ruolo {0} di tutte le isole.' CHANGED_ROLE_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornata con successo il limite per il ruolo {0} per l''isola {1}.' CHANGED_SPAWNER_RATES: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore degli spawner dell''isola di {0}.' CHANGED_SPAWNER_RATES_ALL: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore degli spawner in tutte le isole.' CHANGED_SPAWNER_RATES_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il moltiplicatore degli spawner rates dell''isola {0}.' CHANGED_TEAM_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite dei membri dell''isola di {0}.' CHANGED_TEAM_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornato con successo il limite dei membri di tutte le isole.' CHANGED_TEAM_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il limite di membri dell''isola {0}.' CHANGED_TELEPORT_LOCATION: '&e&lIsola | &7Aggiornato con successo lo spawn dell''isola.' CHANGED_WARPS_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite di warps dell''isola di {0}.' CHANGED_WARPS_LIMIT_ALL: '&e&lAggiornamenti | &7Aggioranto con successo il limite di warps di tutte le isole.' CHANGED_WARPS_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il mite di warps dell''isola {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: quantità COMMAND_ARGUMENT_BIOME: bioma COMMAND_ARGUMENT_BORDER_COLOR: 'colore-bordo' COMMAND_ARGUMENT_COMMAND: 'comando...' COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: discord... COMMAND_ARGUMENT_EFFECT: effetto-pozione COMMAND_ARGUMENT_EMAIL: email COMMAND_ARGUMENT_ENTITY: entità COMMAND_ARGUMENT_ISLAND_NAME: nome-isola COMMAND_ARGUMENT_ISLAND_ROLE: ruolo-isola COMMAND_ARGUMENT_LEADER: capo COMMAND_ARGUMENT_LEVEL: livello COMMAND_ARGUMENT_LIMIT: limite COMMAND_ARGUMENT_MATERIAL: materiale COMMAND_ARGUMENT_MENU: nome-menu COMMAND_ARGUMENT_MESSAGE: messagio... COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: nome-missione COMMAND_ARGUMENT_MODULE_NAME: 'nome-modulo' COMMAND_ARGUMENT_MULTIPLIER: moltiplicatore COMMAND_ARGUMENT_NAME: nome COMMAND_ARGUMENT_NEW_LEADER: nuovo-capo COMMAND_ARGUMENT_PAGE: pagina COMMAND_ARGUMENT_PATH: 'percorso' COMMAND_ARGUMENT_PERMISSION: permesso COMMAND_ARGUMENT_PLAYER_NAME: nome-giocatore COMMAND_ARGUMENT_PRIVATE: privato COMMAND_ARGUMENT_RATING: valutazione COMMAND_ARGUMENT_ROWS: righe COMMAND_ARGUMENT_SCHEMATIC_NAME: nome-schematica COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: impostazioni COMMAND_ARGUMENT_SIZE: dimensione COMMAND_ARGUMENT_TIME: tempo COMMAND_ARGUMENT_TITLE_DURATION: durata COMMAND_ARGUMENT_TITLE_FADE_IN: dissolvenza-in-apertura COMMAND_ARGUMENT_TITLE_FADE_OUT: dissolvenza COMMAND_ARGUMENT_UPGRADE_NAME: nome-aggiornamento COMMAND_ARGUMENT_VALUE: valore COMMAND_ARGUMENT_WARP_NAME: nome-warp COMMAND_ARGUMENT_WARP_CATEGORY: 'categoria-warp' COMMAND_ARGUMENT_WORLD: mondo COMMAND_COOLDOWN_FORMAT: '&c&lErrore | &7È possibile utilizzare questo comando tra {0}.' COMMAND_DESCRIPTION_ACCEPT: Accetta un invito da un giocatore. COMMAND_DESCRIPTION_ADMIN: Utilizzare i comandi di amministrazione. COMMAND_DESCRIPTION_ADMIN_ADD: Aggiungi un utente a un'isola. COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Aumenta il limite di blocchi per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Aggiungi un bonus a un giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Aumenta il limite dei giocatori coop per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Aumenta il moltiplicatore di crescita del raccolto per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Aggiungi un effetto isola per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Aumenta il limite di entità per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Aggiungi la percentuale di un materiale per il generatore di ciottoli. COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Aumenta il moltiplicatore dei mob drops per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Espandi la dimensione dell'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Aumenta il moltiplicatore dei tassi di generazione per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Aumenta il limite di membri per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Aumenta il limite di warps di un'isola. COMMAND_DESCRIPTION_ADMIN_BONUS: Concedi un bonus a un giocatore. COMMAND_DESCRIPTION_ADMIN_BYPASS: Attiva/disattiva la modalità bypass. COMMAND_DESCRIPTION_ADMIN_CHEST: Apri il baule di un'altra isola. COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Cancella i tassi del generatore per un'isola specifica. COMMAND_DESCRIPTION_ADMIN_CLOSE: Chiudi un'isola al pubblico. COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Esegui un comando per tutti i membri delle isole.' COMMAND_DESCRIPTION_ADMIN_COUNT: Controlla un conteggio dei blocchi su un'isola specifica. COMMAND_DESCRIPTION_ADMIN_DATA: 'Interagisci con i dati persistenti di giocatori o isole.' COMMAND_DESCRIPTION_ADMIN_DEBUG: Attiva o disattiva i messaggi di Debug. COMMAND_DESCRIPTION_ADMIN_DEL_WARP: Elimina un warp per un'isola. COMMAND_DESCRIPTION_ADMIN_DEMOTE: Diminuisci il ruolo di un membro dell'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Depositare denaro nella banca dell'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_DISBAND: Sciogli definitivamente l'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Aumenta la quantità di reset disponibili di un giocatore. COMMAND_DESCRIPTION_ADMIN_IGNORE: Rimuovi un giocatore dal menu delle migliori isole. COMMAND_DESCRIPTION_ADMIN_JOIN: Unisciti a un'isola senza un invito. COMMAND_DESCRIPTION_ADMIN_KICK: Caccia un giocatore dalla usa isola. COMMAND_DESCRIPTION_ADMIN_MODULES: 'Gestisci i moduli del plugin.' COMMAND_DESCRIPTION_ADMIN_MISSION: Cambia lo stato di una missione per un giocatore. COMMAND_DESCRIPTION_ADMIN_MSG: Invia a un giocatore un messaggio senza prefissi. COMMAND_DESCRIPTION_ADMIN_MSG_ALL: Invia a tutti i membri dell'isola un messaggio senza prefissi. COMMAND_DESCRIPTION_ADMIN_NAME: Cambia il nome di un'isola. COMMAND_DESCRIPTION_ADMIN_OPEN: Apri un'isola al pubblico. COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Apri un menu personalizzato per un giocatore. COMMAND_DESCRIPTION_ADMIN_PROMOTE: Promuovi un membro nell'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_PURGE: Elimina le isole. COMMAND_DESCRIPTION_ADMIN_RANKUP: Potenzia un aggiornamento per un isola. COMMAND_DESCRIPTION_ADMIN_RECALC: Ricalcola il valore di un'isola. COMMAND_DESCRIPTION_ADMIN_RELOAD: Ricarica tutte le configurazioni e le attività del plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Rimuovi il limite di un blocco da un'isola. COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Rimuovi tutte le valutazioni fornite da un giocatore. COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Ripristina il mondo su un''isole.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Crea una schematica per il plugin. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Imposta il bioma di un'isola. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Imposta la quantità di un blocco in una posizione specifica. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Imposta il limite di un blocco per l'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Imposta il numero di righe del baule dell'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Imposta il limite di giocatori coop per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Imposta il moltiplicatore della crescita delle colture per l'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Imposta la quantità di reset dell'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Imposta il livello dell'effetto dell'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Imposta il limite di entità per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Trasferisci un'isola a qualcun altro. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Imposta il moltiplicatore di drops dei mob per l'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Imposta un ruolo richiesto per avere un'autorizzazione, in tutte le isole. COMMAND_DESCRIPTION_ADMIN_SET_RATE: Imposta la valutazione di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Imposta il limite di ruolo per l''isola di un altro giocatore.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Attiva/disattiva le impostazioni di un'isola. COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Modifica la percentuale di generazione di un materiale dal generatore di ciottoli. COMMAND_DESCRIPTION_ADMIN_SET_SIZE: Cambia la dimensione dell'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Imposta la posizione di spawn del server. COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Imposta il moltiplicatore dei tassi dei generatori di mob per l'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Imposta il limite dei membri per l'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Imposta il livello di un potenziamento per l'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Imposta il limite delle warp di un'isola. COMMAND_DESCRIPTION_ADMIN_SETTINGS: Apri l'editor delle impostazioni del plugin. COMMAND_DESCRIPTION_ADMIN_SHOW: Ottieni informazioni su un'isola. COMMAND_DESCRIPTION_ADMIN_SPAWN: Teletrasportati nella posizione di spawn. COMMAND_DESCRIPTION_ADMIN_SPY: Attiva/disattiva la modalità spia della chat COMMAND_DESCRIPTION_ADMIN_STATS: Mostra le statistiche riguardanti il plugin. COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sincronizza il bonus di un''isola con i mondi generati.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Sincronizza i valori di aggiornamento per un'isola. COMMAND_DESCRIPTION_ADMIN_TELEPORT: Teletrasporto nelle altre isole. COMMAND_DESCRIPTION_ADMIN_TITLE: Invia un titolo al giocatore COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Invia un titolo a tutti i membri dell''isola' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: Smetti di ignorare un'isola dal menu delle migliori isole. COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Sblocca un mondo per un'isola. COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Prelevare denaro dalla banca dell'isola di un giocatore. COMMAND_DESCRIPTION_BALANCE: Controlla la quantità di denaro all'interno della banca di un'isola. COMMAND_DESCRIPTION_BAN: Bandisci un giocatore dalla tua isola. COMMAND_DESCRIPTION_BANK: Apri la banca dell'isola. COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Cambia il bioma dell'isola. COMMAND_DESCRIPTION_BORDER: Cambia il colore del bordo delle isole. COMMAND_DESCRIPTION_CHEST: Apri il baule dell'isola. COMMAND_DESCRIPTION_CLOSE: Chiudi l'isola al pubblico. COMMAND_DESCRIPTION_COOP: Aggiungi un giocatore come coop alla tua isola. COMMAND_DESCRIPTION_COOPS: Apri il menu Coops. COMMAND_DESCRIPTION_COUNTS: Vedi il numero dei blocchi della tua isola. COMMAND_DESCRIPTION_CREATE: Crea una nuova isola. COMMAND_DESCRIPTION_DEL_WARP: Elimina una warp dell'isola. COMMAND_DESCRIPTION_DEMOTE: Diminuisci il ruolo di un membro nella tua isola. COMMAND_DESCRIPTION_DEPOSIT: Deposita i soldi dal tuo conto personale nella banca dell'isola. COMMAND_DESCRIPTION_DISBAND: Sciogli la tua isola in modo permanente. COMMAND_DESCRIPTION_EXPEL: Caccia a un visitatore della tua isola. COMMAND_DESCRIPTION_FLY: Attiva/Disattiva la modalità volo nella tua isola. COMMAND_DESCRIPTION_HELP: Elenco di tutti i comandi. COMMAND_DESCRIPTION_INVITE: Invita un giocatore sulla tua isola. COMMAND_DESCRIPTION_KICK: Caccia un giocatore dalla tua isola. COMMAND_DESCRIPTION_LANG: Cambia la lingua dei messaggi. COMMAND_DESCRIPTION_LEAVE: Lascia la tua isola. COMMAND_DESCRIPTION_MEMBERS: Apri il menu dei membri. COMMAND_DESCRIPTION_MISSION: Completa una missione. COMMAND_DESCRIPTION_MISSIONS: Apri il menu delle missioni. COMMAND_DESCRIPTION_NAME: Cambia il nome della tua isola. COMMAND_DESCRIPTION_OPEN: Apri l'isola al pubblico. COMMAND_DESCRIPTION_PANEL: Apri il pannello dell'isola. COMMAND_DESCRIPTION_PARDON: Perdona(Sbandisci) un giocatore dalla tua isola. COMMAND_DESCRIPTION_PERMISSIONS: Ottieni tutte le autorizzazioni per un ruolo dell'isola. COMMAND_DESCRIPTION_PROMOTE: Promuovi un membro nella tua isola. COMMAND_DESCRIPTION_RANKUP: Sali di livello un aggiornamento dell'isola. COMMAND_DESCRIPTION_RATE: Valuta un isola. COMMAND_DESCRIPTION_RATINGS: Visualizza tutte le valutazioni dell'isola. COMMAND_DESCRIPTION_SETTINGS: Apri il menu delle impostazioni. COMMAND_DESCRIPTION_RECALC: Ri-calcola il valore della tua isola. COMMAND_DESCRIPTION_SET_DISCORD: Imposta il link discord dell'isola per i pagamenti dell'isola. COMMAND_DESCRIPTION_SET_PAYPAL: Imposta l'e-mail paypal dell'isola per i pagamenti dell'isola. COMMAND_DESCRIPTION_SET_ROLE: Cambia il ruolo di un giocatore nella tua isola. COMMAND_DESCRIPTION_SET_TELEPORT: Cambia la posizione del teletrasporto della tua isola. COMMAND_DESCRIPTION_SET_WARP: Crea una nuova warp dell'isola. COMMAND_DESCRIPTION_SHOW: Ottieni informazioni su un'isola. COMMAND_DESCRIPTION_TEAM: Ottieni informazioni sullo stato dei membri dell'isola. COMMAND_DESCRIPTION_TEAM_CHAT: Attiva/disattiva la modalità chat di gruppo. COMMAND_DESCRIPTION_TELEPORT: Teletrasportati sulla tua isola. COMMAND_DESCRIPTION_TOGGLE: Attiva/disattiva i bordi dell'isola e i posizionamenti di blocchi sovrapposti. COMMAND_DESCRIPTION_TOP: Apri il menu delle migliori isole. COMMAND_DESCRIPTION_TRANSFER: Trasferisci la leadership della tua isola. COMMAND_DESCRIPTION_UNCOOP: Rimuovi un giocatore dall'essere un coop nella tua isola. COMMAND_DESCRIPTION_UPGRADE: Apri il pannello degli aggiornamenti. COMMAND_DESCRIPTION_VALUE: Ottieni il valore di un blocco. COMMAND_DESCRIPTION_VALUES: Apri il menu dei valori. COMMAND_DESCRIPTION_VISIT: Teletrasportati nell'isola di un giocatore. COMMAND_DESCRIPTION_VISITORS: Apri il menu dei visitatori. COMMAND_DESCRIPTION_WARP: Teletrasportati ad una warp dell'isola. COMMAND_DESCRIPTION_WARPS: Apri il menu delle warp. COMMAND_DESCRIPTION_WITHDRAW: Prelevare denaro dalla banca della tua isola sul tuo conto personale. COMMAND_USAGE: '&cUsa: /{0}' COOP_ANNOUNCEMENT: '&e&lIsola | &7{0} ha aggiunto {1} come membro coop dell''isola.' COOP_BANNED_PLAYER: '&c&lErrore | &7Questo giocatore è bannato dall''isola e non può essere un mebro coop.' COOP_LIMIT_EXCEED: '&c&lErrore | &7Hai raggiunto il numero massimo di giocatori coop che l''isola può avere.' CREATE_ISLAND: '&e&lIsola | &7Creata una nuova isola a {0} in {1}ms.' CREATE_ISLAND_FAILURE: '&c&lErrore | &7Si è verificato un errore durante la creazione della tua isola. Si prega di contattare l''amministratore per indagare sul problema.' CREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.' DEBUG_MODE_DISABLED: '&e&lDebug | &7Debug mode &cOFF&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7Debug mode &aON&7.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.' DELETE_WARP: '&e&lIsola | &7Hai eliminato la warp {0}.' DELETE_WARP_SIGN_BROKE: '&7&oC''era un cartello per quel warp, è stato rimosso....' DEMOTE_LEADER: '&c&lErrore | &7Non puoi degradare i capi dell''isola.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErrore | &7Puoi degradare solo i giocatori con un ruolo dell''isola inferiore al tuo.' DEMOTED_MEMBER: '&e&lIsola | &7Hai degradato {0} a {1}.' DEPOSIT_ANNOUNCEMENT: '&e&lBanca | &7{0} ha depositato ${1} nella banca dell''isola!' DEPOSIT_ERROR: '&c&lErrore| &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lErrore | &7Non puoi distruggere al di fuori del tuo raggio di protezione.' DISBAND_ANNOUNCEMENT: '&e&lIsola | &7La tua isola è stata sciolta da {0}.' DISBAND_GIVE: '&e&lIsola | &7Hai ricevuto {0} reset da poter usare.' DISBAND_GIVE_ALL: '&e&lIsola | &7Hai dato {0} reset in più a tutti i giocatori.' DISBAND_GIVE_OTHER: '&e&lIsola | &7Hai dato {0} reset a {1}.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oLa tua isola è stata sciolta e ${0} dollari sono stati rimborsati sul tuo conto dalla banca dell''isola' DISBAND_SET: '&e&lIsola | &7Il tuo limite di reset è stato impostato a {0}.' DISBAND_SET_ALL: '&e&lIsola | &7Hai impostato il limite di reset a {0} per tutte le isole.' DISBAND_SET_OTHER: '&e&lIsola | &7Hai impostato i reset dell''isola di {0} a {1}.' DISBANDED_ISLAND: '&e&lIsola | &7Hai sciolto la tua isola.' DISBANDED_ISLAND_OTHER: '&e&lIsola | &7Hai sciolto l''isola di {0}.' DISBANDED_ISLAND_OTHER_NAME: '&e&lIsola | &7Hai sciolto l''isola {0}.' ENTER_PVP_ISLAND: '&7&oSei stato teletrasportato in un''isola con PVP abilitato. Sei immune al PVP per i prossimi 10 secondi...' EXPELLED_PLAYER: '&e&lIsola | &7{0} è stato espulso dall''isola.' FORMAT_QUAD: Q FORMAT_TRILLION: T FORMAT_BILLION: B FORMAT_MILLION: M FORMAT_THOUSANDS: K FORMAT_SECONDS_NAME: secondi FORMAT_SECOND_NAME: secondo FORMAT_MINUTES_NAME: minuti FORMAT_MINUTE_NAME: minuto FORMAT_HOURS_NAME: ore FORMAT_HOUR_NAME: ora FORMAT_DAYS_NAME: giorni FORMAT_DAY_NAME: giorno GENERATOR_CLEARED: '&e&lIsola | &7Cancellati con successo gli importi del generatore per l''isola di {0}.' GENERATOR_CLEARED_NAME: '&e&lIsola | &7Cancellati con successo gli importi del generatore per l''isola {0}.' GENERATOR_CLEARED_ALL: '&e&lIsola | &7Cancellati con successo gli importi del generatore per tutte le isole.' GENERATOR_UPDATED: '&e&lIsola | &7Aggiornato con successo la percentuale di generazione di {0} sull''isola di {1}.' GENERATOR_UPDATED_NAME: '&e&lIsola | &7Aggiornato con successo la percentuale di generazione di {0} sull''isola {1}.' GLOBAL_COMMAND_EXECUTED: '&e&lIsola | &7Successfully executed the command on {0}''s island members!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lIsola | &7Successfully executed the command on the island members of {0}!' GENERATOR_UPDATED_ALL: '&e&lIsola | &7Aggiornato con successo la percentuale di generazione di {0} in tutte le isole.' GLOBAL_MESSAGE_SENT: '&e&lIsola | &7Il messaggio è stato inviato correttamente ai membri dell''isola di {0}!' GLOBAL_MESSAGE_SENT_NAME: '&e&lIsola | &7Il messaggio è stato inviato correttamente ai membri dell''isola di {0}!' GLOBAL_TITLE_SENT: '&e&lIsola | &7Il titolo è stato inviato con successo ai membri dell''isola di {0}!' GLOBAL_TITLE_SENT_NAME: '&e&lIsola | &7Il titolo è stato inviato con successo ai membri dell''isola {0}!' GOT_BANNED: '&e&lIsola | &7Sei stato bannato dall''isola di {0}.' GOT_DEMOTED: '&e&lIsola | &7Sei stato retrocesso a {0} nella tua isola.' GOT_EXPELLED: '&e&lIsola | &7&o{0} ti ha espulso dall''isola.' GOT_INVITE: '&e&lIsola | &7{0} ti ha invitato nella sua isola.' GOT_INVITE_TOOLTIP: '&7Clicca il messaggio per accettare l''invito.' GOT_KICKED: '&e&lIsola | &7{0} ti ha cacciato dall''isola.' GOT_PROMOTED: '&e&lIsola | &7Sei stato promosso a {0} nella tua isola.' GOT_REVOKED: '&e&lIsola | &7{0} ha revocato il suo invito.' GOT_UNBANNED: '&e&lIsola | &7Sei stato sbannato dall''isola di {0}.' HIT_ISLAND_MEMBER: '&c&lErrore | &7Non puoi colpire i membri della tua isola.' HIT_PLAYER_IN_ISLAND: '&c&lErrore | &7Non puoi colpire i giocatori all''interno delle isole affinchè non venga attivato il pvp nell''isola (/is settings).' IGNORED_ISLAND: '&e&lIsola | &7L''isola di {0] da ora in poi verrà ignorata dalle migliori isole.' IGNORED_ISLAND_NAME: '&e&lIsola | &7L''isola {0} da ora in poi verrà ignorata dalle migliori isole.' INTERACT_OUTSIDE_ISLAND: '&c&lErrore | &7Non puoi interagire al di fuori del tuo raggio di protezione.' INVALID_AMOUNT: '&c&lErrore | &7Importo invalido {0}.' INVALID_BIOME: '&c&lErrore | &7Bioma invalido {0}.' INVALID_BLOCK: '&c&lErrore| &7Posizione del blocco invalida {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Colore del bordo non valido: {0}' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lErrore| &7Effetto invalido {0}.' INVALID_ENTITY: '&c&lErrore | &7Entità invalida {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Intervallo non valido: {0}' INVALID_ISLAND: '&c&lErrore | &7Non hai un''isola.' INVALID_ISLAND_LOCATION: '&c&lErrore | &7Non c''è un isola nella tua posizione.' INVALID_ISLAND_OTHER: '&c&lErrore | &7{0} non ha un isola.' INVALID_ISLAND_OTHER_NAME: '&c&lErrore | &7Non esiste un isola col nome di {0}.' INVALID_ISLAND_PERMISSION: | &c&lErrore | &7Impossibile trovare il permesso dell''isola {0}. &c&lErrore | &7Autorizzazioni dell''isola: {1} INVALID_LEVEL: '&c&lErrore | &7Livello non valido {0}.' INVALID_LIMIT: '&c&lErrore | &7Limite non valido {0}.' INVALID_MATERIAL: '&c&lErrore | &7Materiale non valido {0}.' INVALID_MATERIAL_DATA: '&c&lErrore | &7Il material-data non è corretto {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErrore | &7La missione {0} non è corretta.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Modulo non valido: {0}' INVALID_MULTIPLIER: '&c&lErrore | &7Il moltiplicatore {0} non è corretto.' INVALID_PAGE: '&c&lErrore | &7La pagina {0} non è corretta.' INVALID_PERCENTAGE: '&c&lErrore | &7La percentuale deve essere compresa tra 0 e 100.' INVALID_PLAYER: '&c&lErrore | &7Non sono riuscito a trova il giocatore {0}' INVALID_RATE: | &c&lErrore | &7Impossibile trovare una valutazione con il nome {0}. &c&lErrore | &7Valutazioni dell''isola: {1} INVALID_ROWS: '&c&lErrore | &7Il numero di righe non è corretto: {0}' INVALID_ROLE: | &c&lErrore | &7Impossibile trovare il ruolo dell''isola {0}. &c&lErrore | &7Ruoli dell'isola: {1} INVALID_SCHEMATIC: '&c&lErrore | &7Non ho trovato la schematica di nome {0}.' INVALID_SETTINGS: | &c&lErrore | &7Impossibile trovare le impostazioni dell''isola {0}. &c&lErrore | &7Impostazioni dell'isola: {1} INVALID_SIZE: '&c&lErrore | &7Dimensioni non valide {0}.' INVALID_SLOT: '&c&lErrore | &7Slot non valido {0}.' INVALID_TITLE: '&c&lErrore | &7Il titolo inserito non è valido' INVALID_TOGGLE_MODE: '&c&lErrore | &7Non è possibile attivare/disattivare {0}.' INVALID_UPGRADE: | &c&lErrore | &7Impossibile trovare un aggiornamento chiamato {0}. &c&lErrore | &7Aggiornamenti: {1} INVALID_VISIT_LOCATION: '&c&lErrore | &7Quest''isola non ha alcuna impostato la posizione dei visitatori.' INVALID_VISIT_LOCATION_BYPASS: '&7&oHai la modalità bypass, teletrasportandoti sull''isola...' INVALID_WARP: '&c&lErrore | &7Warp invalida {0}.' INVALID_WORLD: '&c&lErrore| &7Mondo invalido {0}.' INVITE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha invitato {1} nella squadra dell''isola.' INVITE_BANNED_PLAYER: '&c&lErrore | &7Questo giocatore è bannato dall''isola e non può essere invitato.' INVITE_TO_FULL_ISLAND: '&c&lErrore | &7Non puoi invitare altri membri sulla tua isola.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lErrore | &7Un''isola con quel nome esiste già.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBanca | &7La banca dell''isola è vuota.' ISLAND_BANK_SHOW: '&e&lBanca | &7La tua isola ha ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBanca | &7L''isola di {0} ha ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanca | &7L''isola {0} ha ${1}.' ISLAND_BEING_CALCULATED: '&c&lErrore | &7Non è possibile interagire con i blocchi durante il ricalcolo dell''isola!' ISLAND_CLOSED: '&e&lIsola | &7Chiusa con successo l''isola al pubblico.' ISLAND_CREATE_PROCESS_FAIL: '&c&lErrore | &7Hai un''attività di creazione dell''isola già in corso.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsola | &7Elaborazione della richiesta...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lFly | &7La modalità volo dell''isola è stata &cdisattivata&7 automaticamente.' ISLAND_FLY_ENABLED: '&e&lFly | &7La modalità volo dell''isola è stata &aattivata&7 automaticamente.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIsola | &7&oSei stato all''interno di un''isola che è stata sciolta, quindi sei stato teletrasportato allo spawn...' ISLAND_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...' ISLAND_HELP_FOOTER: | &e&lSuperiorSkyblock &7Creato da Ome_R &e&lTradotto&7 in Italiano da xSavior_of_God ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista dei comandi [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Usa /is help {0} per girare pagina.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIsola | &7Bank Limit: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lIsola | &7Limite dei blocchi: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIsola | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIsola | &7Coop Limit: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lIsola | &7Effetti dell'isola: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIsola | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lIsola | &7Limite Entità: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIsola | &7 {0}: {1}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIsola | &7Moltiplicatore delle colture: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIsola | &7Moltiplicatore dei drops dei mob: {0}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lIsola | &7Percentuali del generatore: {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIsola | &7 {0}: {1}%' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lIsola | &7Limiti del ruolo: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIsola | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lIsola | &7Dimensione dei bordi: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIsola | &7Moltiplicatore dei generatori di mob: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIsola | &7Limite del team: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lIsola | &7Aggiornamenti: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIsola | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIsola | &7Limite di warps: {0}' ISLAND_INFO_BANK: '&e&lIsola | &7Banca: {0}' ISLAND_INFO_BONUS: '&e&lIsola | &7Valore Bonus: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lIsola | &7Livello Bonus: {0}' ISLAND_INFO_CREATION_TIME: '&e&lIsola | &7Tempo di creazione: {0}' ISLAND_INFO_DISCORD: '&e&lIsola | &7Discord: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lIslola | &7Ultimo aggiornamento: {0} fa' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIsola | &7Ultimo aggiornamento: &aAttualmente Attivo' ISLAND_INFO_LEVEL: '&e&lIsola | &7Livello: {0}' ISLAND_INFO_LOCATION: '&e&lIsola | &7Casa: {0}' ISLAND_INFO_NAME: '&e&lIsola | &7Nome: {0}' ISLAND_INFO_OWNER: '&e&lIsola | &7Capo: {0}' ISLAND_INFO_PAYPAL: '&e&lIsola | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lIsola | &7 - {0}' ISLAND_INFO_RATE: '&e&lIsola | &7Valutazione: {0} &7({1}/5) - valutato da {2} giocatore/i.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: ✦ ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIsola | &7{0}: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIsola | &7Numero di visitatori: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIsola | &7Valore: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsola | &7Aperta con successo l''isola al pubblico.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lAnteprima | &7Sei andato troppo lontano, non sei più in modalità anteprima.' ISLAND_PREVIEW_CANCEL: '&e&lAnteprima | &7Hai annullato la modalità di anteprima.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFERMA' ISLAND_PREVIEW_CANCEL_TEXT: 'ANNULLA' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lAnteprima | &7Hai avviato la modalità di anteprima per la schematica {0}. &e&lAnteprima | &7Scrivi &a&lCONFERMA &7per creare una nuova isola, oppure &c&lANNULLA &7per annullare la modalità di anteprima. &e&lAnteprima | &7Non è possibile lasciare l'area dell'isola, altrimenti la modalità anteprima verrà annullata automaticamente. ISLAND_PROTECTED: '&c&lErrore | &7Quest''isola è protetta.' ISLAND_PROTECTED_OPPED: '&7&oPuoi aggirare questa restrizione utilizzando "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lIsola | &7Membri dell''isola di {0} &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Disconnesso)' ISLAND_TEAM_STATUS_ONLINE: '&a(Connesso)' ISLAND_TEAM_STATUS_ROLES: '&e&lIsola | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Disconnesso)' ISLAND_TOP_STATUS_ONLINE: '&a(Connesso)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Privato]' ISLAND_WAS_CLOSED: '&e&lIsola | &7&oL''isola in cui ti trovavi è stata chiusa e sei stato teletrasportato allo spawn...' ISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.' ISLAND_WORTH_RESULT: '&e&lIsola | &7Il valore della tua isola è {0} [Livello {1}]' ISLAND_WORTH_TIME_OUT: '&c&lError | &7L''attività di calcolo è scaduta. Riprovare più tardi...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lIsola | &7{0} si è unito alla tua isola.' JOIN_ANNOUNCEMENT: '&e&lIsola | &7{0} si è unito alla tua isola.' JOIN_FULL_ISLAND: '&c&lErrore | &7Quest''isola ha raggiunto il numero massimo di membri consentiti.' JOIN_WHILE_IN_ISLAND: '&c&lErrore | &7Sei già dentro un''isola.' JOINED_ISLAND: '&e&lIsola | &7Ti sei unito all''isola di {0}.' JOINED_ISLAND_NAME: '&e&lIsola | &7Ti sei unito all''isola {0}.' JOINED_ISLAND_AS_COOP: '&e&lIsola | &7Ora sei un membro coop dell''isola di {0}.' JOINED_ISLAND_AS_COOP_NAME: '&e&lIsola | &7Ora sei un membro coop dell''isola {0}.' KICK_ANNOUNCEMENT: '&e&lIsola | &7{0} è stato cacciato dall''isola da {1}.' KICK_ISLAND_LEADER: '&c&lErrore | &7Non puoi cacciare il capo dell''isola, per farlo usa /is admin disband' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lErrore | &7Puoi cacciare solo giocatori con un ruolo insulare inferiore al tuo.' LACK_CHANGE_PERMISSION: '&c&lErrore | &7È necessario disporre di questa autorizzazione per cambiarla in altri ruoli.' LAST_ROLE_DEMOTE: '&c&lErrore | &7Non puoi più degradare questo giocatore.' LAST_ROLE_PROMOTE: '&c&lErrore | &7Non puoi più promuovere questo giocatore.' LEAVE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha lasciato l''isola.' LEAVE_ISLAND_AS_LEADER: | &c&lErrore | &7Non puoi lasciare la tua isola quando la possiedi. &c&lErrore | &7È possibile trasferire la proprietà utilizzando /is transfer. LEFT_ISLAND: '&e&lIsola | &7Hai lasciato la tua isola.' LEFT_ISLAND_COOP: '&e&lIsola | &7Non sei più un membro coop dell''isola di {0}.' LEFT_ISLAND_COOP_NAME: '&e&lIsola | &7Non sei più un membro coop dell''isola {0}.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lErrore | &7È necessario fornire un materiale solido.' MAXIMUM_LEVEL: '&c&lErrore | &7Il livello massimo per questo aggiornamento è {0}.' MESSAGE_SENT: '&e&lIsola | &7{0} inviato correttamente il messaggio!' MISSION_CANNOT_COMPLETE: '&c&lErrore | &7Non puoi ancora completare questa missione.' MISSION_NO_AUTO_REWARD: '&e&lMission | &7Hai tutti i materiali necessari per finire {0} - usa /is missions per completarlo!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lErrore | &7Devi completare la missione {0} prima di completare questa missione.' MISSION_STATUS_COMPLETE: '&e&lMission | &7Modificato lo stato della missione {0} da completare per {1}.' MISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Modificato lo stato di tutte le missioni da completare per {0}.' MISSION_STATUS_RESET: '&e&lMission | &7Ripristinato lo stato della missione {0} per {1}.' MISSION_STATUS_RESET_ALL: '&e&lMission | &7Ripristina lo stato di tutte le missioni per {0}.' MODULE_ALREADY_INITIALIZED: '&e&lModule | &7Questo modulo è già caricato.' MODULE_INFO: | &e&lModule | &7{0} by {1} &e&lModule | &7&m-------------------- &e&lModule | &7{2} MODULE_LOADED_SUCCESS: '&e&lModule | &7Caricamento del modulo {0} avvenuto con successo.' MODULE_LOADED_FAILURE: '&e&lModule | &7Impossibile caricare il modulo {0}. Controlla la console per ulteriori informazioni.' MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Modulo disabilitato con successo.' MODULES_LIST: '&fModuli ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lIsola | &7{0} ha cambiato il nome della sua isola in {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lErrore | &7Non puoi usare quel nome.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lErrore | &7Non puoi usare i nomi dei giocatori come nome dell''isola.' NAME_TOO_LONG: '&c&lErrore | &7I nomi delle isole non possono avere una lunghezza superiore a {0} caratteri.' NAME_TOO_SHORT: '&c&lErrore | &7I nomi delle isole non possono avere una lunghezza inferiore a {0} caratteri.' NO_BAN_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per poter vietare i giocatori.' NO_CLOSE_BYPASS: '&c&lErrore | &7Quest''isola non è aperta al pubblico.' NO_CLOSE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per chiudere l''isola al pubblico.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per aggiungere giocatori come membri coop.' NO_DELETE_WARP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per eliminare le warp.' NO_DEMOTE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per degradare i giocatori.' NO_DEPOSIT_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per depositare denaro nella banca dell''isola.' NO_DISBAND_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per sciogliere la tua isola.' NO_EXPEL_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per espellere i giocatori dalla tua isola.' NO_INVITE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per invitare i giocatori.' NO_ISLAND_CHEST_PERMISSION: '&c&lErrore | &7Devi essere {0} per accedere al baule dell''isola.' NO_ISLAND_INVITE: '&c&lErrore | &7Impossibile trovare inviti da quest''isola.' NO_ISLANDS_TO_PURGE: '&c&lErrore | &7Non ci sono isole da eliminare.' NO_KICK_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per cacciare i giocatori.' NO_MORE_DISBANDS: '&c&lErrore | &7Non puoi più sciogliere altre isole.' NO_MORE_WARPS: '&c&lErrore | &7La tua isola non può avere più warp.' NO_NAME_PERMISSION: '&c&lErrore | &7Non puoi cambiare il nome della tua isola.' NO_OPEN_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per aprire l''isola al pubblico.' NO_PERMISSION_CHECK_PERMISSION: '&c&lErrore | &7Devi avere almeno {0} per ottenere informazioni sulle autorizzazioni.' NO_PROMOTE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per promuovere i giocatori.' NO_RANKUP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per poter potenziare gli aggiornamenti.' NO_RATINGS_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per verificare le valutazioni.' NO_SET_BIOME_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per cambiare il bioma dell''isola.' NO_SET_DISCORD_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per cambiare il Discord dell''isola.' NO_SET_HOME_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per impostare la posizione del teletrasporto dell''isola.' NO_SET_PAYPAL_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per cambiare l''email PayPal dell''isola.' NO_SET_ROLE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per impostare i ruoli per i giocatori.' NO_SET_SETTINGS_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per modificare le impostazioni dell''isola.' NO_SET_WARP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per impostare le warp dell''isola.' NO_TRANSFER_PERMISSION: '&c&lErrore | &7Devi essere il capo dell''isola per trasferire la leadership.' NO_UNCOOP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per rimuovere i giocatori dall''essere membri coop.' NO_UPGRADE_PERMISSION: '&c&lErrore | &7Ti manca l''autorizzazione per passare a un altro livello.' NO_WITHDRAW_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per prelevare denaro dalla banca dell''isola.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lErrore | &7Non hai abbastanza soldi per depositare {0} dollari nella banca della tua isola.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lErrore | &7Non hai abbastanza soldi.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7Non hai abbastanza soldi per usare le deformazioni dell''isola.' OPEN_MENU_WHILE_SLEEPING: '&7&oNon credi di essere troppo stanco per interagire con i menu?' PANEL_TOGGLE_OFF: | &e&lPanel | &7Pannello dell'isola impostato &cOFF&7. &e&lPanel | &7Eseguendo /is ti teletrasporterai sulla tua isola. PANEL_TOGGLE_ON: | &e&lPanel | &7Pannello dell'isola impostato &aON&7. &e&lPanel | &7Eseguendo /is aprirà il pannello per te. PERMISSION_CHANGED: '&e&lIsola | &7Aggiornata correttamente l''autorizzazione {0} dell''isola di {1}.' PERMISSION_CHANGED_NAME: '&e&lIsola | &7Aggiornata correttamente l''autorizzazione {0} dell''isola {1}.' PERMISSION_CHANGED_ALL: '&e&lIsola | &7Aggiornata correttamente l''autorizzazione {0} di tutte le isola.' PERSISTENT_DATA_EMPTY: '&c&lError | &7Nessun dato trovato per la tua query.' PERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIsola | &7Successfully reset all the permissions for {0} to default values!' PERMISSIONS_RESET_ROLES: '&e&lIsola | &7Successfully reset all the permissions of the island to default values!' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Si' PLAYER_ALREADY_BANNED: '&c&lErrore | &7Questo giocatore è già stato bannato.' PLAYER_ALREADY_COOP: '&c&lErrore | &7Questo giocatore è già un membro coop.' PLAYER_ALREADY_IN_ISLAND: '&c&lErrore | &7Questo giocatore è già all''interno di un''isola.' PLAYER_ALREADY_IN_ROLE: '&c&lErrore | &7{0} è già un {1}.' PLAYER_EXPEL_BYPASS: '&c&lErrore | &7Questo utente non può essere espulso dall''isola.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lIsola | &7{0} è entrato nel server.' PLAYER_NOT_BANNED: '&c&lErrore | &7Questo giocatore non è bannato.' PLAYER_NOT_COOP: '&c&lErrore | &7Questo giocatore non è un membro coop.' PLAYER_NOT_INSIDE_ISLAND: '&c&lErrore | &7Questo giocatore non è all''interno della tua isola.' PLAYER_NOT_ONLINE: '&c&lErrore | &7Questo giocatore non è in linea!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lIsola | &7{0} è uscito dal server.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErrore | &7Puoi promuovere solo giocatori con un ruolo inferiore al tuo.' PROMOTED_MEMBER: '&e&lIsola | &7Hai promosso {0} a {1} nella sua isola.' PURGE_CLEAR: '&e&lIsola | &7Eliminate con successo tutte le isole in coda da eliminare.' PURGED_ISLANDS: | &e&lIsola | &7{0} isole verranno eliminate al riavvio del server. &e&lIsola | &7Puoi annullarlo in qualsiasi momento utilizzando /is admin purge cancel. RANKUP_SUCCESS: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per l''isola di {1}.' RANKUP_SUCCESS_ALL: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per tutte le isole.' RANKUP_SUCCESS_NAME: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per l''isola {1}.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha valutato la tua isola {1} stelle su 5!' RATE_CHANGE_OTHER: '&e&lIsola | &7Hai cambiato la valutazione di {0} a {1}.' RATE_OWN_ISLAND: '&c&lErrore | &7Non puoi valutare la tua isola.' RATE_REMOVE_ALL: '&e&lIsola | &7Rimosse con successo tutte le valutazioni di {0}.' RATE_REMOVE_ALL_ISLANDS: '&e&lIslola | &7Rimosse con successo le valutazioni di tutte le isole.' RATE_SUCCESS: '&e&lIsola | &7Hai valutato quest''isola con {0} stelle!' REACHED_BLOCK_LIMIT: '&e&lAggiornamenti | &7Hai raggiunto il limite di {0} dell''isola.' REACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.' RECALC_ALREADY_RUNNING: '&c&lErrore | &7La tua isola è già in fase di ricalcolo.' RECALC_ALREADY_RUNNING_OTHER: '&c&lErrore | &7L''isola è già stata ricalcolata.' RECALC_ALL_ISLANDS: '&e&lIsola | &7Ricalcolo di tutte le isole...' RECALC_ALL_ISLANDS_DONE: '&e&lIsola | &7Completato con successo il ricalcolo di tutte le isole.' RECALC_PROCCESS_REQUEST: '&e&lIsola | &7Elaborazione della richiesta...' RELOAD_COMPLETED: '&e&lIsola | &7Il reload è terminato!' RELOAD_PROCCESS_REQUEST: '&e&lIsola | &7Starting to reload configurations...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha revocato l''invito di {1}.' RESET_WORLD_SUCCEED: '&e&lIsola | &7Ripristinato il mondo {0} con successo per l''isola di {1}.' RESET_WORLD_SUCCEED_ALL: '&e&lIsola | &7Ripristinato il mondo {0} con successo per tutte le isole.' RESET_WORLD_SUCCEED_NAME: '&e&lIsola | &7Ripristinato il mondo {0} con successo per {1}.' SAME_NAME_CHANGE: '&c&lErrore | &7Devi inserire un nome diverso dal tuo attuale nome dell''isola.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Posizione selezionata #2 ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lErrore | &7Non hai selezionato due posizioni.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Elaborazione della richiesta...' SCHEMATIC_READY_TO_CREATE: | &e&lSchematics | &7Hai selezionato due posizioni. Esegui /is admin schematic per creare una nuova schematica. &e&lSchematics | &7Assicurati di trovarti nella posizione di teletrasporto quando esegui il comando. SCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Posizione selezionata #1 ({0})' SCHEMATIC_SAVED: '&e&lSchematics | &7Schematica salvata con successo!' SELF_ROLE_CHANGE: '&c&lErrore | &7Non puoi cambiare il tuo ruolo.' SET_UPGRADE_LEVEL: '&e&lAggiornamenti | &7Aggiornato con successo il livello di {0} per l''isola di {1}.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il livello di {0} per {1}.' SET_WARP: '&e&lIsola | &7Creato con successo un nuovo warp a {0}.' SET_WARP_OUTSIDE: '&c&lErrore | &7Non puoi impostare warp fuori dalla tua isola.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} dell''isola di {1}.' SETTINGS_UPDATED_NAME: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} di {1}.' SETTINGS_UPDATED_ALL: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} a tutte le isole.' SIZE_BIGGER_MAX: '&c&lErrore | &7Non è possibile impostare una dimensione maggiore della dimensione massima dell''isola.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Hai teletrasportato {0} con successo allo spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7La posizione di spawn è stata aggiornata correttamente alle coordinate: {0}' SPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lAggiornamenti | &7Sincronizzati con successo tutti i valori degli upgrade dell''isola di {0}.' SYNC_UPGRADES_ALL: '&e&lAggiornamenti | &7Sincronizzati con successo tutti i valori degli upgrade di tutte le isole.' SYNC_UPGRADES_NAME: '&e&lAggiornamenti | &7Sincronizzati con successo tutti i valori degli upgrade di {0}.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lErrore | &7Non sei nella tua isola.' TELEPORT_OUTSIDE_ISLAND: '&c&lErrore | &7Non puoi teletrasportarti fuori dal raggio di protezione.' TELEPORT_WARMUP: '&7&oVerrai teletrasportato in {0}... Non muoverti!' TELEPORT_WARMUP_CANCEL: '&7&oTi sei mosso e quindi il teletrasporto è stato cancellato.' TITLE_SENT: '&e&lIsola | &7Inviato con successo il titolo {0}' TELEPORTED_FAILED: '&e&lIsola | &7Sembra che quest''isola non abbia blocchi sicuri. Si prega di contattare un membro dello staff.' TELEPORTED_SUCCESS: '&e&lIsola | &7Sei stato teletrasportato sulla tua isola.' TELEPORTED_TO_WARP: '&e&lIsola | &7Teletrasportato con successo al warp dell''isola.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIsola | &7Il giocatore {0} si è teletrasportato alla warp {1} dell''isola.' TOGGLED_BYPASS_OFF: '&e&lBypass | &7Modalità bypass &cOFF&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Modalità bypass &aON&7.' TOGGLED_FLY_OFF: '&e&lFly | &7Modalità volo &cOFF&7.' TOGGLED_FLY_ON: '&e&lFly | &7Modalità volo &aON&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Modalità schematica &cOFF&7.' TOGGLED_SCHEMATIC_ON: | &e&lSchematics | &7Schematic mode &aON&7. &e&lSchematics | &7Seleziona un'area usando un'ascia d'oro. TOGGLED_SPY_OFF: '&e&lSpy | &7Spy chat &cOFF&7.' TOGGLED_SPY_ON: '&e&lSpy | &7Spy chat &aON&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Stacker di blocchi &cOFF&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Stacker di blocchi &aON&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Chat di squadra &cOFF&7.' TOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Chat di squadra &aON&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lBorder | &7Bordi del mondo &cOFF&7.' TOGGLED_WORLD_BORDER_ON: '&e&lBorder | &7Bordi del mondo &aON&7.' TRANSFER_ADMIN: '&e&lIsola | &7Hai trasferito la leadership di {0} a {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lErrore | &7{0} è già il leader della sua isola.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lErrore | &7Questi giocatori non sono nelle stesse isole.' TRANSFER_ADMIN_NOT_LEADER: '&c&lErrore | &7Questo giocatore non è un leader di nessuna isola.' TRANSFER_ALREADY_LEADER: '&c&lErrore | &7Sei già il capo di quest''isola.' TRANSFER_BROADCAST: '&e&lIsola | &7La leadership dell''isola è stata trasferita a {0}.' UNBAN_ANNOUNCEMENT: '&e&lIsola | &7{0} è stato sbannato dall''isola da {1}.' UNCOOP_ANNOUNCEMENT: '&e&lIsola | &7{0} ha rimosso {1} dall''essere un membro coop.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsola | &7Non ci sono membri dell''isola online e quindi sei stato espulso automaticamente.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsola | &7{0} è uscito dal server, non è più un membro coop.' UNIGNORED_ISLAND: '&e&lIsola | &7L''isola di {0} ora NON È PIÙ IGNORATA dalle isole migliori(/is top).' UNIGNORED_ISLAND_NAME: '&e&lIsola | &7L''isola {0} ora NON È PIÙ IGNORATA dalle isole migliori(/is top).' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIsola | &7&oSembra che questa warp non sia sicura. Per favore, prova un altra warp.' UPDATED_PERMISSION: '&e&lIsola | &7Autorizzazioni aggiornate per {0}.' UPDATED_SETTINGS: '&e&lIsola | &7Aggiornate le impostazioni dell''isola {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7Puoi eseguire nuovamente l''aggiornamento solo tra {0}.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lErrore | &7Non puoi usare questo comando quando ti trovi sopra ad altre isole.' WARP_ALREADY_EXIST: '&c&lErrore | &7C''è già una warp con questo nome.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lWarps | &7Inserisci una nuova descrizione (Scrivi "-cancel" per annullare) &e&lWarps | &7È possibile separare le righe utilizzando "\n". WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Inserisci un nome (Scrivi "-cancel" per annullare):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Inserisci un nuovo tipo di materiale (Scrivi "-cancel" per annullare):' WARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Icona della categoria aggiornata con successo.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lErrore | &7I nomi delle categorie delle warps non possono essere vuoti.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lErrore | &7I nomi delle categorie delle warps non possono essere più lunghi di 255 caratteri.' WARP_CATEGORY_SLOT: '&e&lWarps | &7Inserisci un nuovo slot (Scrivi "-cancel" per annullare):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lErrore | &7Questo slot è già occupato da un''altra categoria.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Modificato con successo lo slot della categoria in {0}.' WARP_CATEGORY_RENAME: '&e&lWarps | &7Inserisci un nuovo nome (Scrivi "-cancel" per annullare):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lErrore | &7Questo nome è già preso da un''altra categoria.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7La categoria è stata rinominata correttamente in {0}.' WARP_ICON_NEW_LORE: | &e&lWarps | &7Enter a new lore (Scrivi "-cancel" per annullare) &e&lWarps | &7You can separate lines by using "\n". WARP_ICON_NEW_NAME: '&e&lWarps | &7Inserisci un nome (Scrivi "-cancel" per annullare):' WARP_ICON_NEW_TYPE: '&e&lWarps | &7Inserisci un nuovo tipo di materiale (Scrivi "-cancel" per annullare):' WARP_ICON_UPDATED: '&e&lWarps | &7Icona del Warp aggiornata con successo.' WARP_ILLEGAL_NAME: '&c&lErrore | &7I nomi di Warp non possono essere vuoti.' WARP_LOCATION_UPDATE: '&e&lWarps | &7La posizione del Warp è stata aggiornata con successo alla tua posizione.' WARP_NAME_TOO_LONG: '&c&lErrore | &7I nomi delle Warps non possono essere più lunghi di 255 caratteri.' WARP_PUBLIC_UPDATE: '&e&lWarps | &7Hai aperto con successo la Warp al pubblico.' WARP_PRIVATE_UPDATE: '&e&lWarps | &7Chiuso con successo la Warp al pubblico.' WARP_RENAME: '&e&lWarps | &7Inserisci un nuovo nome (Scrivi "-cancel" per annullare):' WARP_RENAME_ALREADY_EXIST: '&c&lErrore | &7Questo nome è già preso da un altra Warp.' WARP_RENAME_SUCCESS: '&e&lWarps | &7Rinominato correttamente il Warp in {0}.' WITHDRAW_ALL_MONEY: | &e&lBanca | &7La banca dell'isola ha solo {0} dollari al suo interno. &e&lBanca | &7&oPrelevamento di tutti i soldi..." WITHDRAW_ANNOUNCEMENT: '&e&lBanca | &7{0} ha prelevato ${1} dalla banca dell''isola!' WITHDRAW_ERROR: '&c&lErrore | &7{0}.' WITHDRAWN_MONEY: '&e&lBanca | &7Hai ritirato ${0} dalla banca dell''isola di {1}!' WITHDRAWN_MONEY_NAME: '&e&lBanca | &7Hai ritirato ${0} dalla riva dell''isola {1}!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lMondi | &7Il mondo {0} non è ancora stato sbloccato!' ================================================ FILE: src/main/resources/lang/iw-IL.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # You can find a tutorial about configuring messages here: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lIsland | &7Successfully added the player {0} to {1}''s island.' ADMIN_ADD_PLAYER_NAME: '&e&lIsland | &7Successfully added the player {0} to the island {1}.' ADMIN_DEPOSIT_MONEY: '&e&lקנב | &7.{1} לש יאה לש קנבל ${0} תרבעה' ADMIN_DEPOSIT_MONEY_NAME: '&e&lקנב | &7.{1} יאה לש קנבל ${0} תרבעה' ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Ome_R י"ע תנכות' ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7ןימדא תודוקפ תמישר [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7אבה דומעל רבעמל /is admin {0} ץרה.' ALREADY_IN_ISLAND: '&c&lהאיגש | &7רחא יא לא ךייתשמ רבכ התא.' ALREADY_IN_ISLAND_OTHER: '&c&lהאיגש | &7ךלש יאב אצמנ רבכ הזה ןקחשה.' BAN_ANNOUNCEMENT: '&e&lיא | &7{1} ידי לע יאהמ קחרוה. {0}' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lהאיגש | &7םכלשמ הכומנ הגרד ילעב םינקחש קר קיחרהל םילוכי םתא.' BANK_DEPOSIT_CUSTOM: '&e&lBank | &7Type the amount you want to deposit:' BANK_DEPOSIT_COMPLETED: 'Deposit Completed' BANK_LIMIT_EXCEED: '&c&lError | &7You have exceeded your bank limit.' BANK_WITHDRAW_CUSTOM: '&e&lBank | &7Type the amount you want to withdraw:' BANK_WITHDRAW_COMPLETED: 'Withdraw Completed' BANNED_FROM_ISLAND: '&c&lהאיגש | &7יאהמ קחרומ התא.' BLOCK_COUNT_CHECK: '&e&lIsland | &7This island has x{0} {1}.' BLOCK_COUNTS_CHECK: | &e&lIsland | &7This island has the following blocks: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lIsland | &7This island has no tracked blocks.' BLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}' BLOCK_LEVEL: '&e&lתודוקנ | &7{1} אוה {0} קולבה לש תודוקנה רפסמ.' BLOCK_LEVEL_WORTHLESS: '&e&lתודוקנ | &7םולכ הווש אל {0} קולבה.' BLOCK_VALUE: '&e&lיווש | &7{1} אוה {0} קולבה לש יוושה.' BLOCK_VALUE_WORTHLESS: '&e&lיווש | &7םולכ הווש אל {0} קולבה.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Blue' BORDER_PLAYER_COLOR_NAME_RED: 'Red' BORDER_PLAYER_COLOR_NAME_GREEN: 'Green' BORDER_PLAYER_COLOR_UPDATED: '&e&lלובג | &7{0} ל החלצהב הנוש ךלש לובגה עבצ.' BUILD_OUTSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאל ץוחמ תונבל לוכי אל התא.' CANNOT_SET_ROLE: '&c&lהאיגש | &7{0} ל ןקחשה לש הגרדה תא תונשל לוכי אל התא.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lהאיגש | &7םינקחשל ךלשמ תוכומנ רתוי תוגרד קר תונשל לושכי התא.' CHANGED_BANK_LIMIT: '&e&lUpgrades | &7Successfully updated the bank limit of {0}''s island.' CHANGED_BANK_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the bank limit of all the islands.' CHANGED_BANK_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the bank limit of {0}.' CHANGED_BIOME: '&e&lיא | &7תרשל שדחמ רבחתהל שי ,םייונישה תא תוארל תנמ לע .{0} ל החלצהב הנוש יאה לש םויבה.' CHANGED_BIOME_ALL: '&e&lIsland | &7Successfully changed biome to {0} for all the islands.' CHANGED_BIOME_NAME: '&e&lIsland | &7Successfully changed biome to {0} for the island {1}.' CHANGED_BIOME_OTHER: '&e&lIsland | &7Successfully changed biome to {0} for {1}''s island.' CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Successfully changed the block amount at {0} to {1}.' CHANGED_BLOCK_LIMIT: '&e&lםיגורדש | &7{1} לש יאל החלצהב הנכדוע {0} קולבה תלבגה.' CHANGED_BLOCK_LIMIT_ALL: '&e&lםיגורדש | &7םייאה לכל החלצהב הנכדוע {0} קולבה תלבגה.' CHANGED_BLOCK_LIMIT_NAME: '&e&lםיגורדש | &7{1} יאל החלצהב הנכדוע {0} קולבה תלבגה.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}''s island.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for all the islands.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}.' CHANGED_COOP_LIMIT: '&e&lUpgrades | &7Successfully updated the coop players limit of {0}''s island.' CHANGED_COOP_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the coop players limit of all the islands.' CHANGED_COOP_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the coop players limit of {0}.' CHANGED_CROP_GROWTH: '&e&lםיגורדש | &7החלצהב ןכדוע {0} לש יאה לש הלידגה סונוב.' CHANGED_CROP_GROWTH_ALL: '&e&lםיגורדש | &7החלצהב ןכדוע םייאה לכ לש הלידגה סונוב..' CHANGED_CROP_GROWTH_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לש הלידגה סונוב.' CHANGED_DISCORD: '&e&lיא | &7{0} ל החלצהב ןכדוע יאה לש דרוקסידה.' CHANGED_ENTITY_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for {1}''s island.' CHANGED_ENTITY_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for all the islands.' CHANGED_ENTITY_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of {0} entities for {1}.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for {1}''s island.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for all the islands.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of the island effect {0} for {1}.' CHANGED_ISLAND_SIZE: '&e&lםיגורדש | &7החלצהב ןכדוע {0} לש יאה לדוג.' CHANGED_ISLAND_SIZE_ALL: '&e&lUpgrades | &7Successfully updated the island size of all the islands.' CHANGED_ISLAND_SIZE_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לדוג.' CHANGED_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.' CHANGED_LANGUAGE: '&e&lהפש | &7תירבעל החלצהב התנוש ךלש הפשה.' CHANGED_MOB_DROPS: '&e&lםיגורדש | &7החלצהב ןכדוע {0} לש יאה לש םיבומ לש םיטירפה סונוב.' CHANGED_MOB_DROPS_ALL: '&e&lםיגורדש | &7החלצהב ןכדוע םייאה לכ לש םיבומ לש םיטירפה סונוב.' CHANGED_MOB_DROPS_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לש םיבומ לש םיטירפה סונוב.' CHANGED_NAME: '&e&lIsland | &7You changed your island''s name to {0}&7.' CHANGED_NAME_OTHER: '&e&lIsland | &7You changed the {0} island''s name to {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lIsland | &7You changed the name of {0}&7 to {1}&7.' CHANGED_PAYPAL: '&e&lיא | &7{0} ל החלצהב ןכדוע יאה לש לאפייפה.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.' CHANGED_ROLE_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}.' CHANGED_SPAWNER_RATES: '&e&lםיגורדש | &7החלצהב ןכדוע {0} לש יאה לש םירנואפסה לש רוגישה סונוב.' CHANGED_SPAWNER_RATES_ALL: '&e&lםיגורדש | &7החלצהב ןכדוע םייאה לכ לש םירנואפסה לש רוגישה סונוב.' CHANGED_SPAWNER_RATES_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לש םירנואפסה לש רוגישה סונוב.' CHANGED_TEAM_LIMIT: '&e&lםיגורדש | &7החלצהב הנכדוע {0} לש יאה לש הצובקה תלבגמ.' CHANGED_TEAM_LIMIT_ALL: '&e&lםיגורדש | &7החלצהב הנכדוע םייאה לכ לש הצובקה תלבגמ.' CHANGED_TEAM_LIMIT_NAME: '&e&lםיגורדש | &7החלצהב הנכדוע רמוע יאה לש הצובקה תלבגמ.' CHANGED_TELEPORT_LOCATION: '&e&lיא | &7החלצהב ןכדוע יאה לש רוגישה םוקמ.' CHANGED_WARPS_LIMIT: '&e&lםיגורדש | &7החלצהב הנכדוע {0} לש יאה לש םימוקימה תלבגמ.' CHANGED_WARPS_LIMIT_ALL: '&e&lםיגורדש | &7החלצהב הנכדוע םייאה לכ לש םימוקימה תלבגמ.' CHANGED_WARPS_LIMIT_NAME: '&e&lםיגורדש | &7החלצהב הנכדוע {0} יאה לש םימוקימה תלבגמ.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: תומכ COMMAND_ARGUMENT_BIOME: 'biome' COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'command...' COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: '...דרוקסיד' COMMAND_ARGUMENT_EFFECT: 'potion-effect' COMMAND_ARGUMENT_EMAIL: ליימיא COMMAND_ARGUMENT_ENTITY: entity COMMAND_ARGUMENT_ISLAND_NAME: יאה םש COMMAND_ARGUMENT_ISLAND_ROLE: הגרד COMMAND_ARGUMENT_LEADER: גיהנמ COMMAND_ARGUMENT_LEVEL: המר COMMAND_ARGUMENT_LIMIT: הלבגמ COMMAND_ARGUMENT_MATERIAL: רמוח COMMAND_ARGUMENT_MENU: 'menu-name' COMMAND_ARGUMENT_MESSAGE: '...העדוה' COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: המישמה םש COMMAND_ARGUMENT_MODULE_NAME: 'module-name' COMMAND_ARGUMENT_MULTIPLIER: סונוב COMMAND_ARGUMENT_NAME: םש COMMAND_ARGUMENT_NEW_LEADER: שדח גיהנמ COMMAND_ARGUMENT_PAGE: דומע COMMAND_ARGUMENT_PATH: 'path' COMMAND_ARGUMENT_PERMISSION: תושר COMMAND_ARGUMENT_PLAYER_NAME: ןקחשה םש COMMAND_ARGUMENT_PRIVATE: יטרפ COMMAND_ARGUMENT_RATING: גוריד COMMAND_ARGUMENT_ROWS: rows COMMAND_ARGUMENT_SCHEMATIC_NAME: הנבמה םש COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: תורדגה COMMAND_ARGUMENT_SIZE: לדוג COMMAND_ARGUMENT_TIME: ןמז COMMAND_ARGUMENT_TITLE_DURATION: 'duration' COMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in' COMMAND_ARGUMENT_TITLE_FADE_OUT: 'fade-out' COMMAND_ARGUMENT_UPGRADE_NAME: גורדשה םש COMMAND_ARGUMENT_VALUE: יווש COMMAND_ARGUMENT_WARP_NAME: םוקימה םש COMMAND_ARGUMENT_WARP_CATEGORY: 'warp-category' COMMAND_ARGUMENT_WORLD: 'world' COMMAND_COOLDOWN_FORMAT: '&c&lהאיגש | &7{0} ב הדוקפב בוש שמתשהל לוכי התא.' COMMAND_DESCRIPTION_ACCEPT: םינקחשמ יאל הנמזה רשאל. COMMAND_DESCRIPTION_ADMIN: .ןימדאה תודוקפב שמתשהל. COMMAND_DESCRIPTION_ADMIN_BONUS: יאל סונוב תתל. COMMAND_DESCRIPTION_ADMIN_ADD: 'Add a user to an island.' COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Increase block limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Add a bonus to a player.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Increase coop players limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Increase the crop growth multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Add an island effect for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Increase entity limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Add percentage of a material for the cobblestone generator.' COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Increase the mob drops multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expand another player''s island size.' COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Increase the spawner rates multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Increase members limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Increase the warps limit of an island.' COMMAND_DESCRIPTION_ADMIN_BYPASS: הפיקע בצמ ףילחהל. COMMAND_DESCRIPTION_ADMIN_CHEST: 'Open island''s chest of another island.' COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Clear generator rates for a specific island. COMMAND_DESCRIPTION_ADMIN_CLOSE: רוביצל יא רוגסל. COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Execute a command for all members of islands.' COMMAND_DESCRIPTION_ADMIN_COUNT: 'Check a block count on a specific island.' COMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.' COMMAND_DESCRIPTION_ADMIN_DEBUG: 'Toggle debug outputs.' COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Delete a warp for an island.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: רחא יאב ןקחש הגרדב דירוהל. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: רחא יא לש קנב לא ףסכ ריבעהל. COMMAND_DESCRIPTION_ADMIN_DISBAND: רחא ןקחש לש יא קוחמל. COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: ןקחשל םייא תוקיחמ תתל. COMMAND_DESCRIPTION_ADMIN_IGNORE: רתויב םיבוטה םייאה תמישרמ יא דירוהל. COMMAND_DESCRIPTION_ADMIN_JOIN: הנמזה אלל יאל סנכיהל. COMMAND_DESCRIPTION_ADMIN_KICK: 'Kick a player from his island.' COMMAND_DESCRIPTION_ADMIN_MODULES: 'Manage modules of the plugin.' COMMAND_DESCRIPTION_ADMIN_MISSION: ןקחש רובע המישמ לש סוטטס תונשל. COMMAND_DESCRIPTION_ADMIN_MSG: העדוה ןקחשל חולשל. COMMAND_DESCRIPTION_ADMIN_MSG_ALL: העדוה יא לש םינקחשה לכל חולשל. COMMAND_DESCRIPTION_ADMIN_NAME: יא לש םשה תא תונשל. COMMAND_DESCRIPTION_ADMIN_OPEN: רוביצל יא חותפל. COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Open a custom menu for a player.' COMMAND_DESCRIPTION_ADMIN_PROMOTE: רחא יאב ןקחש הגרדב תולעהל. COMMAND_DESCRIPTION_ADMIN_PURGE: .םייא תוקנל COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Rankup an upgrade for an island.' COMMAND_DESCRIPTION_ADMIN_RECALC: יא לש יווש שדחמ בשחל. COMMAND_DESCRIPTION_ADMIN_RELOAD: ןיגאלפה לש םיצבקה לכ תא שדחמ ןועטל. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: ןקחש ידי לע ונתנש םיגורידה לכ תא קוחמל. COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: ןיגאלפל שדח הנבמ רוציל. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Set the biome of an island.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Set the block amount in a specific location.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: רחא ןקחש לש יאל םיקולב לש הלבגה תונשל. COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Set the chest rows for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Set coop players limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: רחא ןקחש לש יא של הלידגה סונוב תא תונשל. COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: ןקחש לש תורתומה תוקיחמה תומכ תא תונשל. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Set the island effect level of another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Set entity limit for another player''s island. COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: רחא ןקחשל יא לע תוגיהנמה תא ריבעהל. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: רחא ןקחש לש יא לש םיבומ לש םיטירפה סונוב תא תונשל. COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: םייאה לכל תמייוסמ תושרל תרתומה הגרדה תא תונשל. COMMAND_DESCRIPTION_ADMIN_SET_RATE: יאל ןתנ ןקחשש גוריד תונשל. COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Set role limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: יאל הרדגה ףילחהל. COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: רוטרנ'גמ והשלכ רמוח לש זוחא תונשל. COMMAND_DESCRIPTION_ADMIN_SET_SIZE: ןקחש לש יא לש לדוג תונשל. COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Set the spawn location of the server. COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: רחא ןקחש לש יא לש םירנואפסה סונוב תא תונשל. COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: רחא ןקחש לש יא לש םינקחש תלבגה תונשל. COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: רחא ןקחש לש יא לש גורדש לש המרה תא תונשל. COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: רחא ןקחש לש יא לש םימוקימה תלבגה תא תונשל. COMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Open the plugin settings editor.' COMMAND_DESCRIPTION_ADMIN_SHOW: יא לע עדימ לבקל. COMMAND_DESCRIPTION_ADMIN_SPAWN: Teleport to the spawn location. COMMAND_DESCRIPTION_ADMIN_SPY: יומס טא'צ בצמ ףילחהל. COMMAND_DESCRIPTION_ADMIN_STATS: 'Show stats about the plugin.' COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sync upgrade values for an island.' COMMAND_DESCRIPTION_ADMIN_TELEPORT: רחא יא לא רגתשהל. COMMAND_DESCRIPTION_ADMIN_TITLE: 'Send a player a title.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Send to all island members a title.' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: םיבוטה םייאה תמישרל יא ריזחהל. COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: יאל םלוע חותפל. COMMAND_DESCRIPTION_ADMIN_WITHDRAW: רחא ןקחש לש יאמ ףסכ איצוהל. COMMAND_DESCRIPTION_BALANCE: 'Check the amount of money inside an island''s bank.' COMMAND_DESCRIPTION_BAN: ךלש יאהמ ןקחש קיחרהל. COMMAND_DESCRIPTION_BANK: 'Open the island''s bank.' COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: יאה לש םויבה תא ףילחהל. COMMAND_DESCRIPTION_BORDER: םייאה לש לובגה עבצ תא ףילחהל. COMMAND_DESCRIPTION_CHEST: 'Open the island''s chest.' COMMAND_DESCRIPTION_CLOSE: רוביצל יאה תא רוגסל. COMMAND_DESCRIPTION_COOP: יאה לש הלועפ ףתשמכ ןקחש ףיסוהל. COMMAND_DESCRIPTION_COOPS: 'Open the coops menu.' COMMAND_DESCRIPTION_COUNTS: 'See block counts in your island.' COMMAND_DESCRIPTION_CREATE: שדח יא רוציל. COMMAND_DESCRIPTION_DEL_WARP: יאב םוקימ קוחמל. COMMAND_DESCRIPTION_DEMOTE: יאב ןקחש הגרדב דירוהל. COMMAND_DESCRIPTION_DEPOSIT: יאה לש קנבל ךלש ןובשחהמ ףסכ דיקפהל. COMMAND_DESCRIPTION_DISBAND: תותימצל יאה תא קוחמל. COMMAND_DESCRIPTION_EXPEL: יאהמ רקבמ שרגל. COMMAND_DESCRIPTION_FLY: יאב הפועת בצמ ףילחהל. COMMAND_DESCRIPTION_HELP: תודוקפה לכ תמישר. COMMAND_DESCRIPTION_INVITE: ךלש יאה לא ןקחש ןימזהל. COMMAND_DESCRIPTION_KICK: יאהמ ןקחש ףיעהל. COMMAND_DESCRIPTION_LANG: ךלש הפשה תא ףילחהל. COMMAND_DESCRIPTION_LEAVE: יאה תא בוזעל. COMMAND_DESCRIPTION_MEMBERS: םינקחשה טירפת תא חותפל. COMMAND_DESCRIPTION_MISSION: המישמ םילשהל. COMMAND_DESCRIPTION_MISSIONS: תומישמה טירפת תא חותפל. COMMAND_DESCRIPTION_NAME: יאה םש תא תונשל. COMMAND_DESCRIPTION_OPEN: רוביצל יאה תא חותפל. COMMAND_DESCRIPTION_PANEL: יאה לש ישארה טירפתה תא חותפל. COMMAND_DESCRIPTION_PARDON: יאהמ ןקחש לש הקחרה דירוהל. COMMAND_DESCRIPTION_PERMISSIONS: יאב הגרד לש תואשרהב תופצל. COMMAND_DESCRIPTION_PROMOTE: יאב ןקחש הגרדב תולעהל. COMMAND_DESCRIPTION_RANKUP: גורדש המרב תולעהל. COMMAND_DESCRIPTION_RATE: יא גרדל. COMMAND_DESCRIPTION_RATINGS: יאה לש םיגורידה לכב תופצל. COMMAND_DESCRIPTION_SETTINGS: יאה לש תורדגהה טירפת תא חותפל. COMMAND_DESCRIPTION_RECALC: יאה יווש תא שדחמ בשחל. COMMAND_DESCRIPTION_SET_DISCORD: יאה לש דרוקסידה תא תונשל. COMMAND_DESCRIPTION_SET_PAYPAL: יאה לש לאפייפה תא תונשל. COMMAND_DESCRIPTION_SET_ROLE: יאב ןקחש לש הגרד תונשל. COMMAND_DESCRIPTION_SET_TELEPORT: יאה לש רוגישה םוקמ תא תונשל. COMMAND_DESCRIPTION_SET_WARP: יאב שדח םוקימ רוציל. COMMAND_DESCRIPTION_SHOW: יאה לע עדימ גיצהל. COMMAND_DESCRIPTION_TEAM: יאה לש םינקחשה לש עדימ גיצהל. COMMAND_DESCRIPTION_TEAM_CHAT: יתצובק טא'צ בצמ ףילחהל. COMMAND_DESCRIPTION_TELEPORT: יאה לא רגתשהל. COMMAND_DESCRIPTION_TOGGLE: םייא תולובגו םיקולב גוזימ יבצמ ףילחהל. COMMAND_DESCRIPTION_TOP: םיבוטה םייאה תמישר טירפת תא חותפל. COMMAND_DESCRIPTION_TRANSFER: יאה תוגיהנמ תא ריבעהל. COMMAND_DESCRIPTION_UNCOOP: יאה לש הלועפ ףתשמ תויהלמ ןקחש דירוהל. COMMAND_DESCRIPTION_UPGRADE: םיגורדשה טירפת תא חותפל. COMMAND_DESCRIPTION_VALUE: קולב לש יווש גיצהל. COMMAND_DESCRIPTION_VALUES: 'Open the values menu.' COMMAND_DESCRIPTION_VISIT: יאה לש םירקבמה תדוקנל רגתשהל. COMMAND_DESCRIPTION_VISITORS: םירקבמה טירפת תא חותפל. COMMAND_DESCRIPTION_WARP: יאב םוקימל רגתשהל. COMMAND_DESCRIPTION_WARPS: םימוקימה טירפת תא חותפל. COMMAND_DESCRIPTION_WITHDRAW: ךלש יטרפה ןובשחל יאה קנבמ ףסכ ךושמל. COMMAND_USAGE: '&cשומיש: /{0}' COOP_ANNOUNCEMENT: '&e&lיא | &7יאה לש הלועפ ףתשמכ {1} תא ףיסוה {0}.' COOP_BANNED_PLAYER: '&c&lהאיגש | &7הלועפ ףתשמכ ףסוותהל לוכי אלו יאהמ קחרומ הזה ןקחשה.' COOP_LIMIT_EXCEED: '&c&lError | &7You reached the maximum amount of coop players the island can have.' CREATE_ISLAND: '&e&lיא | &7היינשה תופילא {1} ךות {0} ב שדח יא תרצי.' CREATE_ISLAND_FAILURE: '&c&lError | &7An error occurred while creating your island. Please contact the administrator to investigate the issue.' CREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.' DEBUG_MODE_DISABLED: '&e&lDebug | &7Toggled debug mode &cOFF&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7Toggled debug mode &aON&7.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.' DELETE_WARP: '&e&lיא | &7{0} םוקימה תא תקחמ.' DELETE_WARP_SIGN_BROKE: '&7&o...רבשנ אוה ,טלש הזה םוקימל היה.' DEMOTE_LEADER: '&c&lError | &7You cannot demote island leaders.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lהאיגש | &7ךלשמ הכומנ הגרד ילעב םינקחש קר הגרדב דירוהל לוכי התא.' DEMOTED_MEMBER: '&e&lיא | &7ולש יאב {1} הגרדל {0} תא הגרדב תדרוה.' DEPOSIT_ANNOUNCEMENT: '&e&lקנב | &7יאה לש קנבה לא ${0} דיקפה רמוע!' DEPOSIT_ERROR: '&c&lError | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאל ץוחמ סורהל לוכי אל התא.' DISBAND_ANNOUNCEMENT: '&e&lיא | &7{0} ידי לע קחמנ ךלש יאה.' DISBAND_GIVE: '&e&lיא | &7תורתומ תוקיחמ {0} דוע תלביק.' DISBAND_GIVE_ALL: '&e&lיא | &7םינקחשה לכל תורתומ תוקיחמ {0} דוע תתנ.' DISBAND_GIVE_OTHER: '&e&lיא | &7{1} ל תורתומ תוקיחמ {0} דוע תתנ.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oYour island was disbanded and ${0} dollars were refunded to your account from the island bank' DISBAND_SET: '&e&lיא | &7{0} ל התנוש ךלש תורתומה תוקיחמה תומכ.' DISBAND_SET_ALL: '&e&lיא | &7{0} ל םינקחשה לכ לש תורתומה תוקיחמה תומכ תא תיניש.' DISBAND_SET_OTHER: '&e&lיא | &7{1} ל {0} לש תורתומה תוקיחמה תומכ תא תיניש.' DISBANDED_ISLAND: '&e&lיא | &7ךלש יאה תא תקחמ.' DISBANDED_ISLAND_OTHER: '&e&lיא | &7{0} לש יאה תא תקחמ.' DISBANDED_ISLAND_OTHER_NAME: '&e&lיא | &7{0} יאה תא תקחמ.' ENTER_PVP_ISLAND: '&7&oתוינש 10 כ ךשמב תוכמ לבקת אל התא .תוכמ וב תתל ןתינש יא לא תרגוש...' EXPELLED_PLAYER: '&e&lיא | &7יאה ןמ שרוג {0}.' FORMAT_QUAD: 'Q' FORMAT_TRILLION: 'T' FORMAT_BILLION: 'B' FORMAT_MILLION: 'M' FORMAT_THOUSANDS: 'K' FORMAT_SECONDS_NAME: תוינש FORMAT_SECOND_NAME: היינש FORMAT_MINUTES_NAME: תוקד FORMAT_MINUTE_NAME: הקד FORMAT_HOURS_NAME: תועש FORMAT_HOUR_NAME: העש FORMAT_DAYS_NAME: םימי FORMAT_DAY_NAME: םוי GENERATOR_CLEARED: '&e&lIsland | &7Successfully cleared the generator amounts for {0}''s island.' GENERATOR_CLEARED_NAME: '&e&lIsland | &7Successfully cleared the generator amounts for the island of {0}.' GENERATOR_CLEARED_ALL: '&e&lIsland | &7Successfully cleared the generator amounts for all the islands.' GENERATOR_UPDATED: '&e&lיא | &7החלצהב ןכדוע {1} לש יאה לש רוטארנגב {0} רמוחה לש תומכה.' GENERATOR_UPDATED_NAME: '&e&lיא | &7החלצהב ןכדוע {1} יאה לש רוטארנגב {0} רמוחה לש תומכה.' GENERATOR_UPDATED_ALL: '&e&lיא | &7החלצהב ןכדוע םייאה לכ לש רוטארנגב {0} רמוחה לש תומכה.' GLOBAL_COMMAND_EXECUTED: '&e&lIsland | &7Successfully executed the command on {0}''s island members!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lIsland | &7Successfully executed the command on the island members of {0}!' GLOBAL_MESSAGE_SENT: '&e&lיא | &7{0} לש יאה לש םינקחשל החלצהב החלשנ העדוהה!' GLOBAL_MESSAGE_SENT_NAME: '&e&lיא | &7{0} יאה לש םינקחשל החלצהב החלשנ העדוהה!' GLOBAL_TITLE_SENT: '&e&lIsland | &7Successfully sent to {0}''s island members the title!' GLOBAL_TITLE_SENT_NAME: '&e&lIsland | &7Successfully sent to the island members of {0} the title!' GOT_BANNED: '&e&lיא | &7רמוע לש יאה ןמ תקחרוה.' GOT_DEMOTED: '&e&lיא | &7ךלש יאב {0} תגרדל הגרדב תדרי.' GOT_EXPELLED: '&e&lיא | &7{0} ידי לע יאה ןמ תשרוג.' GOT_INVITE: '&e&lיא | &7ולש יאה לא ךתוא ןימזה {0}.' GOT_INVITE_TOOLTIP: '&7הנמזהה תא רשאל תנמ לע העדוהה לע ץחל.' GOT_KICKED: '&e&lיא | &7{0} ידי לע ךלש יאה ןמ תפעוה.' GOT_PROMOTED: '&e&lיא | &7ךלש יאב {0} תגרדל הגרדב תלעוה.' GOT_REVOKED: '&e&lיא | &7ולש יאל ךלש הנמזהה תא לטיב {0}.' GOT_UNBANNED: '&e&lיא | &7הדרי {0} לש יאהמ ךלש הקחרהה.' HIT_ISLAND_MEMBER: '&c&lהאיגש | &7ךלש יאהמ םינקחשל תוכמ תתל לוכי אל התא.' HIT_PLAYER_IN_ISLAND: '&c&lהאיגש | &7םייא ךותב םינקחשל תוכמ תתל לוכי אל התא.' IGNORED_ISLAND: '&e&lיא | &7םיבוטה םייאה תמישר ןמ דרי {0} לש יאה.' IGNORED_ISLAND_NAME: '&e&lיא | &7םיבוטה םייאה תמישר ןמ דרי {0} יאה.' INTERACT_OUTSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאל ץוחמ םירבד םע היצקרטניא עצבל לוכי אל התא.' INVALID_AMOUNT: '&c&lהאיגש | &7{0} תיקוח אל תומכ.' INVALID_BIOME: '&c&lError | &7Invalid biome {0}.' INVALID_BLOCK: '&c&lError | &7Invalid block location {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lError | &7Invalid effect {0}.' INVALID_ENTITY: '&c&lError | &7Invalid entity {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lהאיגש | &7יא ךל ןיא.' INVALID_ISLAND_LOCATION: '&c&lהאיגש | &7ךלש םוקימב יא ןיא.' INVALID_ISLAND_OTHER: '&c&lהאיגש | &7יא ןיא {0} ל.' INVALID_ISLAND_OTHER_NAME: '&c&lהאיגש | &7{0} םשה םע יא ןיא.' INVALID_ISLAND_PERMISSION: | &c&lהאיגש | &7{0} האשרהה תא אוצמל היה ןתינ אל. &c&lהאיגש | &7{1} :יאה תואשרה INVALID_LEVEL: '&c&lהאיגש | &7{0} תיקוח אל המר.' INVALID_LIMIT: '&c&lהאיגש | &7{0} תיקוח אל הלבגמ.' INVALID_MATERIAL: '&c&lהאיגש | &7{0} תיקוח אל רמוח.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lהאיגש | &7{0} תיקוח אל המישמ.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lהאיגש | &7{0} יקוח אל סונוב.' INVALID_PAGE: '&c&lError | &7Invalid page {0}.' INVALID_PERCENTAGE: '&c&lהאיגש | &7100 ל 0 ןיב תויהל בייח זוחא.' INVALID_PLAYER: '&c&lהאיגש | &7{0} םשה םע ןקחש אוצמל ןתינ אל.' INVALID_RATE: | &c&lהאיגש | &7{0} םשה םע גוריד אוצמל ןתינ אל. &c&lהאיגש | &7{0} :םיגוריד INVALID_ROWS: '&c&lError | &7Invalid amount of rows: {0}' INVALID_ROLE: | &c&lהאיגש | &7{0} הגרדה תא אוצמל היה ןתינ אל. &c&lהאיגש | &7{1} :תוגרד INVALID_SCHEMATIC: '&c&lהאיגש | &7{0} םשה םע הנבמ אוצמל היה ןתינ אל.' INVALID_SETTINGS: | &c&lהאיגש | &7{0} םשה םע תורדגה אוצמל ןתינ אל. &c&lהאיגש | &7{1} :תורדגה INVALID_SIZE: '&c&lהאיגש | &7{0} יקוח אל לדוג.' INVALID_SLOT: '&c&lError | &7Invalid slot {0}.' INVALID_TITLE: '&c&lError | &7Invalid title entered.' INVALID_TOGGLE_MODE: '&c&lהאיגש | &7{0} בצמ ףילחהל ןתינ אל.' INVALID_UPGRADE: | &c&lהאיגש | &7{0} םשה םע גורדש אוצמל היה ןתינ אל. &c&lהאיגש | &7{1} :םיגורדש INVALID_VISIT_LOCATION: '&c&lהאיגש | &7םירקבמ םוקמ ןיא הזה יאל.' INVALID_VISIT_LOCATION_BYPASS: '&7&oתאז לכב יאה לא ךתוא רגשמ ,לעפומ הפיקע בצמ...' INVALID_WARP: '&c&lהאיגש | &7{0} יקוח אל םוקימ.' INVALID_WORLD: '&c&lError | &7Invalid world {0}.' INVITE_ANNOUNCEMENT: '&e&lיא | &7יאה לא {1} תא ןימזה {0}.' INVITE_BANNED_PLAYER: '&c&lהאיגש | &7הנמזה לבקל לוכי אל ןכלו יאה ןמ קחרומ הזה ןקחשה.' INVITE_TO_FULL_ISLAND: '&c&lהאיגש | &7ךלש יאל םישנא דוע ןימזהל לוכי אל התא.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lהאיגש | &7םייק רבכ {0} םשה םע יא.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lקנב | &7קיר יאה קנב.' ISLAND_BANK_SHOW: '&e&lBank | &7Your island has ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBank | &7{0}''s island has ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBank | &7The island {0} has ${1}.' ISLAND_BEING_CALCULATED: '&c&lהאיגש | &7שדחמ בשוחמ יאהש ןמזב םיקולב תונשל לוכי אל התא!' ISLAND_CLOSED: '&e&lיא | &7החלצהב רוביצל רגסנ יאה.' ISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7You have an already ongoing island creation task.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lיא | &7ךתשקב תא דבעמ...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lהפועת | &7יטמוטוא הפועת בצמ &cקספוה&7.' ISLAND_FLY_ENABLED: '&e&lהפועת | &7יטמוטוא הפועת בצמ &aלעפוה&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lיא | &7&oןואפסה לא תרגוש ןכל ,קחמנש יא ךותב תייה...' ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lיא | &7&oןואפסל תרגוש ןכל ,םינקחש ןיב תוכמ ליעפהש יאב תייה...' ISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7ידי לע רצונ Ome_R' ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7תודוקפ תמישר [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7אבה דומעל רבעמל /is help {0} ץרה.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIsland | &7Bank Limit: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lיא | &7םיקולב תלבגה: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lיא | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIsland | &7Coop Limit: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lIsland | &7Island Effects: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lIsland | &7Entities Limits: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lיא | &7הלידג סונוב: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lיא | &7םיבוממ םיטירפ סונוב: {0}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lיא | &7רוטארנג ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lיא | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lIsland | &7Role Limits: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIsland | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lיא | &7לובגה לדוג: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lיא | &7םירנואפס סונוב: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lיא | &7הצובק תלבגה: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lיא | &7םיגורדש: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lיא | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIsland | &7Warps Limit: {0}' ISLAND_INFO_BANK: '&e&lיא | &7קנב: {0}' ISLAND_INFO_BONUS: '&e&lIsland | &7Worth Bonus: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lIsland | &7Level Bonus: {0}' ISLAND_INFO_CREATION_TIME: '&e&lIsland | &7Creation Time: {0}' ISLAND_INFO_DISCORD: '&e&lיא | &7דרוקסיד: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lיא | &7ןכדועש הנורחא םעפ: {0} ינפל' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lיא | &7ןכדועש הנורחא םעפ: &aליעפ עגרכ' ISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}' ISLAND_INFO_LOCATION: '&e&lיא | &7תיב: {0}' ISLAND_INFO_NAME: '&e&lיא | &7םש: {0}' ISLAND_INFO_OWNER: '&e&lיא | &7גיהנמ: {0}' ISLAND_INFO_PAYPAL: '&e&lיא | &7לאפייפ: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lיא | &7 - {0}' ISLAND_INFO_RATE: '&e&lיא | &7גוריד: {0} &7({1}/5) - םינוש םיגוריד {2}.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: ✦ ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lיא | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIsland | &7Visitors Count: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lיא | &7יווש: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lיא | &7החלצהב רוביצל חתפנ יאה.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you are no longer in preview mode.' ISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' ISLAND_PREVIEW_CANCEL_TEXT: 'CANCEL' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lPreview | &7You started the preview mode for the schematic {0}. &e&lPreview | &7Type &a&lCONFIRM &7to create a new island, or &c&lCANCEL &7to cancel the preview mode. &e&lPreview | &7You cannot leave the area of the island, otherwise the preview mode will be cancelled automatically. ISLAND_PROTECTED: '&c&lהאיגש | &7ןגומ הזה יאה.' ISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lיא | &7 לש יאה לש םינקחשה {0} &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(קתונמ)' ISLAND_TEAM_STATUS_ONLINE: '&a(רבוחמ)' ISLAND_TEAM_STATUS_ROLES: '&e&lיא | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(קתונמ)' ISLAND_TOP_STATUS_ONLINE: '&a(רבוחמ)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[יטרפ]' ISLAND_WAS_CLOSED: '&e&lיא | &7&oןואפסל תרגוש ןכלו ,רוביצל רגסנ וב תייהש יאה...' ISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.' ISLAND_WORTH_RESULT: '&e&lיא | &7אוה ךלש יאה יווש {0} [המר {1}]' ISLAND_WORTH_TIME_OUT: '&c&lError | &7The calculation task has timed out. Try again later...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lיא | &7ךלש יאה לא סנכנ {0}.' JOIN_ANNOUNCEMENT: '&e&lיא | &7ךלש יאה לא סנכנ {0}.' JOIN_FULL_ISLAND: '&c&lהאיגש | &7תרתומה םינקחשה תומכ תלבגמל עיגה יאה.' JOIN_WHILE_IN_ISLAND: '&c&lהאיגש | &7יאב אצמנ רבכ התא.' JOINED_ISLAND: '&e&lיא | &7{0} לש יאה לא תסנכנ.' JOINED_ISLAND_NAME: '&e&lיא | &7{0} יאה לא תסנכנ.' JOINED_ISLAND_AS_COOP: '&e&lיא | &7{0} לש יאל הלועפ ףתשמכ תסנכנ.' JOINED_ISLAND_AS_COOP_NAME: '&e&lיא | &7{0} יאל הלועפ ףתשמכ תסנכנ.' KICK_ANNOUNCEMENT: '&e&lיא | &7{1} ידי לע יאהמ ףעוה {0}.' KICK_ISLAND_LEADER: '&c&lError | &7You cannot kick the leader of the island, use /is admin disband instead.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lהאיגש | &7ךלשמ הכומנ רתוי הגרד ילעב קר םינקחש ףיעהל לוכי התא.' LACK_CHANGE_PERMISSION: '&c&lהאיגש | &7תורחא תוגרדל התוא תונשל תנמ לע האשרהה תא ךל היהיש בייח התא.' LAST_ROLE_DEMOTE: '&c&lהאיגש | &7הזה ןקחשה תא הגרדב דירוהל דוע לוכי אל התא.' LAST_ROLE_PROMOTE: '&c&lהאיגש | &7הזה ןקחשה תא הגרדב תולעהל דוע לוכי אל התא.' LEAVE_ANNOUNCEMENT: '&e&lיא | &7יאה תא בזע {0}.' LEAVE_ISLAND_AS_LEADER: |- &c&lהאיגש | &7ותוא גיהנמ התא רשאכ יאה תא בוזעל לוכי אל התא. &c&lהאיגש | &7/is transfer ידי לע יאה לע תוגיהנמה תא ריבעהל לוכי התא. LEFT_ISLAND: '&e&lיא | &7ךלש יאה תא תבזע.' LEFT_ISLAND_COOP: '&e&lיא | &7{0} לש יאה לש הלועפ ףתשמ אל התא.' LEFT_ISLAND_COOP_NAME: '&e&lיא | &7רמוע יאה לש הלועפ ףתשמ אל התא.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lהאיגש | &7חישק רמוח סינכהל ביוחמ התא.' MAXIMUM_LEVEL: '&c&lהאיגש | &7{0} איה גורדשה לש תילמיסקמה המרה.' MESSAGE_SENT: '&e&lיא | &7החלצהב {0} לא החלשנ העדוהה!' MISSION_CANNOT_COMPLETE: '&c&lהאיגש | &7ןיידע המישמה תא םילשהל לוכי אל התא.' MISSION_NO_AUTO_REWARD: '&e&lתומישמ | &7התוא םילשהל תנמ לע /is mission complete ץרה - {0} המישמה תא םילשהל תנמ לע םיכרצמה לכ תא ךל שי!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lהאיגש | &7וזה המישמה תא םילשמ התאש ינפל {0} המישמה תא םילשהל בייח התא.' MISSION_STATUS_COMPLETE: '&e&lתומישמ | &7{1} ןקחשל העצובל התנוש {0} המישמה לש סוטטסה.' MISSION_STATUS_COMPLETE_ALL: '&e&lMission | &7Changed the status of all the missions to completed for {0}.' MISSION_STATUS_RESET: '&e&lתומישמ | &7{1} ןקחשל הלחתוא {0} המישמה לש סוטטסה.' MISSION_STATUS_RESET_ALL: '&e&lMission | &7Reset the status of all the missions for {0}.' MODULE_ALREADY_INITIALIZED: '&e&lModule | &7This module is already loaded.' MODULE_INFO: | &e&lModule | &7{0} by {1} &e&lModule | &7&m-------------------- &e&lModule | &7{2} MODULE_LOADED_SUCCESS: '&e&lModule | &7Successfully loaded the module {0}.' MODULE_LOADED_FAILURE: '&e&lModule | &7Couldn''t load the module {0}. Check out the console for more information.' MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lIsland | &7{0} changed his island name to {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lהאיגש | &7הזה םשב שמתשהל לוכי אל התא.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lError | &7You cannot use player names as island names.' NAME_TOO_LONG: '&c&lהאיגש | &7םיוות {0} מ לעמ תויהל םילוכי אל םייא לש תומש.' NAME_TOO_SHORT: '&c&lהאיגש | &7םיוות {0} מ תוחפ תויהל םילוכי אל םייא לש תומש.' NO_BAN_PERMISSION: '&c&lהאיגש | &7םינקחש קיחרהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_CLOSE_BYPASS: '&c&lהאיגש | &7רוביצל חותפ אל הזה יאה.' NO_CLOSE_PERMISSION: '&c&lהאיגש | &7רוביצל יאה תא רוגסל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lהאיגש | &7הלועפ יפתשמכ םינקחש ףיסוהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_DELETE_WARP_PERMISSION: '&c&lהאיגש | &7םימוקימ קוחמל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_DEMOTE_PERMISSION: '&c&lהאיגש | &7המרב םינקחש דירוהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_DEPOSIT_PERMISSION: '&c&lהאיגש | &7יאה לש קנבב ףסכ דיקפהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_DISBAND_PERMISSION: '&c&lהאיגש | &7יאה תא קוחמל תנמ לע ןימדא תגרדב תוחפל תויהל בייח התא.' NO_EXPEL_PERMISSION: '&c&lהאיגש | &7יאהמ םירקבמ שרגל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_INVITE_PERMISSION: '&c&lהאיגש | &7םינקחש ןימזהל תנמ לע ןימדא תגרדב תוחפל תויהל בייח התא.' NO_ISLAND_CHEST_PERMISSION: '&c&lError | &7You must be at least {0} in order to access the island''s chest.' NO_ISLAND_INVITE: '&c&lהאיגש | &7הזה יאהמ תונמזה אוצמל ןתינ היה אל.' NO_ISLANDS_TO_PURGE: '&c&lהאיגש | &7יוקינל םייא םוש ואצמנ אל.' NO_KICK_PERMISSION: '&c&lהאיגש | &7םינקחש ףיעהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_MORE_DISBANDS: '&c&lהאיגש | &7םייא דוע קוחמל לוכי אל התא.' NO_MORE_WARPS: '&c&lהאיגש | &7ךלש יאל םימוקימ דוע רוציל ןתינ אל.' NO_NAME_PERMISSION: '&c&lהאיגש | &7ךלש יאה לש םשה תא תונשל לוכי אל התא.' NO_OPEN_PERMISSION: '&c&lהאיגש | &7רוביצל יאה תא חותפל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_PERMISSION_CHECK_PERMISSION: '&c&lהאיגש | &7תואשרה רובע עדימ לבקל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_PROMOTE_PERMISSION: '&c&lהאיגש | &7םינקחש הגרדב תולעהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_RANKUP_PERMISSION: '&c&lהאיגש | &7םיגורדש המרב תולעהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_RATINGS_PERMISSION: '&c&lהאיגש | &7םיגוריד קודבל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_SET_BIOME_PERMISSION: '&c&lהאיגש | &7יאה לש םויבה תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_SET_DISCORD_PERMISSION: '&c&lהאיגש | &7יאה לש דרוקסידה תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_SET_HOME_PERMISSION: '&c&lהאיגש | &7יאל רוגישה םוקימ תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_SET_PAYPAL_PERMISSION: '&c&lהאיגש | &7יאה לש לאפייפה תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_SET_ROLE_PERMISSION: '&c&lהאיגש | &7םינקחשל תוגרד תתל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_SET_SETTINGS_PERMISSION: '&c&lהאיגש | &7יאה לש תורדגהה תא תונשל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_SET_WARP_PERMISSION: '&c&lהאיגש | &7יאב םימוקימ רוציל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_TRANSFER_PERMISSION: '&c&lהאיגש | &7רחא ןקחשל תוגיהנמה תא ריבעהל תנמ לע יאה גיהנמ תויהל בייח התא.' NO_UNCOOP_PERMISSION: '&c&lהאיגש | &7יאה לש הלועפ יפתשמ תויהלמ םישנא דירוהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_UPGRADE_PERMISSION: '&c&lהאיגש | &7המר דועל גרדשל האשרהה ךל הרסח.' NO_WITHDRAW_PERMISSION: '&c&lהאיגש | &7יאה לש קנבהמ ףסכ ךושמל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lהאיגש | &7יאה לש קנבל רלוד {0} ריבעהל תנמ לע ףסכ קיפסמ ךל ןיא.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lהאיגש | &7ףסכ קיפסמ ךל ןיא.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lError | &7You don''t have enough money to use island warps.' OPEN_MENU_WHILE_SLEEPING: '&7&oYou''re too tired to interact with menus, don''t you think?' PANEL_TOGGLE_OFF: |- &e&lטירפת | &cתיביכ &יטמוטואה יאה טירפת בצמ תא7. &e&lטירפת | &7יאה לא םכתא חלשת /is תצרה. PANEL_TOGGLE_ON: |- &e&lטירפת | &aתקלדה &יטמוטואה יאה טירפת בצמ תא7. &e&lטירפת | &7יאה טירפת תא חתפת /is תצרה. PERMISSION_CHANGED: '&e&lיא | &7החלצהב {1} לש יאב {0} האשרהה תא תיניש.' PERMISSION_CHANGED_NAME: '&e&lיא | &7החלצהב {1} יאב {0} האשרהה תא תיניש.' PERMISSION_CHANGED_ALL: '&e&lיא | &7החלצהב םייאה לכב {0} האשרהה תא תיניש.' PERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.' PERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIsland | &7Successfully reset all the permissions for {0} to default values!' PERMISSIONS_RESET_ROLES: '&e&lIsland | &7Successfully reset all the permissions of the island to default values!' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Yes' PLAYER_ALREADY_BANNED: '&c&lהאיגש | &7יאהמ קחרומ רבכ הזה ןקחשה.' PLAYER_ALREADY_COOP: '&c&lהאיגש | &7יאה לש הלועפ ףתשמ רבכ הזה ןקחשה.' PLAYER_ALREADY_IN_ISLAND: '&c&lError | &7This player is already inside an island.' PLAYER_ALREADY_IN_ROLE: '&c&lהאיגש | &7{1} הגרדב אצמנ רבכ {0}.' PLAYER_EXPEL_BYPASS: '&c&lהאיגש | &7יאהמ שרוגמ תויהל לוכי אל הזה ןקחשה.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lיא | &7תרשה לא רבחתה {0}.' PLAYER_NOT_BANNED: '&c&lהאיגש | &7יאהמ קחרומ וניא הזה ןקחשה.' PLAYER_NOT_COOP: '&c&lהאיגש | &7יאה לש הלועפ ףתשמ וניא הזה ןקחשה.' PLAYER_NOT_INSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאה ךותב אצמנ אל הזה ןקחשה.' PLAYER_NOT_ONLINE: '&c&lהאיגש | &7רבוחמ אל הזה ןקחשה.' PLAYER_QUIT_ANNOUNCEMENT: '&e&lיא | &7תרשה תא בזע {0}.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lהאיגש | &7ךלשמ הכומנ הגרד ילעב םינקחש הגרד תולעהל קר לוכי התא.' PROMOTED_MEMBER: '&e&lיא | &7ולש יאב {1} תגרדל {0} תא הגרדב תלעה.' PURGE_CLEAR: '&e&lיא | &7המישרהמ וקחמנ ,תוקנתהל םיכירצ ויהש םייאה לכ.' PURGED_ISLANDS: |- &e&lיא | &7טרטסיר רובעי תרשה רשאכ וקנתי םייא {0}. &e&lיא | &7/is admin purge cancel הדוקפה תצרה ידי לע ןמז לכב תאז לטבל ןתינ. RANKUP_SUCCESS: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}''s island.' RANKUP_SUCCESS_ALL: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for all the islands.' RANKUP_SUCCESS_NAME: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lיא | &75 ךותמ {1} ךלש יאה תא גריד {0}!' RATE_CHANGE_OTHER: '&e&lיא | &7{1} ל {0} לש גורידה תא תיניש.' RATE_OWN_ISLAND: '&c&lהאיגש | &7ךלש יאה תא גרדל לוכי אל התא.' RATE_REMOVE_ALL: '&e&lיא | &7החלצהב {0} לש םיגורידה לכ תא תקחמ.' RATE_REMOVE_ALL_ISLANDS: '&e&lIsland | &7Successfully removed all ratings of all the islands.' RATE_SUCCESS: '&e&lיא | &7םיבכוכ {0} םע הזה יאה תא תגריד!' REACHED_BLOCK_LIMIT: '&e&lםיגורדש | &7{0} קולבה לש יאב םיקולבה תלבגמל תעגה.' REACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.' RECALC_ALREADY_RUNNING: '&c&lError | &7Your island is already being recalculated.' RECALC_ALREADY_RUNNING_OTHER: '&c&lError | &7This island is already being recalculated.' RECALC_ALL_ISLANDS: '&e&lיא | &7םייאה לכ לש יוושה תא שדחמ בשחמ...' RECALC_ALL_ISLANDS_DONE: '&e&lיא | &7החלצהב שדחמ ובשוח םייאה לכ.' RECALC_PROCCESS_REQUEST: '&e&lיא | &7ךתשקב תא דבעמ...' RELOAD_COMPLETED: '&e&lSuperiorSkyblock | &7החלצהב העצוב שדחמ הניעט!' RELOAD_PROCCESS_REQUEST: '&e&lSuperiorSkyblock | &7םיצבקה לכ תא שדחמ ןעוט...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lיא | &7יאה לא {1} לש הנמזהה תא לטיב {0}.' RESET_WORLD_SUCCEED: '&e&lIsland | &7Successfully reset the world {0} for {1}''s island.' RESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for all the islands.' RESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.' SAME_NAME_CHANGE: '&c&lהאיגש | &7ךלש יאה לש יוושכעה םשהמ רחא םש סינכהל ךירצ התא.' SCHEMATIC_LEFT_SELECT: '&e&lםינבמ רצוי | &7היינש הדוקנ תנמיס ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lהאיגש | &7תודוקנ ינש תרחב אל.' SCHEMATIC_PROCCESS_REQUEST: '&e&lםינבמ רצוי | &7ךתשקב תא דבעמ...' SCHEMATIC_READY_TO_CREATE: | &e&lםינבמ רצוי | &7שדח הנבמ רוציל תנמ לע Run /is admin schematic ץרה .תודוקנ יתש תרחב. &e&lםינבמ רצוי | &7הדוקפה תא ץירמ התא רשאכ רגתשהל םירומא וילא רוזאב דמוע התאש בל םיש. SCHEMATIC_RIGHT_SELECT: '&e&lםינבמ רצוי | &7הנושאר הדוקנ תנמיס ({0})' SCHEMATIC_SAVED: '&e&lםינבמ רצוי | &7החלצהב רמשנ הנבמה!' SELF_ROLE_CHANGE: '&c&lהאיגש | &7ךמצע לש הגרדה תא תונשל לוכי אל התא.' SET_UPGRADE_LEVEL: '&e&lםיגורדש | &7החלצהב התנוש {1} לש יאב {0} גורדשה לש המרה.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lםיגורדש | &7החלצהב התנוש {1} יאב {0} גורדשה לש המרה.' SET_WARP: '&e&lיא | &7{0} ב החלצהב שדח םוקימ תרצי.' SET_WARP_OUTSIDE: '&c&lהאיגש | &7ךלש יאל ץוחמ םימוקימ רוציל לוכי אל התא.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lיא | &7{1} לש יאב החלצהב הנכדוע {0} הרדגהה.' SETTINGS_UPDATED_NAME: '&e&lיא | &7{1} יאב החלצהב הנכדוע {0} הרדגהה.' SETTINGS_UPDATED_ALL: '&e&lיא | &7םייאה לכב החלצהב הנכדוע {0} הרדגהה.' SIZE_BIGGER_MAX: '&c&lError | &7You cannot set a size bigger than the max island size.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Successfully teleported {0} to spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Successfully updated the spawn location to {0}.' SPY_TEAM_CHAT_FORMAT: '&7[יומס] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lUpgrades | &7Successfully synced all upgrade values of {0}''s island.' SYNC_UPGRADES_ALL: '&e&lUpgrades | &7Successfully synced all upgrade values of all the islands.' SYNC_UPGRADES_NAME: '&e&lUpgrades | &7Successfully synced all upgrade values of {0}.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lהאיגש | &7ךלש יאב אצמנ אל התא.' TELEPORT_OUTSIDE_ISLAND: '&c&lError | &7You cannot teleport outside of your protection range.' TELEPORT_WARMUP: '&7&oזוזת לא {0}... ב רגושת התא!' TELEPORT_WARMUP_CANCEL: '&7&oלטוב רוגישה ןכלו תזז.' TITLE_SENT: '&e&lIsland | &7Successfully sent {0} the title!' TELEPORTED_FAILED: '&e&lיא | &7תרשה תווצל הנפת אנא .יאב חוטב םוקמ ןיא יכ הארנ.' TELEPORTED_SUCCESS: '&e&lיא | &7ךלש יאל תרגוש.' TELEPORTED_TO_WARP: '&e&lיא | &7החלצהב יאה םוקימל תרגוש.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIsland | &7The player {0} teleported to the island warp {1}.' TOGGLED_BYPASS_OFF: '&e&lהפיקע | &7הפיקעה בצמ תא &cתיביכ&7.' TOGGLED_BYPASS_ON: '&e&lהפיקע | &7הפיקעה בצמ תא &aתקלדה&7.' TOGGLED_FLY_OFF: '&e&lהפועת | &7תיטמוטואה הפועתה בצמ תא &cתיביכ&7.' TOGGLED_FLY_ON: '&e&lהפועת | &7תיטמוטואה הפועתה בצמ תא &aתקלדה&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lםינבמ רצוי | &7םינבמה תריצי בצמ תא &cתיביכ&7.' TOGGLED_SCHEMATIC_ON: |- &e&lםינבמ רצוי | &7םינבמה תריצי בצמ תא &aתקלדה&7. &e&lםינבמ רצוי | בהז ןזרג תרזעב רוזא ןמס. TOGGLED_SPY_OFF: '&e&lיומס | &7יומסה טא''צה בצמ תא &cתיביכ&7.' TOGGLED_SPY_ON: '&e&lיומס | &7יומסה טא''צה בצמ תא &aתקלדה&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lםיקולב גוזימ | &7םיקולב גוזימה בצמ תא &cתיביכ&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lםיקולב גוזימ | &7םיקולב גוזימה בצמ תא &aתקלדה&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lטא''צ | &7Toggling team chat &cOFF&7.' TOGGLED_TEAM_CHAT_ON: '&e&lטא''צ | &7Toggling team chat &aON&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lלובג | &7יתצובקה טא''צה בצמ תא &cתיביכ&7.' TOGGLED_WORLD_BORDER_ON: '&e&lלובג | &7יתצובקה טא''צה בצמ תא &aתקלדה&7.' TRANSFER_ADMIN: '&e&lיא | &7{1} לא {0} לש יאה תגהנה תא תרבעה.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lהאיגש | &7ולש יאה לש גיהנמה רבכ {0}.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lהאיגש | &7יאה ותואב אל הלאה םינקחשה.' TRANSFER_ADMIN_NOT_LEADER: '&c&lהאיגש | &7יא ףא גיהנמ אל הזה ןקחשה.' TRANSFER_ALREADY_LEADER: '&c&lהאיגש | &7הזה יאה לש גיהנמה רבכ התא.' TRANSFER_BROADCAST: '&e&lיא | &7{0} לא הרבע יאה תוגיהנמ.' UNBAN_ANNOUNCEMENT: '&e&lיא | &7{1} ידי לע הלטוב {0} לש הקחרהה.' UNCOOP_ANNOUNCEMENT: '&e&lיא | &7יאה לש הלועפ ףתשמכ {1} תא דירוה {0}.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lיא | &7דוע יאה לש הלועפ ףתשמ וניא ןכלו תרשה תא בזע {0}.' UNIGNORED_ISLAND: '&e&lיא | &7החלצהב םיבוטה םייאה תמישרל ףסוותה {0} לש יאה.' UNIGNORED_ISLAND_NAME: '&e&lיא | &7החלצהב םיבוטה םייאה תמישרל ףסוותה {0} יאה.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lיא | &7&oרחא םוקימ הסנ אנא .חוטב וניא םוקימה יכ הארנ.' UPDATED_PERMISSION: '&e&lיא | &7{0} ל תואשרהה ונכדוע.' UPDATED_SETTINGS: '&e&lיא | &7{0} תורדגהה ונכדוע.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lהאיגש | &7םירחא םייאב וזה הדוקפב שמתשהל לוכי אל התא.' WARP_ALREADY_EXIST: '&c&lהאיגש | &7הזה םשה םע םוקימ םייק רבכ.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lWarps | &7Enter a new lore (Type "-cancel" to cancel): &e&lWarps | &7You can separate lines by using "\n". WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type "-cancel" to cancel):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type "-cancel" to cancel):' WARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7Successfully updated the category''s icon.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lError | &7Warp category names cannot be empty.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.' WARP_CATEGORY_SLOT: '&e&lWarps | &7Enter a new slot (Type "-cancel" to cancel):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lError | &7This slot is already taken by another category.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7Successfully changed the category''s slot to {0}.' WARP_CATEGORY_RENAME: '&e&lWarps | &7Enter a new name (Type "-cancel" to cancel):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another category.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the category to {0}.' WARP_ICON_NEW_LORE: | &e&lWarps | &7Enter a new lore (Type "-cancel" to cancel): &e&lWarps | &7You can separate lines by using "\n". WARP_ICON_NEW_NAME: '&e&lWarps | &7Enter a name (Type "-cancel" to cancel):' WARP_ICON_NEW_TYPE: '&e&lWarps | &7Enter a new material type (Type "-cancel" to cancel):' WARP_ICON_UPDATED: '&e&lWarps | &7Successfully updated the warp''s icon.' WARP_ILLEGAL_NAME: '&c&lError | &7Warp names cannot be empty.' WARP_LOCATION_UPDATE: '&e&lWarps | &7Successfully updated the warp''s location to your location.' WARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.' WARP_PUBLIC_UPDATE: '&e&lWarps | &7Successfully opened the warp to the public.' WARP_PRIVATE_UPDATE: '&e&lWarps | &7Successfully closed the warp to the public.' WARP_RENAME: '&e&lWarps | &7Enter a new name (Type "-cancel" to cancel):' WARP_RENAME_ALREADY_EXIST: '&c&lError | &7This name is already taken by another warp.' WARP_RENAME_SUCCESS: '&e&lWarps | &7Successfully renamed the warp to {0}.' WITHDRAW_ALL_MONEY: |- &e&lקנב | &7וכותב םירלוד {0} קר שי יאה לש קנבב. &e&lקנב | &7&oףסכה לכ תא ךשומ... WITHDRAW_ANNOUNCEMENT: '&e&lקנב | &7יאה לש קנבהמ ${1} ךשמ {0}!' WITHDRAW_ERROR: '&c&lError | &7{0}.' WITHDRAWN_MONEY: '&e&lקנב | &7{1} לש יאה לש קנבהמ ${0} תכשמ!' WITHDRAWN_MONEY_NAME: '&e&lקנב | &7{1} יאה לש קנבהמ ${0} תכשמ!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lתומלוע | &7הזה יאב חותפ אל ןיידע {0} םלועה.' ================================================ FILE: src/main/resources/lang/pl-PL.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # You can find a tutorial about configuring messages here: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lWyspa | &7Pomyslnie dodano gracza {0} do wyspy {1}.' ADMIN_ADD_PLAYER_NAME: '&e&lWyspa | &7Pomyslnie dodano gracza {0} do wyspy {1}.' ADMIN_DEPOSIT_MONEY: '&e&lBank | &7Wplaciles {0}$ do banku wyspy {1}.' ADMIN_DEPOSIT_MONEY_NAME: '&e&lBank | &7Wplaciles ${0} na do wyspy {1}.' ADMIN_HELP_FOOTER: '&e&lSkyblock &7Opracowany przez Ome_R' ADMIN_HELP_HEADER: '&e&lSkyblock &7Lista poleceń administratora [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSkyblock &7Uzyj /is admin {0} na nastepnej stronie.' ALREADY_IN_ISLAND: '&c&lBlad | &7Jestes juz na wyspie.' ALREADY_IN_ISLAND_OTHER: '&c&lBlad | &7Ten gracz jest juz czlonkiem Twojej wyspy.' BAN_ANNOUNCEMENT: '&e&lWyspa | &7{0} zostal ZBANOWANY na wyspie przez {1}.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lBlad | &7Mozesz zbanowac tylko graczy z nizsza rola wyspy niz twoja.' BANK_DEPOSIT_CUSTOM: '&e&lBank | &7Wpisz kwote, która chcesz wplacic:' BANK_DEPOSIT_COMPLETED: 'Wplata zakończona' BANK_LIMIT_EXCEED: '&c&lBlad | &7Przekroczyles limit bankowy.' BANK_WITHDRAW_CUSTOM: '&e&lBank | &7Wpisz kwote, która chcesz wyplacic:' BANK_WITHDRAW_COMPLETED: 'Wyplata zakończona' BANNED_FROM_ISLAND: '&c&lBlad | &7Masz zakaz wstepu na te wyspe.' BLOCK_COUNT_CHECK: '&e&lWyspa | &7Ta wyspa ma x{0} {1}.' BLOCK_COUNTS_CHECK: '| &e&lWyspa | &7Ta wyspa ma nastepujace bloki: &7{0}' BLOCK_COUNTS_CHECK_EMPTY: '&e&lWyspa | &7Ta wyspa nie ma sledzonych bloków.' BLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}' BLOCK_LEVEL: '&e&lLevel | &7Poziom bloku {0} to {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7Blok {0} jest bezwartosciowy.' BLOCK_VALUE: '&e&lWartosc | &7Blok {0} o wartosci {1}.' BLOCK_VALUE_WORTHLESS: '&e&lWartosc | &7Blok {0} jest bezwartosciowy.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Niebieski' BORDER_PLAYER_COLOR_NAME_RED: 'Czerwony' BORDER_PLAYER_COLOR_NAME_GREEN: 'Zielony' BORDER_PLAYER_COLOR_UPDATED: '&e&lBariera | &7Pomyslnie zmieniono kolor bariery na {0}.' BUILD_OUTSIDE_ISLAND: '&c&lBlad | &7Nie mozesz budowac poza bariera.' CANNOT_SET_ROLE: '&c&lBlad | &7Nie mozesz ustawic roli gracza na {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lBlad | &7Mozesz zmienic uprawnienia tylko na nizsza role wyspy niz twoja.' CHANGED_BANK_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit banku wyspy {0}.' CHANGED_BANK_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit bankowy wszystkich wysp.' CHANGED_BANK_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit bankowy w wysokosci {0}.' CHANGED_BIOME: '&e&lWyspa | &7Pomyslnie zmieniono biom na {0}. Aby zobaczyc zmiany, moze byc konieczne ponowne polaczenie z serwerem.' CHANGED_BIOME_ALL: '&e&lWyspa | &7Pomyslnie zmieniono biom na {0} dla wszystkich wysp.' CHANGED_BIOME_NAME: '&e&lWyspa | &7Pomyslnie zmieniono biom na {0} dla wyspy {1}.' CHANGED_BIOME_OTHER: '&e&lWyspa | &7Pomyslnie zmieniono biom na {0} dla wyspy {1}.' CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Pomyslnie zmieniono wielkosc bloku z {0} na {1}.' CHANGED_BLOCK_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit bloków {0} wyspy {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} blokowania wszystkich wysp.' CHANGED_BLOCK_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit blokowania {0} {1}.' CHANGED_BONUS_LEVEL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu wyspy {0}.' CHANGED_BONUS_LEVEL_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu wszystkich wysp.' CHANGED_BONUS_LEVEL_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu {0}.' CHANGED_BONUS_WORTH: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci wyspy {0}.' CHANGED_BONUS_WORTH_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci wszystkich wysp.' CHANGED_BONUS_WORTH_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci {0}.' CHANGED_CHEST_SIZE: '&e&lKlatka | &7Pomyslnie zaktualizowano wiersze strony nr {0} na {1} dla wyspy {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lKlatka | &7Pomyslnie zaktualizowano wiersze na stronie nr {0} do {1} dla wszystkich wysp.' CHANGED_CHEST_SIZE_NAME: '&e&lSkrzynia | &7Pomyslnie zaktualizowano wiersze strony nr {0} do {1} dla {2}.' CHANGED_COOP_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit graczy w trybie wspólpracy na wyspie {0}.' CHANGED_COOP_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit graczy w trybie wspólpracy na wszystkich wyspach.' CHANGED_COOP_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit graczy w trybie wspólpracy wynoszacy {0}.' CHANGED_CROP_GROWTH: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wzrostu plonów wyspy {0}.' CHANGED_CROP_GROWTH_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wzrostu upraw na wszystkich wyspach.' CHANGED_CROP_GROWTH_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wzrostu plonów wynoszacy {0}.' CHANGED_DISCORD: '&e&lWyspa | &7Pomyslnie zmieniono niezgodnosc wyspy na {0}.' CHANGED_ENTITY_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} jednostek dla wyspy {1}.' CHANGED_ENTITY_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} jednostek dla wszystkich wysp.' CHANGED_ENTITY_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} jednostek dla {1}.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom efektu wyspy {0} dla wyspy {1}.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lAktualizacje | &7Sukces' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom efektu wyspowego {0} dla {1}.' CHANGED_ISLAND_SIZE: '&e&lAktualizacje | &7Pomyslnie zaktualizowano rozmiar wyspy {0}.' CHANGED_ISLAND_SIZE_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano rozmiar wszystkich wysp.' CHANGED_ISLAND_SIZE_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano rozmiar wyspy {0}.' CHANGED_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.' CHANGED_LANGUAGE: '&e&lJezyk | &7Pomyslnie zmieniono jezyk na angielski.' CHANGED_MOB_DROPS: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania mobów z wyspy {0}.' CHANGED_MOB_DROPS_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania z mobów na wszystkich wyspach.' CHANGED_MOB_DROPS_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania mobów wynoszacy {0}.' CHANGED_NAME: '&e&lWyspa | &7Zmieniles nazwe swojej wyspy na {0}&7.' CHANGED_NAME_OTHER: '&e&lWyspa | &7Zmieniles nazwe wyspy {0} na {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lWyspa | &7Zmieniles nazwe {0}&7 na {1}&7.' CHANGED_PAYPAL: '&e&lWyspa | &7Pomyslnie zmieniono paypal wyspy na {0}.' CHANGED_ROLE_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit roli {0} dla wyspy {1}.' CHANGED_ROLE_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit roli {0} dla wszystkich wysp.' CHANGED_ROLE_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit roli {0} dla {1}.' CHANGED_SPAWNER_RATES: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik liczby odradzajacych sie wyspy {0}.' CHANGED_SPAWNER_RATES_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik liczby pojawiajacych sie na wszystkich wyspach.' CHANGED_SPAWNER_RATES_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wspólczynników pojawiania sie {0}.' CHANGED_TEAM_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit zespolu wyspy {0}.' CHANGED_TEAM_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit druzyn na wszystkich wyspach.' CHANGED_TEAM_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit zespolu {0}.' CHANGED_TELEPORT_LOCATION: '&e&lWyspa | &7Pomyslnie zaktualizowano lokalizacje teleportu.' CHANGED_WARPS_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warpow wyspy {0}.' CHANGED_WARPS_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warp na wszystkich wyspach.' CHANGED_WARPS_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warpow {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'kwota' COMMAND_ARGUMENT_BIOME: 'biom' COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'polecenie...' COMMAND_ARGUMENT_DIMENSION: 'wymiar' COMMAND_ARGUMENT_DISCORD: 'niezgoda...' COMMAND_ARGUMENT_EFFECT: 'efekt mikstury' COMMAND_ARGUMENT_EMAIL: 'e-mail' COMMAND_ARGUMENT_ENTITY: 'podmiot' COMMAND_ARGUMENT_ISLAND_NAME: 'nazwa-wyspy' COMMAND_ARGUMENT_ISLAND_ROLE: 'rola-wyspy' COMMAND_ARGUMENT_LEADER: 'lider' COMMAND_ARGUMENT_LEVEL: 'poziom' COMMAND_ARGUMENT_LIMIT: 'limit' COMMAND_ARGUMENT_MATERIAL: 'material' COMMAND_ARGUMENT_MENU: 'nazwa-menu' COMMAND_ARGUMENT_MESSAGE: 'wiadomosc...' COMMAND_ARGUMENT_MISSION_CATEGORY: 'kategoria misji' COMMAND_ARGUMENT_MISSION_NAME: 'nazwa misji' COMMAND_ARGUMENT_MODULE_NAME: 'nazwa-modulu' COMMAND_ARGUMENT_MULTIPLIER: 'mnoznik' COMMAND_ARGUMENT_NAME: 'nazwa' COMMAND_ARGUMENT_NEW_LEADER: 'nowy lider' COMMAND_ARGUMENT_PAGE: 'strona' COMMAND_ARGUMENT_PATH: 'path' COMMAND_ARGUMENT_PERMISSION: 'uprawnienie' COMMAND_ARGUMENT_PLAYER_NAME: 'nazwa gracza' COMMAND_ARGUMENT_PRIVATE: 'prywatny' COMMAND_ARGUMENT_RATING: 'ocena' COMMAND_ARGUMENT_ROWS: 'wiersze' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'nazwa schematu' COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'ustawienia' COMMAND_ARGUMENT_SIZE: 'rozmiar' COMMAND_ARGUMENT_TIME: 'czas' COMMAND_ARGUMENT_TITLE_DURATION: 'czas trwania' COMMAND_ARGUMENT_TITLE_FADE_IN: 'zanikanie' COMMAND_ARGUMENT_TITLE_FADE_OUT: 'zanikanie' COMMAND_ARGUMENT_UPGRADE_NAME: 'nazwa uaktualnienia' COMMAND_ARGUMENT_VALUE: 'wartosc' COMMAND_ARGUMENT_WARP_NAME: 'nazwa wypaczenia' COMMAND_ARGUMENT_WARP_CATEGORY: 'kategoria wypaczenia' COMMAND_ARGUMENT_WORLD: 'swiat' COMMAND_COOLDOWN_FORMAT: '&c&lBlad | &7Mozesz uzywac tylko polecenia w {0}.' COMMAND_DESCRIPTION_ACCEPT: 'Zaakceptuj zaproszenie od gracza.' COMMAND_DESCRIPTION_ADMIN: 'Uzyj poleceń administratora.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Dodaj uzytkownika do wyspy.' COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Zwieksz limit banku dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Zwieksz limit bloków dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Dodaj bonus do gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Zwieksz limit graczy w trybie wspólpracy na wyspie innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Zwieksz mnoznik wzrostu plonów na wyspie innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Dodaj efekt wyspy dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Zwieksz limit jednostek dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Dodaj procent materialu do generatora kostki brukowej.' COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Zwieksz mnoznik dropów z mobów dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Zwieksz rozmiar wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Zwieksz mnoznik wspólczynników pojawiania sie na wyspie innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Zwieksz limit czlonków na wyspie innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Zwieksz limit wypaczeń wyspy.' COMMAND_DESCRIPTION_ADMIN_BONUS: 'Przyznaj graczowi bonus.' COMMAND_DESCRIPTION_ADMIN_BYPASS: 'Przelacz tryb obejscia.' COMMAND_DESCRIPTION_ADMIN_CHEST: 'Otwórz skrzynie innej wyspy na wyspie.' COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Wyczysc stawki generatora dla okreslonej wyspy.' COMMAND_DESCRIPTION_ADMIN_CLOSE: 'Zamknij wyspe dla publicznosci.' COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Wykonaj polecenie dla wszystkich czlonków wysp.' COMMAND_DESCRIPTION_ADMIN_COUNT: 'Sprawdz liczbe bloków na okreslonej wyspie.' COMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.' COMMAND_DESCRIPTION_ADMIN_DEBUG: 'Przelacz wyjscia debugowania.' COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Usuń warp dla wyspy.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Zdegraduj czlonka na wyspie innego gracza.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Wplac pieniadze do banku wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Rozwiaz wyspe innego gracza na stale.' COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Daj rozwiazania graczowi.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignoruj ​​wyspe z najlepszych wysp.' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Dolacz do wyspy bez zaproszenia.' COMMAND_DESCRIPTION_ADMIN_KICK: 'Wyrzuc gracza z jego wyspy.' COMMAND_DESCRIPTION_ADMIN_MODULES: 'Zarzadzaj modulami wtyczki.' COMMAND_DESCRIPTION_ADMIN_MISSION: 'Zmień status misji gracza.' COMMAND_DESCRIPTION_ADMIN_MSG: 'Wyslij graczowi wiadomosc bez zadnych prefiksów.' COMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Wyslij do wszystkich czlonków wyspy wiadomosc bez zadnych prefiksów.' COMMAND_DESCRIPTION_ADMIN_NAME: 'Zmień nazwe wyspy.' COMMAND_DESCRIPTION_ADMIN_OPEN: 'Otwórz wyspe dla publicznosci.' COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Otwórz niestandardowe menu gracza.' COMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Awansuj czlonka na wyspie innego gracza.' COMMAND_DESCRIPTION_ADMIN_PURGE: 'Oczysc wyspy.' COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Ranguj ulepszenie wyspy.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Ponownie oblicza wartosc wyspy.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Zaladuj ponownie wszystkie konfiguracje i zadania wtyczki.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Usuń limit bloków z wyspy.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Usun limit bytów z wyspy.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Usuń wszystkie oceny wystawione przez gracza.' COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Zresetuj wszystkie uprawnienia wyspy dla konkretnej wyspy.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Zresetuj wszystkie ustawienia wyspy dla konkretnej wyspy.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Zresetuj swiat dla wyspy.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Utwórz schematy dla wtyczki.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Ustaw limit banku dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Ustaw biom wyspy.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Ustaw kwote bloku w okreslonej lokalizacji.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Ustaw limit bloków dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Ustaw rzedy skrzyni dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Ustaw limit graczy w trybie wspólpracy na wyspie innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Ustaw mnoznik wzrostu plonów dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Ustaw ilosc rozwiazanych wysp dla gracza.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Ustaw level wyspy innego gracza' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Ustaw limit jednostek dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Ustaw lokalizacje podgladu dla wyspy.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Przenies wyspe komus innemu.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Ustaw mnoznik dropów mobów dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Ustaw wymagana role uprawnień dla wszystkich wysp.' COMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Ustaw ocene innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Ustaw limit ról dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Przelacz ustawienia dla okreslonej wyspy.' COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Zmień procent materialu generatora kostki brukowej.' COMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Zmień rozmiar wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Ustaw lokalizacje odradzania sie serwera.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Ustaw mnoznik wspólczynnika pojawiania sie dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Ustaw limit czlonków dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Ustaw poziom ulepszenia wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Ustaw limit warpow wyspy.' COMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Otwórz edytor ustawień wtyczki.' COMMAND_DESCRIPTION_ADMIN_SHOW: 'Uzyskaj informacje o wyspie.' COMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teleportuj sie do miejsca odrodzenia.' COMMAND_DESCRIPTION_ADMIN_SPY: 'Przelacz tryb szpiegowania czatu' COMMAND_DESCRIPTION_ADMIN_STATS: 'Pokaz statystyki dotyczace wtyczki.' COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Synchronizuj wartosci aktualizacji dla wyspy.' COMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teleportuj sie na inne wyspy.' COMMAND_DESCRIPTION_ADMIN_TITLE: 'Wyslij graczowi tytul.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Wyslij tytul do wszystkich czlonków wyspy.' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Zignoruj ​​wyspe z najlepszych wysp.' COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Odblokuj swiat dla wyspy.' COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Wyplac pieniadze z banku wyspy innego gracza.' COMMAND_DESCRIPTION_BALANCE: 'Sprawdz ilosc pieniedzy w banku wyspy.' COMMAND_DESCRIPTION_BAN: 'Zablokuj gracza na swojej wyspie.' COMMAND_DESCRIPTION_BANK: 'Otwórz bank wyspy.' COMMAND_DESCRIPTION_BANS: 'Otwórz menu banów.' COMMAND_DESCRIPTION_BIOME: 'Zmień biom wyspy.' COMMAND_DESCRIPTION_BORDER: 'Zmień kolor bariery wysp.' COMMAND_DESCRIPTION_CHEST: 'Otwórz skrzynie wyspy.' COMMAND_DESCRIPTION_CLOSE: 'Zamknij wyspe dla graczy.' COMMAND_DESCRIPTION_COOP: 'Dodaj gracza w trybie wspólpracy na swojej wyspie.' COMMAND_DESCRIPTION_COOPS: 'Otwórz menu wspólpracy.' COMMAND_DESCRIPTION_COUNTS: 'Zobacz liczbe bloków na swojej wyspie.' COMMAND_DESCRIPTION_CREATE: 'Utwórz nowa wyspe.' COMMAND_DESCRIPTION_DEL_WARP: 'Usuń warp wyspy.' COMMAND_DESCRIPTION_DEMOTE: 'Zdegraduj czlonka na swojej wyspie.' COMMAND_DESCRIPTION_DEPOSIT: 'Wplac pieniadze ze swojego konta osobistego do banku wyspy.' COMMAND_DESCRIPTION_DISBAND: 'Rozwiaz swoja wyspe na stale.' COMMAND_DESCRIPTION_EXPEL: 'Wyrzuc goscia ze swojej wyspy.' COMMAND_DESCRIPTION_FLY: 'Przelacz lot na wyspe.' COMMAND_DESCRIPTION_HELP: 'Lista wszystkich poleceń.' COMMAND_DESCRIPTION_INVITE: 'Zapros gracza na swoja wyspe.' COMMAND_DESCRIPTION_KICK: 'Wyrzuc gracza ze swojej wyspy.' COMMAND_DESCRIPTION_LANG: 'Zmień swój osobisty jezyk.' COMMAND_DESCRIPTION_LEAVE: 'Opusc swoja wyspe.' COMMAND_DESCRIPTION_MEMBERS: 'Otwórz menu czlonków.' COMMAND_DESCRIPTION_MISSION: 'Ukończ misje.' COMMAND_DESCRIPTION_MISSIONS: 'Otwórz menu misji.' COMMAND_DESCRIPTION_NAME: 'Zmień nazwe swojej wyspy.' COMMAND_DESCRIPTION_OPEN: 'Otwórz wyspe dla graczy.' COMMAND_DESCRIPTION_PANEL: 'Otwórz panel wyspy.' COMMAND_DESCRIPTION_PARDON: 'Odbanuj gracza na swojej wyspie.' COMMAND_DESCRIPTION_PERMISSIONS: 'Uzyskaj wszystkie uprawnienia dla roli wyspy.' COMMAND_DESCRIPTION_PROMOTE: 'Awansuj czlonka na swojej wyspie.' COMMAND_DESCRIPTION_RANKUP: 'Popraw uaktualnienie na wyzszym poziomie.' COMMAND_DESCRIPTION_RATE: 'Oceń wyspe.' COMMAND_DESCRIPTION_RATINGS: 'Pokaz wszystkie oceny wysp.' COMMAND_DESCRIPTION_SETTINGS: 'Otwórz menu ustawień.' COMMAND_DESCRIPTION_RECALC: 'Ponownie oblicza wartosc wyspy.' COMMAND_DESCRIPTION_SET_DISCORD: 'Ustaw niezgode na wyspie dla wyplat na wyspie.' COMMAND_DESCRIPTION_SET_PAYPAL: 'Ustaw adres e-mail PayPal wyspy dla wyplat na wyspie.' COMMAND_DESCRIPTION_SET_ROLE: 'Zmień role gracza na swojej wyspie.' COMMAND_DESCRIPTION_SET_TELEPORT: 'Zmień lokalizacje teleportacji swojej wyspy.' COMMAND_DESCRIPTION_SET_WARP: 'Utwórz nowa wyspe warp.' COMMAND_DESCRIPTION_SHOW: 'Uzyskaj informacje o wyspie.' COMMAND_DESCRIPTION_TEAM: 'Uzyskaj informacje o czlonkach wyspy' COMMAND_DESCRIPTION_TEAM_CHAT: 'Wlacz/wylacz czat wyspy.' COMMAND_DESCRIPTION_TELEPORT: 'Teleportuj na wyspe.' COMMAND_DESCRIPTION_TOGGLE: 'Wlacz/wylacz granice wyspy i stakowanie sie bloków.' COMMAND_DESCRIPTION_TOP: 'Otwórz menu najlepszych wysp.' COMMAND_DESCRIPTION_TRANSFER: 'Zmień lidera wyspy.' COMMAND_DESCRIPTION_UNCOOP: 'Usuń co-op graczowi na twojej wyspie.' COMMAND_DESCRIPTION_UPGRADE: 'Otwórz menu ulepszeń.' COMMAND_DESCRIPTION_VALUE: 'Pokaz wartosc bloku.' COMMAND_DESCRIPTION_VALUES: 'Otwórz menu wartosci bloków.' COMMAND_DESCRIPTION_VISIT: 'Teleportuj w miejsce spawnu odwiedzajacych na wyspie.' COMMAND_DESCRIPTION_VISITORS: 'Otwórz menu odwiedzajacych.' COMMAND_DESCRIPTION_WARP: 'Teleportuj na warp wyspy.' COMMAND_DESCRIPTION_WARPS: 'Otwórz menu warpów.' COMMAND_DESCRIPTION_WITHDRAW: 'Wyplac pieniadze z banku wyspy na twoje konto.' COMMAND_USAGE: '&cUzycie: /{0}' COOP_ANNOUNCEMENT: '&e&lWyspa | &7{0} dodal {1} jako czlonka co-op.' COOP_BANNED_PLAYER: '&c&lBlad | &7Ten gracz jest zablokowany na wyspie i nie moze zostac czlonkiem co-op.' COOP_LIMIT_EXCEED: '&c&lBlad | &7Osiagnales maksymalna liczbe czlonków co-op na wyspie.' CREATE_ISLAND: '&e&lWyspa | &7Stworzono wyspe na {0} w {1}ms.' CREATE_ISLAND_FAILURE: '&c&lBlad | &7Wystapil blad ze stworzeniem wyspy. Skontaktuj sie z administracja.' CREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.' DEBUG_MODE_DISABLED: '&e&lDebug | &7Tryb debug mode &cWylaczony&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7Tryb debug mode &aWlaczony&7.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.' DELETE_WARP: '&e&lWyspa | &7Usunales warp {0}.' DELETE_WARP_SIGN_BROKE: '&7&oWarp nie istnieje...' DEMOTE_LEADER: '&c&lBlad | &7Nie mozesz zmienic lidera wyspy.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lBlad | &7Mozesz zmniejszyc range tylko osobom nizej od ciebie.' DEMOTED_MEMBER: '&e&lWyspa | &7Zmniejszyles range {0} do {1} na wyspie.' DEPOSIT_ANNOUNCEMENT: '&e&lBank | &7{0} wplacil ${1} do banku wyspy!' DEPOSIT_ERROR: '&c&lBlad | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lBlad | &7Nie mozesz niszczyc poza zasiegiem ochrony.' DISBAND_ANNOUNCEMENT: '&e&lWyspa | &7Twoja wyspa zostala rozwiazana przez {0}.' DISBAND_GIVE: '&e&lWyspa | &7Otrzymales {0} rozwiazania.' DISBAND_GIVE_ALL: '&e&lWyspa | &7Dales {0} rozwiazanych wszystkim graczom.' DISBAND_GIVE_OTHER: '&e&lWyspa | &7Dales {0} rozwiazania dla {1}.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oTwoja wyspa zostala rozwiazana, a na Twoje konto zwrócono {0}$$ z banku wyspy' DISBAND_SET: '&e&lWyspa | &7Liczba rozlaczeń zostala ustawiona na {0}.' DISBAND_SET_ALL: '&e&lWyspa | &7Ustawiles licznik likwidacji wszystkich graczy na {0}.' DISBAND_SET_OTHER: '&e&lWyspa | &7Ustawiles liczbe rozlaczeń uzytkownika {0} na {1}.' DISBANDED_ISLAND: '&e&lWyspa | &7 Zlikwidowales swoja wyspe.' DISBANDED_ISLAND_OTHER: '&e&lWyspa | &7Usunales wyspe uzytkownika {0}.' DISBANDED_ISLAND_OTHER_NAME: '&e&lWyspa | &7Usunales wyspe {0}.' ENTER_PVP_ISLAND: '&7&oZostales przeteleportowany na wyspe z wlaczonym PVP. Jestes odporny na PvP przez nastepne 10 sekund...' EXPELLED_PLAYER: '&e&lWyspa | &7{0} zostal wydalony z wyspy.' FORMAT_QUAD: 'P' FORMAT_TRILLION: 'T' FORMAT_BILLION: 'B' FORMAT_MILLION: 'M' FORMAT_THOUSANDS: 'K' FORMAT_SECONDS_NAME: 'sekundy' FORMAT_SECOND_NAME: 'druga' FORMAT_MINUTES_NAME: 'minuty' FORMAT_MINUTE_NAME: 'minuta' FORMAT_HOURS_NAME: 'godziny' FORMAT_HOUR_NAME: 'godzina' FORMAT_DAYS_NAME: 'dni' FORMAT_DAY_NAME: 'dzień' GENERATOR_CLEARED: '&e&lWyspa | &7Pomyslnie wyczyszczono kwoty generatora dla wyspy {0}.' GENERATOR_CLEARED_NAME: '&e&lWyspa | &7Pomyslnie wyczyszczono kwoty generatora dla wyspy {0}.' GENERATOR_CLEARED_ALL: '&e&lWyspa | &7Pomyslnie wyczyszczono kwoty generatorów dla wszystkich wysp.' GENERATOR_UPDATED: '&e&lWyspa | &7Pomyslnie zaktualizowano liczbe generatorów {0} na wyspe {1}.' GENERATOR_UPDATED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano liczbe generatorów {0} na wyspe {1}.' GENERATOR_UPDATED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano liczbe generatorów {0} dla wszystkich wysp.' GLOBAL_COMMAND_EXECUTED: '&e&lWyspa | &7Pomyslnie wykonano polecenie na czlonkach wyspy {0}!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lWyspa | &7Pomyslnie wykonano polecenie na elementach wyspy {0}!' GLOBAL_MESSAGE_SENT: '&e&lWyspa | &7Pomyslnie wyslano wiadomosc do czlonków wyspy {0}!' GLOBAL_MESSAGE_SENT_NAME: '&e&lWyspa | &7Pomyslnie wyslano do czlonków wyspy {0} wiadomosc!' GLOBAL_TITLE_SENT: '&e&lWyspa | &7Pomyslnie wyslano tytul do czlonków wyspy {0}!' GLOBAL_TITLE_SENT_NAME: '&e&lWyspa | &7Pomyslnie wyslano do czlonków wyspy {0} tytul!' GOT_BANNED: '&e&lWyspa | &7Zostales ZABRONIONY z wyspy uzytkownika {0}.' GOT_DEMOTED: '&e&lWyspa | &7Zostales zdegradowany do {0} na swojej wyspie.' GOT_EXPELLED: '&e&lWyspa | &7&oZostales wydalony z wyspy przez {0}.' GOT_INVITE: '&e&lWyspa | &7{0} zaprosil cie na swoja wyspe.' GOT_INVITE_TOOLTIP: '&7Kliknij wiadomosc, aby zaakceptowac zaproszenie.' GOT_KICKED: '&e&lWyspa | &7Zostales wyrzucony z wyspy przez {0}.' GOT_PROMOTED: '&e&lWyspa | &7Zostales awansowany na {0} na swojej wyspie.' GOT_REVOKED: '&e&lWyspa | &7{0} odwolal Twoje zaproszenie na swoja wyspe.' GOT_UNBANNED: '&e&lWyspa | &7Zostales ODBANOWANY z wyspy uzytkownika {0}.' HIT_ISLAND_MEMBER: '&c&lBlad | &7Nie mozesz uderzyc czlonków swojej wyspy.' HIT_PLAYER_IN_ISLAND: '&c&lBlad | &7Nie mozesz uderzac graczy na wyspach.' IGNORED_ISLAND: '&e&lWyspa | Wyspa &7{0} jest teraz ignorowana z najlepszych wysp.' IGNORED_ISLAND_NAME: '&e&lWyspa | &7Wyspa {0} jest teraz ignorowana z najlepszych wysp.' INTERACT_OUTSIDE_ISLAND: '&c&lBlad | &7Nie mozesz wchodzic w interakcje poza zasiegiem ochrony.' INVALID_AMOUNT: '&c&lBlad | &7Nieprawidlowa kwota {0}.' INVALID_BIOME: '&c&lBlad | &7Nieprawidlowy biom {0}.' INVALID_BLOCK: '&c&lBlad | &7Nieprawidlowa lokalizacja bloku {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_COMMAND: '&c&lBlad | &7Nieprawidlowa komenda {0}.' INVALID_EFFECT: '&c&lBlad | &7Nieprawidlowy efekt {0}.' INVALID_ENTITY: '&c&lBlad | &7Nieprawidlowa jednostka {0}.' INVALID_ENVIRONMENT: '&c&lBlad | &7Nieprawidlowy wymiar {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lBlad | &7Nie masz wyspy.' INVALID_ISLAND_LOCATION: '&c&lBlad | &7W Twojej lokalizacji nie ma wyspy.' INVALID_ISLAND_OTHER: '&c&lBlad | &7{0} nie ma wyspy.' INVALID_ISLAND_OTHER_NAME: '&c&lBlad | &7Nie ma wyspy o nazwie {0}.' INVALID_ISLAND_PERMISSION: | &c&lBlad | &7Nie mozna znalezc uprawnienia wyspy {0}. &c&lBlad | &7Uprawnienia na wyspie: {1} INVALID_LEVEL: '&c&lBlad | &7Nieprawidlowy poziom {0}.' INVALID_LIMIT: '&c&lBlad | &7Nieprawidlowy limit {0}.' INVALID_MATERIAL: '&c&lBlad | &7Nieprawidlowy material {0}.' INVALID_MATERIAL_DATA: '&c&lBlad | &7Nieprawidlowe dane materialu {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lBlad | &7Nieprawidlowa misja {0}.' INVALID_MISSION_CATEGORY: '&c&lBlad | &7Nieprawidlowa kategoria misji {0}.' INVALID_MODULE: '&c&lBlad | &7Nieprawidlowy modul {0}.' INVALID_MULTIPLIER: '&c&lBlad | &7Nieprawidlowy mnoznik {0}.' INVALID_PAGE: '&c&lBlad | &7Nieprawidlowa strona {0}.' INVALID_PERCENTAGE: '&c&lBlad | &7Procent musi zawierac sie w przedziale od 0 do 100.' INVALID_PLAYER: '&c&lBlad | &7Nie mozna znalezc gracza o nazwie {0}' INVALID_RATE: | &c&lBlad | &7Nie udalo sie znalezc oceny o nazwie {0}. &c&lBlad | &7Oceny wysp: {1} INVALID_ROWS: '&c&lBlad | &7Nieprawidlowa liczba wierszy: {0}' INVALID_ROLE: | &c&lBlad | &7Nie mozna znalezc roli wyspy {0}. &c&lBlad | &7Role na wyspie: {1} INVALID_SCHEMATIC: '&c&lBlad | &7Nie mozna znalezc schematu o nazwie {0}.' INVALID_SETTINGS: | &c&lBlad | &7Nie mozna znalezc ustawień wyspy {0}. &c&lBlad | &7Ustawienia wyspy: {1} INVALID_SIZE: '&c&lBlad | &7Nieprawidlowy rozmiar {0}.' INVALID_SLOT: '&c&lBlad | &7Nieprawidlowy przedzial {0}.' INVALID_TITLE: '&c&lBlad | &7Wprowadzono nieprawidlowy tytul.' INVALID_TOGGLE_MODE: '&c&lBlad | &7Nie mozna przelaczyc {0}.' INVALID_UPGRADE: | &c&lBlad | &7Nie mozna znalezc uaktualnienia o nazwie {0}. &c&lBlad | &7Aktualizacje: {1} INVALID_VISIT_LOCATION: '&c&lBlad | &7Ta wyspa nie ma lokalizacji odwiedzajacych.' INVALID_VISIT_LOCATION_BYPASS: '&7&oMasz tryb obejscia, teleportujesz cie na wyspe...' INVALID_WARP: '&c&lBlad | &7Nieprawidlowe wypaczenie {0}.' INVALID_WORLD: '&c&lBlad | &7Nieprawidlowy swiat {0}.' INVITE_ANNOUNCEMENT: '&e&lWyspa | &7{0} zaprosil {1} na wyspe.' INVITE_BANNED_PLAYER: '&c&lBlad | &7Ten gracz ma zakaz wstepu na wyspe i nie moze zostac zaproszony.' INVITE_TO_FULL_ISLAND: '&c&lBlad | &7Nie mozesz zaprosic wiecej czlonków na swoja wyspe.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lBlad | &7Wyspa o tej nazwie juz istnieje.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBank | &7Bank na wyspie jest pusty.' ISLAND_BANK_SHOW: '&e&lBank | &7Twoja wyspa ma {0}$.' ISLAND_BANK_SHOW_OTHER: '&e&lBank | Wyspa &7{0} ma {1}$.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBank | &7Wyspa {0} ma {1}$.' ISLAND_BEING_CALCULATED: '&c&lBlad | &7Nie mozesz wchodzic w interakcje z blokami podczas przeliczania wyspy!' ISLAND_CLOSED: '&e&lWyspa | &7Pomyslnie zamknelismy wyspe dla publicznosci.' ISLAND_CREATE_PROCESS_FAIL: '&c&lBlad | &7Masz juz trwajace zadanie tworzenia wyspy.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lWyspa | &7Przetwarzanie zadania...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lFly | &7Mucha na wyspe zostala automatycznie &cwylaczona&7.' ISLAND_FLY_ENABLED: '&e&lFly | &7Lot na wyspe zostal automatycznie &wlaczony&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lWyspa | &7&oByles na wyspie, która zostala rozwiazana, wiec zostales przeteleportowany z powrotem na miejsce odrodzenia...' ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lWyspa | &7&oByles na wyspie, na której wlaczono PvP, wiec zostales przeteleportowany z powrotem na miejsce odrodzenia...' ISLAND_HELP_FOOTER: '&e&lSkyblock &7Opracowany przez Ome_R' ISLAND_HELP_HEADER: '&e&lSkyblock &7Lista poleceń [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Uzyj /is help {0} na nastepnej stronie.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lWyspa | &7Limit banku: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lWyspa | &7 Limity bloków: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lWyspa | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lWyspa | &7Limit wspólpracy: {0}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lWyspa | &7Mnoznik upraw: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lWyspa | &7Mnoznik zrzutów: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lWyspa | &7Efekty wyspy: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lWyspa | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lWyspa | &7 Limity jednostek: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lWyspa | &7 {0}: {1}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lWyspa | &7Ceny generatora ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lWyspa | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lWyspa | &7 Limity ról: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lWyspa | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lWyspa | &7Rozmiar obramowania: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lWyspa | &7Mnoznik spawnerów: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lWyspa | &7Limit zespolu: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lWyspa | &7Aktualizacje: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lWyspa | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lWyspa | &7Limit wypaczeń: {0}' ISLAND_INFO_BANK: '&e&lWyspa | &7Bank: {0}' ISLAND_INFO_BONUS: '&e&lWyspa | &7Warta premia: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lWyspa | &7 Premia za poziom: {0}' ISLAND_INFO_CREATION_TIME: '&e&lWyspa | &7Czas utworzenia: {0}' ISLAND_INFO_DISCORD: '&e&lWyspa | &7Niezgodnosc: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lWyspa | &7Ostatnia aktualizacja: {0} temu' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lWyspa | &7Ostatnia aktualizacja: &aObecnie aktywny' ISLAND_INFO_LEVEL: '&e&lIsland | &7Level: {0}' ISLAND_INFO_LOCATION: '&e&lWyspa | &7Strona glówna: {0}' ISLAND_INFO_NAME: '&e&lWyspa | &7Nazwa: {0}' ISLAND_INFO_OWNER: '&e&lWyspa | &7Lider: {0}' ISLAND_INFO_PAYPAL: '&e&lWyspa | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lWyspa | &7 - {0}' ISLAND_INFO_RATE: '&e&lWyspa | &7Ocena: {0} &7({1}/5) - {2} lacznych ocen.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: '✦' ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lWyspa | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lWyspa | &7Odwiedzajacy: {0} ({1} unikalnych odwiedzajacych)' ISLAND_INFO_WORTH: '&e&lWyspa | &7Wartosc: {0}' ISLAND_NAME_NONE: Brak ISLAND_OPENED: '&e&lWyspa | &7Pomyslnie zmieniles status wyspy na publiczny.' ISLAND_OWNER_NONE: Brak ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lBlad | &7Nie mozesz uzyc tej komendy w trybie podgladu.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPodglad | &7Odszedles za daleko, nie jestes juz w trybie podgladu.' ISLAND_PREVIEW_CANCEL: '&e&lPodglad | &7Anulowales tryb podgladu.' ISLAND_PREVIEW_CONFIRM_TEXT: 'POTWIERDZ' ISLAND_PREVIEW_CANCEL_TEXT: 'ANULUJ' ISLAND_PREVIEW_SET: '&e&lPodglad | &7Pomyslnie zaktualizowano lokalizacje podgladu dla schematu {0} na {1}.' ISLAND_PREVIEW_START: | &e&lPodglad | &7Wlaczyles tryb podgladu dla schematu {0}. &e&lPodglad | &7Wpisz &a&lPOTWIERDZ &7by stworzyc nowa wyspe, lub &c&lANULUJ &7by wylaczyc tryb podladu. &e&lPodglad | &7Nie mozesz opuscic terenu wyspy, w przeciwnym razie tryb podgladowy zostanie anulowany. ISLAND_PROTECTED: '&c&lBlad | &7Ta wyspa jest chroniona.' ISLAND_PROTECTED_OPPED: '&7&oMozesz ominac to ograniczenie, uzywajac "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lWyspa | &7Czlonkowie {0}''s Wyspy &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)' ISLAND_TEAM_STATUS_ONLINE: '&a(Online)' ISLAND_TEAM_STATUS_ROLES: '&e&lWyspa | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Offline)' ISLAND_TOP_STATUS_ONLINE: '&a(Online)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Prywatne]' ISLAND_WAS_CLOSED: '&e&lWyspa | &7&oWyspa, na której byles, zostala zamknieta i zostales przeteleportowany z powrotem na miejsce odrodzenia...' ISLAND_WORTH_ERROR: '&c&lBlad | &7Podczas obliczania wyspy wystapil nieoczekiwany blad. Skontaktuj sie z administratorami, jesli problem bedzie sie powtarzal.' ISLAND_WORTH_RESULT: '&e&lWyspa | &7Wartosc Twojej wyspy to {0} [Poziom {1}]' ISLAND_WORTH_TIME_OUT: '&c&lBlad | &7Uplynal limit czasu zadania obliczeniowego. Spróbuj ponownie pózniej...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lWyspa | &7{0} dolaczyl do Twojej wyspy.' JOIN_ANNOUNCEMENT: '&e&lWyspa | &7{0} dolaczyl do Twojej wyspy.' JOIN_FULL_ISLAND: '&c&lBlad | &7Ta wyspa osiagnela maksymalna liczbe dozwolonych czlonków.' JOIN_WHILE_IN_ISLAND: '&c&lBlad | &7Jestes juz na wyspie.' JOINED_ISLAND: '&e&lWyspa | &7Dolaczyles do wyspy uzytkownika {0}.' JOINED_ISLAND_NAME: '&e&lWyspa | &7Dolaczyles do wyspy {0}.' JOINED_ISLAND_AS_COOP: '&e&lWyspa | &7Jestes teraz czlonkiem trybu wspólpracy na wyspie {0}.' JOINED_ISLAND_AS_COOP_NAME: '&e&lWyspa | &7Jestes teraz czlonkiem trybu wspólpracy na wyspie {0}.' KICK_ANNOUNCEMENT: '&e&lWyspa | &7{0} zostal wyrzucony z wyspy przez {1}.' KICK_ISLAND_LEADER: '&c&lBlad | &7Nie mozesz wyrzucic przywódcy wyspy, zamiast tego uzyj /is admin disband.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lBlad | &7Mozesz wyrzucac tylko graczy z nizsza rola wyspy niz twoja.' LACK_CHANGE_PERMISSION: '&c&lBlad | &7Musisz miec to uprawnienie, aby zmienic je na inne role.' LAST_ROLE_DEMOTE: '&c&lBlad | &7Nie mozesz juz zdegradowac tego gracza.' LAST_ROLE_PROMOTE: '&c&lBlad | &7Nie mozesz juz promowac tego gracza.' LEAVE_ANNOUNCEMENT: '&e&lWyspa | &7{0} opuscil wyspe.' LEAVE_ISLAND_AS_LEADER: |- &c&lBlad | &7Nie mozesz opuscic swojej wyspy, kiedy jest jej wlascicielem. &c&lBlad | &7Mozesz przeniesc prawo wlasnosci za pomoca /is transfer. LEFT_ISLAND: '&e&lWyspa | &7Opusciles swoja wyspe.' LEFT_ISLAND_COOP: '&e&lWyspa | &7Nie jestes juz czlonkiem trybu wspólpracy na wyspie {0}.' LEFT_ISLAND_COOP_NAME: '&e&lWyspa | &7Nie jestes juz czlonkiem spóldzielni na wyspie {0}.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lBlad | &7Musisz dostarczyc solidny material.' MAXIMUM_LEVEL: '&c&lBlad | &7Maksymalny poziom tego uaktualnienia to {0}.' MESSAGE_SENT: '&e&lWyspa | &7Pomyslnie wyslano {0} wiadomosc!' MISSION_CANNOT_COMPLETE: '&c&lBlad | &7Nie mozesz jeszcze ukończyc tej misji.' MISSION_NO_AUTO_REWARD: '&e&lMisja | &7Masz wszystkie wymagane materialy do ​​ukończenia {0} - uzyj /is misji, aby ukończyc!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lBlad | &7Musisz ukończyc {0} przed ukończeniem tej misji.' MISSION_STATUS_COMPLETE: '&e&lMisja | &7Zmieniono status misji {0} na ukończona dla {1}.' MISSION_STATUS_COMPLETE_ALL: '&e&lMisja | &7Zmieniono status wszystkich misji na ukończone dla {0}.' MISSION_STATUS_RESET: '&e&lMisja | &7Zresetuj status misji {0} dla {1}.' MISSION_STATUS_RESET_ALL: '&e&lMisja | &7Zresetuj status wszystkich misji dla {0}.' MODULE_ALREADY_INITIALIZED: '&e&lModul | &7Ten modul jest juz zaladowany.' MODULE_INFO: | &e&lModul | &7{0} przez {1} &e&lModul | &7&m-------------------- &e&lModul | &7{2} MODULE_LOADED_SUCCESS: '&e&lModul | &7Pomyslnie zaladowano modul {0}.' MODULE_LOADED_FAILURE: '&e&lModul | &7Nie udalo sie zaladowac modulu {0}. Sprawdz konsole, aby uzyskac wiecej informacji.' MODULE_UNLOADED_SUCCESS: '&e&lModul | &7Pomyslnie wyladowano modul.' MODULES_LIST: '&fModuly ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f,' NAME_ANNOUNCEMENT: '&e&lWyspa | &7{0} zmienil nazwe swojej wyspy na {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lWyspa | &7{0} zmienil nazwe wyspy {1} na {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lWyspa | &7{0} zmienil nazwe {1}&7 na {2}&7.' NAME_BLACKLISTED: '&c&lBlad | &7Nie mozesz uzywac tej nazwy.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lBlad | &7Nie mozesz uzywac nazw graczy jako nazw wysp.' NAME_TOO_LONG: '&c&lBlad | &7Nazwy wysp nie moga miec wiecej niz {0} znaków.' NAME_TOO_SHORT: '&c&lBlad | &7Nazwy wysp nie moga miec mniej niz {0} znaki.' NO_BAN_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby blokowac graczy.' NO_CLOSE_BYPASS: '&c&lBlad | &7Ta wyspa nie jest otwarta dla publicznosci.' NO_CLOSE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zamknac wyspe dla publicznosci.' NO_COMMAND_PERMISSION: '&c&lBlad | &7Nie masz uprawnien do uzycia tego polecenia. ({0})' NO_COOP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby dodawac graczy jako czlonków trybu wspólpracy.' NO_DELETE_WARP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby usunac wypaczenia.' NO_DEMOTE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zdegradowac graczy.' NO_DEPOSIT_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby wplacac pieniadze do banku wyspy.' NO_DISBAND_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby rozwiazac swoja wyspe.' NO_EXPEL_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby wydalic graczy ze swojej wyspy.' NO_INVITE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zapraszac graczy.' NO_ISLAND_CHEST_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby uzyskac dostep do skrzyni wyspy.' NO_ISLAND_INVITE: '&c&lBlad | &7Nie udalo sie znalezc zadnych zaproszeń z tej wyspy.' NO_ISLANDS_TO_PURGE: '&c&lBlad | &7Nie bylo wysp do oczyszczenia.' NO_KICK_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby wyrzucac graczy.' NO_MORE_DISBANDS: '&c&lBlad | &7Nie mozesz juz rozwiazac kolejnych wysp.' NO_MORE_WARPS: '&c&lBlad | &7Twoja wyspa nie moze miec wiecej wypaczeń.' NO_NAME_PERMISSION: '&c&lBlad | &7Nie mozesz zmienic nazwy swojej wyspy.' NO_OPEN_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby otworzyc wyspe dla publicznosci.' NO_PERMISSION_CHECK_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby uzyskac informacje o uprawnieniach.' NO_PROMOTE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby promowac graczy.' NO_RANKUP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby awansowac na wyzsza range.' NO_RATINGS_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby sprawdzac oceny.' NO_SET_BIOME_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zmienic biom wyspy.' NO_SET_DISCORD_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zmienic niezgodnosc wysp.' NO_SET_HOME_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby ustawic lokalizacje teleportu na wyspie.' NO_SET_PAYPAL_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zmienic adres e-mail na wyspie PayPal.' NO_SET_ROLE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby ustawic role dla graczy.' NO_SET_SETTINGS_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zmienic ustawienia wyspy.' NO_SET_WARP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby ustawic zawijanie wysp.' NO_TRANSFER_PERMISSION: '&c&lBlad | &7Musisz byc przywódca wyspy, aby przekazac przywództwo.' NO_UNCOOP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby usunac graczy z czlonkostwa w trybie wspólpracy.' NO_UPGRADE_PERMISSION: '&c&lBlad | &7Nie masz uprawnień do przejscia na inny poziom.' NO_WITHDRAW_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby wyplacac pieniadze z banku wyspy.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lBlad | &7Nie masz wystarczajaco duzo pieniedzy, aby wplacic {0} dolarów do banku wyspy.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lBlad | &7Nie masz wystarczajaco duzo pieniedzy.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lBlad | &7Nie masz wystarczajaco duzo pieniedzy, aby korzystac z wypaczeń wyspowych.' OPEN_MENU_WHILE_SLEEPING: '&7&oJestes zbyt zmeczony, aby korzystac z menu, nie sadzisz?' PANEL_TOGGLE_OFF: |- &e&lPanel | &7Wlaczony panel wyspowy &cWYl&7. &e&lPanel | &7Uruchomienie /is przeniesie Cie na wyspe. PANEL_TOGGLE_ON: |- &e&lPanel | &7Wlaczony panel wyspy &aWl&7. &e&lPanel | &7Uruchomienie /is otworzy panel. PERMISSION_CHANGED: '&e&lWyspa | &7Pomyslnie zaktualizowano uprawnienia {0} wyspy {1}.' PERMISSION_CHANGED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano uprawnienia {0} wyspy {1}.' PERMISSION_CHANGED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano uprawnienia {0} dla wszystkich wysp.' PERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.' PERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' PERMISSIONS_RESET: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy gracza {0} do wartosci domyslnych!' PERMISSIONS_RESET_ALL: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wszystkich wysp do wartosci domyslnych!' PERMISSIONS_RESET_NAME: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy {0} do wartosci domyslnych!' PERMISSIONS_RESET_PLAYER: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia dla {0} do wartosci domyslnych!' PERMISSIONS_RESET_ROLES: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy do wartosci domyslnych!' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Yes' PLAYER_ALREADY_BANNED: '&c&lBlad | &7Ten gracz jest juz zbanowany.' PLAYER_ALREADY_COOP: '&c&lBlad | &7Ten gracz jest juz w trybie wspólpracy.' PLAYER_ALREADY_IN_ISLAND: '&c&lBlad | &7Ten gracz jest juz na wyspie.' PLAYER_ALREADY_IN_ROLE: '&c&lBlad | &7{0} to juz {1}.' PLAYER_EXPEL_BYPASS: '&c&lBlad | &7Tego uzytkownika nie mozna usunac z wyspy.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lWyspa | &7{0} dolaczyl do serwera.' PLAYER_NOT_BANNED: '&c&lBlad | &7Ten gracz nie jest zbanowany.' PLAYER_NOT_COOP: '&c&lBlad | &7Ten gracz nie jest w trybie wspólpracy.' PLAYER_NOT_INSIDE_ISLAND: '&c&lBlad | &7Ten gracz nie znajduje sie na twojej wyspie.' PLAYER_NOT_ONLINE: '&c&lBlad | &7Ten gracz nie jest online!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lWyspa | &7{0} opuscil serwer.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lBlad | &7Mozesz promowac tylko graczy z nizsza rola wyspy niz twoja.' PROMOTED_MEMBER: '&e&lWyspa | &7Awansowales {0} na {1} na jego wyspie.' PURGE_CLEAR: '&e&lWyspa | &7Pomyslnie wyczyscilem wszystkie wyspy w kolejce do oczyszczenia.' PURGED_ISLANDS: |- &e&lWyspa | &7{0} wyspy zostana wyczyszczone po ponownym uruchomieniu serwera. &e&lWyspa | &7Mozesz to anulowac w dowolnym momencie za pomoca /is admin purge cancel. RANKUP_SUCCESS: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom uaktualnienia {0} dla wyspy {1}.' RANKUP_SUCCESS_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom aktualizacji {0} dla wszystkich wysp.' RANKUP_SUCCESS_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom uaktualnienia {0} dla {1}.' RATE_ALREADY_GIVEN: '&c&lBlad | &7Oceniles juz te wyspe.' RATE_ANNOUNCEMENT: '&e&lWyspa | &7{0} ocenilo Twoja wyspe {1} na 5!.' RATE_CHANGE_OTHER: '&e&lWyspa | &7Zmieniles ocene z {0} na {1}.' RATE_OWN_ISLAND: '&c&lBlad | &7Nie mozesz ocenic wlasnej wyspy.' RATE_REMOVE_ALL: '&e&lWyspa | &7Pomyslnie usunieto wszystkie oceny {0}.' RATE_REMOVE_ALL_ISLANDS: '&e&lWyspa | &7Pomyslnie usunieto wszystkie oceny wszystkich wysp.' RATE_SUCCESS: '&e&lWyspa | &7Ocenales te wyspe na {0} gwiazdek!' REACHED_BLOCK_LIMIT: '&e&lAktualizacje | &7Osiagnieto limit wyspy dla {0} blokowania.' REACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.' RECALC_ALREADY_RUNNING: '&c&lBlad | &7Twoja wyspa jest juz przeliczana.' RECALC_ALREADY_RUNNING_OTHER: '&c&lBlad | &7Ta wyspa jest juz przeliczana.' RECALC_ALL_ISLANDS: '&e&lWyspa | &7Ponowne obliczanie wszystkich wysp...' RECALC_ALL_ISLANDS_DONE: '&e&lWyspa | &7Pomyslnie zakończono ponowne obliczanie wszystkich wysp.' RECALC_PROCCESS_REQUEST: '&e&lWyspa | &7Przetwarzanie zadania...' RELOAD_COMPLETED: '&e&lWyspa | &7Ponowne ladowanie zakończone!' RELOAD_PROCCESS_REQUEST: '&e&lWyspa | &7Rozpoczynanie ponownego ladowania konfiguracji...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lWyspa | &7{0} odwolal zaproszenie uzytkownika {1} na wyspe.' RESET_WORLD_SUCCEED: '&e&lWyspa | &7Pomyslnie zresetuj swiat {0} dla wyspy {1}.' RESET_WORLD_SUCCEED_ALL: '&e&lWyspa | &7Pomyslnie zresetuj swiat {0} dla wszystkich wysp.' RESET_WORLD_SUCCEED_NAME: '&e&lWyspa | &7Pomyslnie zresetuj swiat {0} dla {1}.' SAME_NAME_CHANGE: '&c&lBlad | &7Musisz wprowadzic inna nazwe niz obecna nazwa wyspy.' SCHEMATIC_LEFT_SELECT: '&e&lSchematy | &7Wybrana pozycja #2 ({0})' SCHEMATIC_NOT_ADDED: '&c&lBlad | &7Serwer nie dodal schematu {0}. Skontaktuj sie z administratorem, aby rozwiazac problem. Format dla schematu {0} to "{1}".' SCHEMATIC_NOT_READY: '&c&lBlad | &7Nie wybrales dwóch pozycji.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematy | &7Przetwarzanie zadania...' SCHEMATIC_READY_TO_CREATE: | &e&lSchematy | &7Wybrales dwie pozycje. Uruchom /is admin schematic , aby utworzyc nowy schemat. &e&lSchematy | &7Upewnij sie, ze stoisz w miejscu teleportacji podczas wykonywania polecenia. SCHEMATIC_RIGHT_SELECT: '&e&lSchematy | &7Wybrana pozycja nr 1 ({0})' SCHEMATIC_SAVED: '&e&lSchematy | &7Schemat zapisany pomyslnie!' SELF_ROLE_CHANGE: '&c&lBlad | &7Nie mozesz zmienic swojej roli.' SET_UPGRADE_LEVEL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla wyspy {1}.' SET_UPGRADE_LEVEL_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla wszystkich wysp.' SET_UPGRADE_LEVEL_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla {1}.' SET_WARP: '&e&lWyspa | &7Pomyslnie utworzono nowe wypaczenie w {0}.' SET_WARP_OUTSIDE: '&c&lBlad | &7Nie mozesz ustawic warp poza swoja wyspa.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie ustawienia wyspy do domyslnych wartosci!' SETTINGS_UPDATED: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.' SETTINGS_UPDATED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.' SETTINGS_UPDATED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} dla wszystkich wysp.' SIZE_BIGGER_MAX: '&c&lBlad | &7Nie mozna ustawic rozmiaru wiekszego niz maksymalny rozmiar wyspy.' SPAWN_PROTECTED: '&c&lBlad | &7Spawn jest chroniony.' SPAWN_PROTECTED_OPPED: '&7&oMozesz ominac to ograniczenie, uzywajac "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Pomyslnie teleportowano {0} do odrodzenia.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Pomyslnie zaktualizowano lokalizacje odradzania do {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Szpieg] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lAktualizacje | &7Pomyslnie zsynchronizowano wszystkie wartosci aktualizacji wyspy {0}.' SYNC_UPGRADES_ALL: '&e&lAktualizacje | &7Pomyslnie zsynchronizowano wszystkie wartosci aktualizacji na wszystkich wyspach.' SYNC_UPGRADES_NAME: '&e&lAktualizacje | &7Pomyslnie zsynchronizowano wszystkie wartosci aktualizacji {0}.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lBlad | &7 Nie jestes na swojej wyspie.' TELEPORT_OUTSIDE_ISLAND: '&c&lBlad | &7Nie mozesz teleportowac sie poza swój zasieg ochrony.' TELEPORT_WARMUP: '&7&oZostaniesz przeteleportowany w {0}... Nie ruszaj sie!' TELEPORT_WARMUP_CANCEL: '&7&oPrzeniosles sie, wiec teleportacja zostala anulowana.' TITLE_SENT: '&e&lWyspa | &7Pomyslnie wyslano {0} tytul!' TELEPORTED_FAILED: '&e&lWyspa | &7Wyglada na to, ze ta wyspa nie ma bezpiecznych bloków. Prosze skontaktowac sie z czlonkiem wyspy.' TELEPORTED_SUCCESS: '&e&lWyspa | &7Zostales przeteleportowany na swoja wyspe.' TELEPORTED_TO_WARP: '&e&lWyspa | &7Pomyslnie teleportowano sie na te wyspe warp.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lWyspa | &7Gracz {0} teleportowal sie na wyspe warp {1}.' TOGGLED_BYPASS_OFF: '&e&lBypass | &7Wlaczony tryb obejscia &cWYl&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Wlaczony tryb obejscia &aWl&7.' TOGGLED_FLY_OFF: '&e&lFly | &7Wlacz lot wyspowy &cWYl&7.' TOGGLED_FLY_ON: '&e&lFly | &7Wlacz lot wyspowy &aON&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematy | &7Przelaczanie trybu schematu &cOFF&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchematy | &7Przelaczanie trybu schematu &aWl&7. &e&lSchematy | &7Wybierz obszar za pomoca zlotego topora. TOGGLED_SPY_OFF: '&e&lSpy | &7Wlaczono czat szpiegowski &cWYl&7.' TOGGLED_SPY_ON: '&e&lSpy | &7Wlaczony czat szpiegowski &aWl&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Przelaczanie ukladarki bloków &cWYl&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Przelaczanie ukladarki bloków &aON&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Przelaczanie czatu zespolu &cWYl&7.' TOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Przelaczanie czatu zespolu &aON&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lBariera | &7Przelaczanie granicy swiata &cWYl&7.' TOGGLED_WORLD_BORDER_ON: '&e&lBariera | &7Przelaczanie granicy swiata &aW&7.' TRANSFER_ADMIN: '&e&lWyspa | &7Przeniosles kierownictwo uzytkownika {0} do {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lBlad | &7{0} jest juz przywódca swojej wyspy.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lBlad | &7Ci gracze nie sa na tych samych wyspach.' TRANSFER_ADMIN_NOT_LEADER: '&c&lBlad | &7Ten gracz nie jest przywódca zadnej wyspy.' TRANSFER_ALREADY_LEADER: '&c&lBlad | &7Jestes juz przywódca tej wyspy.' TRANSFER_BROADCAST: '&e&lWyspa | &7Przywództwo wyspy zostalo przeniesione do {0}.' UNBAN_ANNOUNCEMENT: '&e&lWyspa | &7{0} zostal ODBLOKOWANY na wyspie przez {1}.' UNCOOP_ANNOUNCEMENT: '&e&lWyspa | &7{0} usunelo {1} z czlonkostwa w trybie wspólpracy.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lWyspa | &7{0} opuscil gre i nie jest juz czlonkiem trybu wspólpracy.' UNIGNORED_ISLAND: '&e&lWyspa | Wyspa &7{0} nie jest teraz ignorowana wsród najlepszych wysp.' UNIGNORED_ISLAND_NAME: '&e&lWyspa | &7Wyspa {0} nie jest teraz ignorowana wsród najlepszych wysp.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lWyspa | &7&oWyglada na to, ze to wypaczenie jest niebezpieczne. Prosze spróbowac innego wypaczenia.' UPDATED_PERMISSION: '&e&lWyspa | &7Zaktualizowano uprawnienia dla {0}.' UPDATED_SETTINGS: '&e&lWyspa | &7Zaktualizowano ustawienia wyspy {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lBlad | &7Mozesz uaktualnic ponownie dopiero za {0}.' VAULT_NOT_INSTALLED: '&c&lBlad | &7Na serwerze nie ma zainstalowanego pluginu Vault, wiec transakcje sa wylaczone.' VISITOR_BLOCK_COMMAND: '&c&lBlad | &7Nie mozesz uzyc tego polecenia na innych wyspach.' WARP_ALREADY_EXIST: '&c&lBlad | &7Istnieje juz warp o tej nazwie.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lWarpy | &7Wprowadz nowa wiedze (wpisz -cancel", aby anulowac): &e&lWarpy | &7Mozesz oddzielic wiersze, uzywajac '\n.' WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarpy | &7Wpisz nazwe (wpisz "-cancel", aby anulowac):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarpy | &7Wprowadz nowy typ materialu (wpisz "-cancel", aby anulowac):' WARP_CATEGORY_ICON_UPDATED: '&e&lWarpy | &7Pomyslnie zaktualizowano ikone kategorii.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lBlad | &7W nazwach kategorii wypaczenia mozna uzywac tylko liter alfabetu, cyfr i ''_''.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lError | Warp category names cannot be longer than 255 chars.' WARP_CATEGORY_SLOT: '&e&lWarpy | &7Wprowadz nowe miejsce (wpisz "-cancel", aby anulowac):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lBlad | &7To miejsce jest juz zajete przez inna kategorie.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarpy | &7Pomyslnie zmieniono miejsce kategorii na {0}.' WARP_CATEGORY_RENAME: '&e&lWarpy | &7Wprowadz nowa nazwe (wpisz "-cancel", aby anulowac):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lBlad | &7Ta nazwa jest juz zajeta przez inna kategorie.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarpy | &7Pomyslnie zmieniono nazwe kategorii na {0}.' WARP_ICON_NEW_LORE: | &e&lWarpy | &7Wprowadz nowa wiedze (wpisz "-cancel", aby anulowac): &e&lWarpy | &7Mozesz oddzielic wiersze, uzywajac '\n.' WARP_ICON_NEW_NAME: '&e&lWarpy | &7Wpisz nazwe (wpisz "-cancel", aby anulowac):' WARP_ICON_NEW_TYPE: '&e&lWarpy | &7Wprowadz nowy typ materialu (wpisz "-cancel", aby anulowac):' WARP_ICON_UPDATED: '&e&lWarpy | &7Pomyslnie zaktualizowano ikone wypaczenia.' WARP_ILLEGAL_NAME: '&c&lBlad | &7W nazwach wypaczeń mozna uzywac tylko liter alfabetu, cyfr i ''_''.' WARP_LOCATION_UPDATE: '&e&lWarpy | &7Pomyslnie zaktualizowano lokalizacje wypaczenia do Twojej lokalizacji.' WARP_NAME_TOO_LONG: '&c&lError | Warp names cannot be longer than 255 chars.' WARP_PUBLIC_UPDATE: '&e&lWarpy | &7Udalo sie otworzyc osnowe dla publicznosci.' WARP_PRIVATE_UPDATE: '&e&lWarpy | &7Z powodzeniem zamknieto osnowe dla publicznosci.' WARP_RENAME: '&e&lWarpy | &7Wprowadz nowa nazwe (wpisz "-cancel", aby anulowac):' WARP_RENAME_ALREADY_EXIST: '&c&lBlad | &7Ta nazwa jest juz przejeta przez inna osnowe.' WARP_RENAME_SUCCESS: '&e&lWarpy | &7Pomyslnie zmieniono nazwe wypaczenia na {0}.' WITHDRAW_ALL_MONEY: |- &e&lBank | &7Island Bank ma w sobie tylko {0} dolarów. &e&lBank | &7&oWyplata wszystkich pieniedzy..." WITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} wyplaciles {1}$ z banku wyspy!' WITHDRAW_ERROR: '&c&lBlad | &7{0}.' WITHDRAWN_MONEY: '&e&lBank | &7Wyplaciles {0}$ z banku wysp {1}!' WITHDRAWN_MONEY_NAME: '&e&lBank | &7Wyplaciles {0}$ z banku wyspy {1}!' WORLD_NOT_ENABLED: '&e&lWorlds | &7Swiat {0} nie jest wlaczony na serwerze.' WORLD_NOT_UNLOCKED: '&e&lSwiaty | &7swiat {0} nie jest jeszcze odblokowany!' ================================================ FILE: src/main/resources/lang/pt-BR.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # You can find a tutorial about configuring messages here: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lIlha | &7Jogador {0} adicionado com sucesso à ilha de {1}.' ADMIN_ADD_PLAYER_NAME: '&e&lIlha | &7Jogador {0} adicionado com sucesso à ilha {1}.' ADMIN_DEPOSIT_MONEY: '&e&lBanco | &7Você depositou R${0} no banco da ilha de {1}.' ADMIN_DEPOSIT_MONEY_NAME: '&e&lBanco | &7Você depositou R${0} no banco da ilha {1}.' ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Desenvolvido por Ome_R' ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista de Comandos Admin [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSkyblock &7Use /is admin {0} para a próxima página.' ALREADY_IN_ISLAND: '&c&lErro | &7Você já está em uma ilha.' ALREADY_IN_ISLAND_OTHER: '&c&lErro | &7Este jogador já é membro da sua ilha.' BAN_ANNOUNCEMENT: '&e&lIlha | &7{0} foi BANIDO da ilha por {1}.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode banir jogadores com um cargo inferior ao seu na ilha.' BANK_DEPOSIT_CUSTOM: '&e&lBanco | &7Digite o valor que deseja depositar:' BANK_DEPOSIT_COMPLETED: 'Depósito Concluído' BANK_LIMIT_EXCEED: '&c&lErro | &7Você excedeu o limite do banco.' BANK_WITHDRAW_CUSTOM: '&e&lBanco | &7Digite o valor que deseja sacar:' BANK_WITHDRAW_COMPLETED: 'Saque Concluído' BANNED_FROM_ISLAND: '&c&lErro | &7Você está banido desta ilha.' BLOCK_COUNT_CHECK: '&e&lIlha | &7Esta ilha possui x{0} {1}.' BLOCK_COUNTS_CHECK: | &e&lIlha | &7Esta ilha possui os seguintes blocos: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lIlha | &7Esta ilha não possui blocos registrados.' BLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}' BLOCK_LEVEL: '&e&lNível | &7O nível do bloco {0} é {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lNível | &7O bloco {0} não possui valor.' BLOCK_VALUE: '&e&lValor | &7O bloco {0} vale {1}.' BLOCK_VALUE_WORTHLESS: '&e&lValor | &7O bloco {0} não possui valor.' BONUS_SYNC_ALL: '&e&lIlha | &7Bônus sincronizado com sucesso para todas as ilhas.' BONUS_SYNC_NAME: '&e&lIlha | &7Bônus sincronizado com sucesso para {0}.' BONUS_SYNC: '&e&lIlha | &7Bônus sincronizado com sucesso para a ilha de {0}.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Azul' BORDER_PLAYER_COLOR_NAME_RED: 'Vermelho' BORDER_PLAYER_COLOR_NAME_GREEN: 'Verde' BORDER_PLAYER_COLOR_UPDATED: '&e&lBorda | &7Cor da borda pessoal alterada com sucesso para {0}.' BUILD_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode construir fora do seu limite de proteção.' CANNOT_SET_ROLE: '&c&lErro | &7Você não pode definir o cargo do jogador como {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lErro | &7Você só pode alterar permissões para cargos inferiores ao seu na ilha.' CHANGED_BANK_LIMIT: '&e&lMelhorias | &7Limite do banco da ilha de {0} atualizado com sucesso.' CHANGED_BANK_LIMIT_ALL: '&e&lMelhorias | &7Limite do banco de todas as ilhas atualizado com sucesso.' CHANGED_BANK_LIMIT_NAME: '&e&lMelhorias | &7Limite do banco de {0} atualizado com sucesso.' CHANGED_BIOME: '&e&lIlha | &7Bioma alterado com sucesso para {0}. Você pode precisar se reconectar ao servidor para ver as mudanças.' CHANGED_BIOME_ALL: '&e&lIlha | &7Bioma alterado com sucesso para {0} em todas as ilhas.' CHANGED_BIOME_NAME: '&e&lIlha | &7Bioma alterado com sucesso para {0} na ilha {1}.' CHANGED_BIOME_OTHER: '&e&lIlha | &7Bioma alterado com sucesso para {0} na ilha de {1}.' CHANGED_BLOCK_AMOUNT: '&e&lBlocos | &7Quantidade de blocos em {0} alterada para {1}.' CHANGED_BLOCK_LIMIT: '&e&lMelhorias | &7Limite de blocos {0} atualizado na ilha de {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lMelhorias | &7Limite de blocos {0} atualizado em todas as ilhas.' CHANGED_BLOCK_LIMIT_NAME: '&e&lMelhorias | &7Limite de blocos {0} atualizado em {1}.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} na ilha de {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} em todas as ilhas.' CHANGED_CHEST_SIZE_NAME: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} de {2}.' CHANGED_COOP_LIMIT: '&e&lMelhorias | &7O limite de jogadores na cooperação da ilha de {0} foi atualizado com sucesso.' CHANGED_COOP_LIMIT_ALL: '&e&lMelhorias | &7O limite de jogadores na cooperação de todas as ilhas foi atualizado com sucesso.' CHANGED_COOP_LIMIT_NAME: '&e&lMelhorias | &7O limite de jogadores na cooperação de {0} foi atualizado com sucesso.' CHANGED_CROP_GROWTH: '&e&lMelhorias | &7O multiplicador de crescimento das plantações da ilha de {0} foi atualizado com sucesso.' CHANGED_CROP_GROWTH_ALL: '&e&lMelhorias | &7O multiplicador de crescimento das plantações de todas as ilhas foi atualizado com sucesso.' CHANGED_CROP_GROWTH_NAME: '&e&lMelhorias | &7O multiplicador de crescimento das plantações de {0} foi atualizado com sucesso.' CHANGED_DISCORD: '&e&lIlha | &7O Discord da ilha foi atualizado para {0}.' CHANGED_ENTITY_LIMIT: '&e&lMelhorias | &7O limite de entidades {0} para a ilha de {1} foi atualizado com sucesso.' CHANGED_ENTITY_LIMIT_ALL: '&e&lMelhorias | &7O limite de entidades {0} para todas as ilhas foi atualizado com sucesso.' CHANGED_ENTITY_LIMIT_NAME: '&e&lMelhorias | &7O limite de entidades {0} para {1} foi atualizado com sucesso.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lMelhorias | &7O nível do efeito da ilha {0} para a ilha de {1} foi atualizado com sucesso.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lMelhorias | &7O nível do efeito da ilha {0} para todas as ilhas foi atualizado com sucesso.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lMelhorias | &7O nível do efeito da ilha {0} para {1} foi atualizado com sucesso.' CHANGED_ISLAND_SIZE: '&e&lMelhorias | &7O tamanho da ilha de {0} foi atualizado com sucesso.' CHANGED_ISLAND_SIZE_ALL: '&e&lMelhorias | &7O tamanho de todas as ilhas foi atualizado com sucesso.' CHANGED_ISLAND_SIZE_NAME: '&e&lMelhorias | &7O tamanho da ilha de {0} foi atualizado com sucesso.' CHANGED_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.' CHANGED_LANGUAGE: '&e&lIdioma | &7Seu idioma foi alterado com sucesso para Inglês.' CHANGED_MOB_DROPS: '&e&lMelhorias | &7O multiplicador de drops de mobs da ilha de {0} foi atualizado com sucesso.' CHANGED_MOB_DROPS_ALL: '&e&lMelhorias | &7O multiplicador de drops de mobs de todas as ilhas foi atualizado com sucesso.' CHANGED_MOB_DROPS_NAME: '&e&lMelhorias | &7O multiplicador de drops de mobs de {0} foi atualizado com sucesso.' CHANGED_NAME: '&e&lIlha | &7Você alterou o nome da sua ilha para {0}&7.' CHANGED_NAME_OTHER: '&e&lIlha | &7Você alterou o nome da ilha de {0} para {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lIlha | &7Você alterou o nome de {0}&7 para {1}&7.' CHANGED_PAYPAL: '&e&lIlha | &7O PayPal da ilha foi atualizado para {0}.' CHANGED_ROLE_LIMIT: '&e&lMelhorias | &7O limite do cargo {0} para a ilha de {1} foi atualizado com sucesso.' CHANGED_ROLE_LIMIT_ALL: '&e&lMelhorias | &7O limite do cargo {0} para todas as ilhas foi atualizado com sucesso.' CHANGED_ROLE_LIMIT_NAME: '&e&lMelhorias | &7O limite do cargo {0} para {1} foi atualizado com sucesso.' CHANGED_SPAWNER_RATES: '&e&lMelhorias | &7O multiplicador das taxas de geradores da ilha de {0} foi atualizado com sucesso.' CHANGED_SPAWNER_RATES_ALL: '&e&lMelhorias | &7O multiplicador das taxas de geradores de todas as ilhas foi atualizado com sucesso.' CHANGED_SPAWNER_RATES_NAME: '&e&lMelhorias | &7O multiplicador das taxas de geradores de {0} foi atualizado com sucesso.' CHANGED_TEAM_LIMIT: '&e&lMelhorias | &7O limite de membros da equipe da ilha de {0} foi atualizado com sucesso.' CHANGED_TEAM_LIMIT_ALL: '&e&lMelhorias | &7O limite de membros da equipe de todas as ilhas foi atualizado com sucesso.' CHANGED_TEAM_LIMIT_NAME: '&e&lMelhorias | &7O limite de membros da equipe de {0} foi atualizado com sucesso.' CHANGED_TELEPORT_LOCATION: '&e&lIlha | &7A localização de teletransporte foi atualizada com sucesso.' CHANGED_WARPS_LIMIT: '&e&lMelhorias | &7O limite de warps da ilha de {0} foi atualizado com sucesso.' CHANGED_WARPS_LIMIT_ALL: '&e&lMelhorias | &7O limite de warps de todas as ilhas foi atualizado com sucesso.' CHANGED_WARPS_LIMIT_NAME: '&e&lMelhorias | &7O limite de warps de {0} foi atualizado com sucesso.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'quantidade' COMMAND_ARGUMENT_BIOME: 'bioma' COMMAND_ARGUMENT_BORDER_COLOR: 'cor-da-borda' COMMAND_ARGUMENT_COMMAND: 'comando...' COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: 'efeito-de-poção' COMMAND_ARGUMENT_EMAIL: 'email' COMMAND_ARGUMENT_ENTITY: 'entidade' COMMAND_ARGUMENT_ISLAND_NAME: 'nome-da-ilha' COMMAND_ARGUMENT_ISLAND_ROLE: 'cargo-da-ilha' COMMAND_ARGUMENT_LEADER: 'líder' COMMAND_ARGUMENT_LEVEL: 'nível' COMMAND_ARGUMENT_LIMIT: 'limite' COMMAND_ARGUMENT_MATERIAL: 'material' COMMAND_ARGUMENT_MENU: 'nome-do-menu' COMMAND_ARGUMENT_MESSAGE: 'mensagem...' COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: 'nome-da-missão' COMMAND_ARGUMENT_MODULE_NAME: 'nome-do-módulo' COMMAND_ARGUMENT_MULTIPLIER: 'multiplicador' COMMAND_ARGUMENT_NAME: 'nome' COMMAND_ARGUMENT_NEW_LEADER: 'novo-líder' COMMAND_ARGUMENT_PAGE: 'página' COMMAND_ARGUMENT_PATH: 'caminho' COMMAND_ARGUMENT_PERMISSION: 'permissão' COMMAND_ARGUMENT_PLAYER_NAME: 'nome-do-jogador' COMMAND_ARGUMENT_PRIVATE: 'privado' COMMAND_ARGUMENT_RATING: 'avaliação' COMMAND_ARGUMENT_ROWS: 'linhas' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'nome-da-esquema' COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'configurações' COMMAND_ARGUMENT_SIZE: 'tamanho' COMMAND_ARGUMENT_TIME: 'tempo' COMMAND_ARGUMENT_TITLE_DURATION: 'duração' COMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in' COMMAND_ARGUMENT_TITLE_FADE_OUT: 'desaparecer' COMMAND_ARGUMENT_UPGRADE_NAME: 'nome-do-upgrade' COMMAND_ARGUMENT_VALUE: 'valor' COMMAND_ARGUMENT_WARP_NAME: 'nome-do-warp' COMMAND_ARGUMENT_WARP_CATEGORY: 'categoria-do-warp' COMMAND_ARGUMENT_WORLD: 'mundo' COMMAND_COOLDOWN_FORMAT: '&c&lErro | &7Você só pode usar o comando novamente em {0}.' COMMAND_DESCRIPTION_ACCEPT: 'Aceite um convite de um jogador.' COMMAND_DESCRIPTION_ADMIN: 'Use os comandos de administrador.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Adicione um usuário a uma ilha.' COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Aumente o limite de blocos para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Adicione um bônus a um jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Aumente o limite de jogadores na cooperação da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Aumente o multiplicador de crescimento das plantações da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Adicione um efeito à ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Aumente o limite de entidades na ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Adicione porcentagem de um material ao gerador de pedra.' COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Aumente o multiplicador de drops de mobs da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expanda o tamanho da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Aumente o multiplicador das taxas dos geradores da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Aumente o limite de membros da equipe da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Aumente o limite de warps de uma ilha.' COMMAND_DESCRIPTION_ADMIN_BONUS: 'Conceda um bônus a um jogador.' COMMAND_DESCRIPTION_ADMIN_BYPASS: 'Alternar o modo bypass.' COMMAND_DESCRIPTION_ADMIN_CHEST: 'Abrir o baú da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Limpar as taxas do gerador para uma ilha específica.' COMMAND_DESCRIPTION_ADMIN_CLOSE: 'Fechar uma ilha para o público.' COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Executar um comando para todos os membros de ilhas.' COMMAND_DESCRIPTION_ADMIN_COUNT: 'Verificar a contagem de blocos em uma ilha específica.' COMMAND_DESCRIPTION_ADMIN_DATA: 'Interagir com dados persistentes de jogadores ou ilhas.' COMMAND_DESCRIPTION_ADMIN_DEBUG: 'Alternar saídas de depuração.' COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Excluir um warp de uma ilha.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Rebaixar um membro na ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Depositar dinheiro no banco da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Desfazer permanentemente a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Conceder dissoluções de ilhas a um jogador.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignorar uma ilha das melhores ilhas.' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Entrar em uma ilha sem convite.' COMMAND_DESCRIPTION_ADMIN_KICK: 'Expulsar um jogador de sua ilha.' COMMAND_DESCRIPTION_ADMIN_MODULES: 'Gerenciar módulos do plugin.' COMMAND_DESCRIPTION_ADMIN_MISSION: 'Alterar o status de uma missão para um jogador.' COMMAND_DESCRIPTION_ADMIN_MSG: 'Enviar uma mensagem a um jogador sem prefixos.' COMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Enviar a todos os membros de uma ilha uma mensagem sem prefixos.' COMMAND_DESCRIPTION_ADMIN_NAME: 'Alterar o nome de uma ilha.' COMMAND_DESCRIPTION_ADMIN_OPEN: 'Abrir uma ilha para o público.' COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Abrir um menu personalizado para um jogador.' COMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Promover um membro na ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_PURGE: 'Remover ilhas.' COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Subir o nível de um upgrade para uma ilha.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Recalcular o valor de uma ilha.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarregar todas as configurações e tarefas do plugin.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remover o limite de blocos de uma ilha.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remover todas as avaliações dadas por um jogador.' COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Redefinir um mundo para uma ilha.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Criar esquemas para o plugin.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Definir o bioma de uma ilha.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Definir a quantidade de blocos em um local específico.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Definir o limite de blocos para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Definir as linhas do baú para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Definir o limite de cooperação para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Definir o multiplicador de crescimento de plantações para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Definir a quantidade de dissoluções de ilhas de um jogador.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Definir o nível do efeito da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Definir o limite de entidades para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transferir uma ilha para outra pessoa.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Definir o multiplicador de drops de mobs para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Definir uma permissão de função obrigatória para todas as ilhas.' COMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Definir a avaliação de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Definir o limite de cargos para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Alternar configurações para uma ilha específica.' COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Alterar a porcentagem de um material no gerador de pedra.' COMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Alterar o tamanho da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Definir o local de spawn do servidor.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Definir o multiplicador das taxas de spawner para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Definir o limite de membros da equipe para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Definir o nível de um upgrade para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Definir o limite de warps de uma ilha.' COMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Abrir o editor de configurações do plugin.' COMMAND_DESCRIPTION_ADMIN_SHOW: 'Obter informações sobre uma ilha.' COMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teletransportar para o local de spawn.' COMMAND_DESCRIPTION_ADMIN_SPY: 'Alternar o modo de espionagem de chat.' COMMAND_DESCRIPTION_ADMIN_STATS: 'Exibir estatísticas sobre o plugin.' COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sincronizar o bônus de uma ilha com os mundos gerados.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sincronizar os valores de upgrades de uma ilha.' COMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teletransportar para outras ilhas.' COMMAND_DESCRIPTION_ADMIN_TITLE: 'Enviar um título para um jogador.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Enviar um título para todos os membros de uma ilha.' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Remover uma ilha da lista de ignorados das melhores ilhas.' COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Desbloquear um mundo para uma ilha.' COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Retirar dinheiro do banco da ilha de outro jogador.' COMMAND_DESCRIPTION_BALANCE: 'Verificar a quantidade de dinheiro no banco da ilha.' COMMAND_DESCRIPTION_BAN: 'Banir um jogador de sua ilha.' COMMAND_DESCRIPTION_BANK: 'Abrir o banco da ilha.' COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: 'Alterar o bioma da ilha.' COMMAND_DESCRIPTION_BORDER: 'Alterar a cor da borda das ilhas.' COMMAND_DESCRIPTION_CHEST: 'Abrir o baú da ilha.' COMMAND_DESCRIPTION_CLOSE: 'Fechar a ilha para o público.' COMMAND_DESCRIPTION_COOP: 'Adicionar um jogador como coop na sua ilha.' COMMAND_DESCRIPTION_COOPS: 'Abrir o menu de coops.' COMMAND_DESCRIPTION_COUNTS: 'Ver contagem de blocos na sua ilha.' COMMAND_DESCRIPTION_CREATE: 'Criar uma nova ilha.' COMMAND_DESCRIPTION_DEL_WARP: 'Excluir um warp da ilha.' COMMAND_DESCRIPTION_DEMOTE: 'Rebaixar um membro na sua ilha.' COMMAND_DESCRIPTION_DEPOSIT: 'Depositar dinheiro da sua conta pessoal no banco da ilha.' COMMAND_DESCRIPTION_DISBAND: 'Dissolver sua ilha permanentemente.' COMMAND_DESCRIPTION_EXPEL: 'Expulsar um visitante da sua ilha.' COMMAND_DESCRIPTION_FLY: 'Alternar o modo de voo na ilha.' COMMAND_DESCRIPTION_HELP: 'Lista de todos os comandos.' COMMAND_DESCRIPTION_INVITE: 'Convidar um jogador para sua ilha.' COMMAND_DESCRIPTION_KICK: 'Expulsar um jogador da sua ilha.' COMMAND_DESCRIPTION_LANG: 'Alterar seu idioma pessoal.' COMMAND_DESCRIPTION_LEAVE: 'Sair da sua ilha.' COMMAND_DESCRIPTION_MEMBERS: 'Abrir o menu de membros.' COMMAND_DESCRIPTION_MISSION: 'Completar uma missão.' COMMAND_DESCRIPTION_MISSIONS: 'Abrir o menu de missões.' COMMAND_DESCRIPTION_NAME: 'Alterar o nome da sua ilha.' COMMAND_DESCRIPTION_OPEN: 'Abrir a ilha para o público.' COMMAND_DESCRIPTION_PANEL: 'Abrir o painel da ilha.' COMMAND_DESCRIPTION_PARDON: 'Desbanir um jogador da sua ilha.' COMMAND_DESCRIPTION_PERMISSIONS: 'Exibir todas as permissões para um cargo da ilha.' COMMAND_DESCRIPTION_PROMOTE: 'Promover um membro na sua ilha.' COMMAND_DESCRIPTION_RANKUP: 'Subir de nível em um upgrade.' COMMAND_DESCRIPTION_RATE: 'Avaliar uma ilha.' COMMAND_DESCRIPTION_RATINGS: 'Exibir todas as avaliações das ilhas.' COMMAND_DESCRIPTION_SETTINGS: 'Abrir o menu de configurações.' COMMAND_DESCRIPTION_RECALC: 'Recalcular o valor da ilha.' COMMAND_DESCRIPTION_SET_DISCORD: 'Definir o discord da ilha para prêmios de ilha.' COMMAND_DESCRIPTION_SET_PAYPAL: 'Definir o e-mail do PayPal da ilha para prêmios de ilha.' COMMAND_DESCRIPTION_SET_ROLE: 'Alterar o cargo de um jogador na sua ilha.' COMMAND_DESCRIPTION_SET_TELEPORT: 'Alterar a localização de teleporte da sua ilha.' COMMAND_DESCRIPTION_SET_WARP: 'Criar um novo warp da ilha.' COMMAND_DESCRIPTION_SHOW: 'Obter informações sobre uma ilha.' COMMAND_DESCRIPTION_TEAM: 'Obter informações sobre o status dos membros da ilha.' COMMAND_DESCRIPTION_TEAM_CHAT: 'Alternar o modo de chat da equipe.' COMMAND_DESCRIPTION_TELEPORT: 'Teletransportar para sua ilha.' COMMAND_DESCRIPTION_TOGGLE: 'Alternar as bordas da ilha e o posicionamento de blocos empilhados.' COMMAND_DESCRIPTION_TOP: 'Abrir o painel das melhores ilhas.' COMMAND_DESCRIPTION_TRANSFER: 'Transferir a liderança da sua ilha.' COMMAND_DESCRIPTION_UNCOOP: 'Remover um jogador como coop da sua ilha.' COMMAND_DESCRIPTION_UPGRADE: 'Abrir o painel de upgrades.' COMMAND_DESCRIPTION_VALUE: 'Obter o valor de um bloco.' COMMAND_DESCRIPTION_VALUES: 'Abrir o menu de valores.' COMMAND_DESCRIPTION_VISIT: 'Teletransportar para o local de visitantes de uma ilha.' COMMAND_DESCRIPTION_VISITORS: 'Abrir o menu de visitantes.' COMMAND_DESCRIPTION_WARP: 'Ir para um warp da ilha.' COMMAND_DESCRIPTION_WARPS: 'Abrir o menu de warps.' COMMAND_DESCRIPTION_WITHDRAW: 'Retirar dinheiro do banco da sua ilha para sua conta pessoal.' COMMAND_USAGE: '&cUso: /{0}' COOP_ANNOUNCEMENT: '&e&lIlha | &7{0} adicionou {1} como membro coop.' COOP_BANNED_PLAYER: '&c&lErro | &7Este jogador está banido da ilha e não pode ser adicionado como coop.' COOP_LIMIT_EXCEED: '&c&lErro | &7Você atingiu o número máximo de jogadores coop que a ilha pode ter.' CREATE_ISLAND: '&e&lIlha | &7Criou uma nova ilha em {0} em {1}ms.' CREATE_ISLAND_FAILURE: '&c&lErro | &7Ocorreu um erro ao criar sua ilha. Por favor, entre em contato com o administrador para investigar o problema.' CREATE_WORLD_FAILURE: '&c&lErro | &7Ocorreu um erro ao gerar o mundo. Por favor, entre em contato com o administrador para investigar o problema.' DEBUG_MODE_DISABLED: '&e&lDebug | &7Modo de debug alternado para &cDESATIVADO&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7Modo de debug alternado para &aATIVADO&7.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Filtro de debug {0} alternado para &aATIVADO&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Todos os filtros de debug alternados para &cDESATIVADO&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Filtro de debug {0} alternado para &cDESATIVADO&7.' DELETE_WARP: '&e&lIlha | &7Você excluiu o warp {0}.' DELETE_WARP_SIGN_BROKE: '&7&oHavia uma placa para esse warp, ela foi quebrada...' DEMOTE_LEADER: '&c&lErro | &7Você não pode rebaixar líderes da ilha.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode rebaixar jogadores com um cargo inferior ao seu.' DEMOTED_MEMBER: '&e&lIlha | &7Você rebaixou {0} para {1} na ilha dele.' DEPOSIT_ANNOUNCEMENT: '&e&lBanco | &7{0} depositou ${1} no banco da ilha!' DEPOSIT_ERROR: '&c&lErro | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode destruir fora da sua área de proteção.' DISBAND_ANNOUNCEMENT: '&e&lIlha | &7Sua ilha foi apagada por {0}.' DISBAND_GIVE: '&e&lIlha | &7Você recebeu {0} dissoluções.' DISBAND_GIVE_ALL: '&e&lIlha | &7Você deu {0} dissoluções para todos os jogadores.' DISBAND_GIVE_OTHER: '&e&lIlha | &7Você deu {0} dissoluções para {1}.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oSua ilha foi apagada, e ${0} foram reembolsados para sua conta a partir do banco da ilha.' DISBAND_SET: '&e&lIlha | &7O número de dissoluções foi definido como {0}.' DISBAND_SET_ALL: '&e&lIlha | &7Você definiu o número de dissoluções para todos os jogadores como {0}.' DISBAND_SET_OTHER: '&e&lIlha | &7Você definiu o número de dissoluções de {0} para {1}.' DISBANDED_ISLAND: '&e&lIlha | &7Você apagou sua ilha.' DISBANDED_ISLAND_OTHER: '&e&lIlha | &7Você apagou a ilha de {0}.' DISBANDED_ISLAND_OTHER_NAME: '&e&lIlha | &7Você apagou a ilha {0}.' ENTER_PVP_ISLAND: '&7&oVocê foi teleportado para uma ilha com PVP ativado. Você está imune ao PVP pelos próximos 10 segundos...' EXPELLED_PLAYER: '&e&lIlha | &7{0} foi expulso da ilha.' FORMAT_QUAD: 'Q' FORMAT_TRILLION: 'T' FORMAT_BILLION: 'B' FORMAT_MILLION: 'M' FORMAT_THOUSANDS: 'K' FORMAT_SECONDS_NAME: 'segundos' FORMAT_SECOND_NAME: 'segundo' FORMAT_MINUTES_NAME: 'minutos' FORMAT_MINUTE_NAME: 'minuto' FORMAT_HOURS_NAME: 'horas' FORMAT_HOUR_NAME: 'hora' FORMAT_DAYS_NAME: 'dias' FORMAT_DAY_NAME: 'dia' GENERATOR_CLEARED: '&e&lIlha | &7Os valores do gerador da ilha de {0} foram limpos com sucesso.' GENERATOR_CLEARED_NAME: '&e&lIlha | &7Os valores do gerador da ilha de {0} foram limpos com sucesso.' GENERATOR_CLEARED_ALL: '&e&lIlha | &7Os valores do gerador de todas as ilhas foram limpos com sucesso.' GENERATOR_UPDATED: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para a ilha de {1}.' GENERATOR_UPDATED_NAME: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para a ilha de {1}.' GENERATOR_UPDATED_ALL: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para todas as ilhas.' GLOBAL_COMMAND_EXECUTED: '&e&lIlha | &7Comando executado com sucesso nos membros da ilha de {0}!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lIlha | &7Comando executado com sucesso nos membros da ilha de {0}!' GLOBAL_MESSAGE_SENT: '&e&lIlha | &7Mensagem enviada com sucesso para os membros da ilha de {0}!' GLOBAL_MESSAGE_SENT_NAME: '&e&lIlha | &7Mensagem enviada com sucesso para os membros da ilha de {0}!' GLOBAL_TITLE_SENT: '&e&lIlha | &7Título enviado com sucesso para os membros da ilha de {0}!' GLOBAL_TITLE_SENT_NAME: '&e&lIlha | &7Título enviado com sucesso para os membros da ilha de {0}!' GOT_BANNED: '&e&lIlha | &7Você foi BANIDO da ilha de {0}.' GOT_DEMOTED: '&e&lIlha | &7Você foi rebaixado para {0} na sua ilha.' GOT_EXPELLED: '&e&lIlha | &7&oVocê foi expulso da ilha por {0}.' GOT_INVITE: '&e&lIlha | &7{0} convidou você para a ilha dele.' GOT_INVITE_TOOLTIP: '&7Clique na mensagem para aceitar o convite.' GOT_KICKED: '&e&lIlha | &7Você foi expulso da sua ilha por {0}.' GOT_PROMOTED: '&e&lIlha | &7Você foi promovido para {0} na sua ilha.' GOT_REVOKED: '&e&lIlha | &7{0} revogou seu convite para a ilha dele.' GOT_UNBANNED: '&e&lIlha | &7Você foi DESBANIDO da ilha de {0}.' HIT_ISLAND_MEMBER: '&c&lErro | &7Você não pode atacar membros da sua ilha.' HIT_PLAYER_IN_ISLAND: '&c&lErro | &7Você não pode atacar jogadores dentro de ilhas.' IGNORED_ISLAND: '&e&lIlha | &7A ilha de {0} agora está ignorada no ranking das melhores ilhas.' IGNORED_ISLAND_NAME: '&e&lIlha | &7A ilha {0} agora está ignorada no ranking das melhores ilhas.' INTERACT_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode interagir fora da sua área de proteção.' INVALID_AMOUNT: '&c&lErro | &7Valor inválido {0}.' INVALID_BIOME: '&c&lErro | &7Bioma inválido {0}.' INVALID_BLOCK: '&c&lErro | &7Localização de bloco inválida {0}.' INVALID_BORDER_COLOR: '&c&lErro | &7Cor da borda inválida {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lErro | &7Efeito inválido {0}.' INVALID_ENTITY: '&c&lErro | &7Entidade inválida {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lErro | &7Intervalo inválido {0}.' INVALID_ISLAND: '&c&lErro | &7Você não tem uma ilha.' INVALID_ISLAND_LOCATION: '&c&lErro | &7Não há ilha na sua localização.' INVALID_ISLAND_OTHER: '&c&lErro | &7{0} não tem uma ilha.' INVALID_ISLAND_OTHER_NAME: '&c&lErro | &7Não existe uma ilha com o nome {0}.' INVALID_ISLAND_PERMISSION: | &c&lErro | &7Não foi possível encontrar a permissão da ilha {0}. &c&lErro | &7Permissões da ilha: {1} INVALID_LEVEL: '&c&lErro | &7Nível inválido {0}.' INVALID_LIMIT: '&c&lErro | &7Limite inválido {0}.' INVALID_MATERIAL: '&c&lErro | &7Material inválido {0}.' INVALID_MATERIAL_DATA: '&c&lErro | &7Material-dados inválido {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErro | &7Missão inválida {0}.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lErro | &7Módulo inválido {0}.' INVALID_MULTIPLIER: '&c&lErro | &7Multiplicador inválido {0}.' INVALID_PAGE: '&c&lErro | &7Página inválida {0}.' INVALID_PERCENTAGE: '&c&lErro | &7A porcentagem deve estar entre 0 e 100.' INVALID_PLAYER: '&c&lErro | &7Não foi possível encontrar um jogador chamado {0}.' INVALID_RATE: | &c&lErro | &7Não foi possível encontrar uma classificação com o nome {0}. &c&lErro | &7Classificações da ilha: {1} INVALID_ROWS: '&c&lErro | &7Quantidade inválida de linhas: {0}' INVALID_ROLE: | &c&lErro | &7Não foi possível encontrar a função da ilha {0}. &c&lErro | &7Funções da ilha: {1} INVALID_SCHEMATIC: '&c&lErro | &7Não foi possível encontrar um esquema com o nome {0}.' INVALID_SETTINGS: | &c&lErro | &7Não foi possível encontrar as configurações da ilha {0}. &c&lErro | &7Configurações da ilha: {1} INVALID_SIZE: '&c&lErro | &7Tamanho inválido {0}.' INVALID_SLOT: '&c&lErro | &7Slot inválido {0}.' INVALID_TITLE: '&c&lErro | &7Título inválido inserido.' INVALID_TOGGLE_MODE: '&c&lErro | &7Não é possível alternar {0}.' INVALID_UPGRADE: | &c&lErro | &7Não foi possível encontrar uma atualização chamada {0}. &c&lErro | &7Atualizações: {1} INVALID_VISIT_LOCATION: '&c&lErro | &7Esta ilha não tem localização de visitantes.' INVALID_VISIT_LOCATION_BYPASS: '&7&oVocê tem o modo bypass, teletransportando você para a ilha...' INVALID_WARP: '&c&lErro | &7Warp inválido {0}.' INVALID_WORLD: '&c&lErro | &7Mundo inválido {0}.' INVITE_ANNOUNCEMENT: '&e&lIlha | &7{0} convidou {1} para a ilha.' INVITE_BANNED_PLAYER: '&c&lErro | &7Este jogador foi banido da ilha e não pode ser convidado.' INVITE_TO_FULL_ISLAND: '&c&lErro | &7Você não pode convidar mais membros para sua ilha.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lErro | &7Uma ilha com esse nome já existe.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBanco | &7O banco da ilha está vazio.' ISLAND_BANK_SHOW: '&e&lBanco | &7Sua ilha tem ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBanco | &7A ilha de {0} tem ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanco | &7A ilha {0} tem ${1}.' ISLAND_BEING_CALCULATED: '&c&lErro | &7Você não pode interagir com blocos quando a ilha está sendo recalculada!' ISLAND_CLOSED: '&e&lIsland | &7A ilha foi fechada com sucesso para o público.' ISLAND_CREATE_PROCESS_FAIL: '&c&lErro | &7Você já tem uma tarefa de criação de ilha em andamento.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIlha | &7Processando sua solicitação...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lVoar | &7Voar na ilha foi automaticamente &cdesabilitado&7.' ISLAND_FLY_ENABLED: '&e&lVoar | &7Voar na ilha foi automaticamente &ahabilitado&7.' ISLAND_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...' ISLAND_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...' ISLAND_HELP_FOOTER: '&e&lSkyblock &7Desenvolvido por Ome_R' ISLAND_HELP_HEADER: '&e&lSkyblock &7Lista de Comandos [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Use /is help {0} para a próxima página.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIlha | &7Limite do Banco: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lIlha | &7Blocos Limites: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIlha | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIlha | &7Limite de coop: {0}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIlha | &7Multiplicador de colheitas: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIlha | &7Multiplicador de gotas: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lIlha | &7Efeitos da Ilha: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIlha | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lIlha | Limites de &7Entidades: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIlha | &7 {0}: {1}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lIlha | &7Taxas de Geração ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIlha | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lIlha | &7Limites de Função: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIlha | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lIlha | &7Tamanho da Borda: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIlha | &7Multiplicador de Geradores: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIlha | &7Limite da Equipe: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lIlha | &7Melhorias: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIlha | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIlha | &7Limite de Warps: {0}' ISLAND_INFO_BANK: '&e&lIlha | &7Banco: {0}' ISLAND_INFO_BONUS: '&e&lIlha | &7Bônus de valor: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lIlha | &7Bônus de nível: {0}' ISLAND_INFO_CREATION_TIME: '&e&lIlha | &7Hora da criação: {0}' ISLAND_INFO_DISCORD: '&e&lIlha | &7Discord: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lIlha | &7Última atualização: {0} atrás' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIlha | &7Última atualização: &aAtualmente ativo' ISLAND_INFO_LEVEL: '&e&lIlha | &7Nível: {0}' ISLAND_INFO_LOCATION: '&e&lIlha | &7Casa: {0}' ISLAND_INFO_NAME: '&e&lIlha | &7Nome: {0}' ISLAND_INFO_OWNER: '&e&lIlha | &7Líder: {0}' ISLAND_INFO_PAYPAL: '&e&lIlha | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lIlha | &7 - {0}' ISLAND_INFO_RATE: '&e&lIlha | &7Rate: {0} &7({1}/5) - {2} avaliações totais.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: '✦' ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIlha | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIlha | &7Contagem de visitantes: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIlha | &7Valor: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIlha | &7A ilha foi aberta com sucesso ao público.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVisualizar | &7Você foi muito longe e não está mais no modo de visualização.' ISLAND_PREVIEW_CANCEL: '&e&lVisualizar | &7Você cancelou o modo de visualização.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMAR' ISLAND_PREVIEW_CANCEL_TEXT: 'CANCELAR' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lVisualizar | &7Você iniciou o modo de visualização para o esquema {0}. &e&lVisualizar | &7Digite &a&lCONFIRMAR &7para criar uma nova ilha, ou &c&lCANCELAR &7para cancelar o modo de pré-visualização. &e&lPreview | &7Você não pode sair da área da ilha, caso contrário, o modo de pré-visualização será cancelado automaticamente. ISLAND_PROTECTED: '&c&lErro | &7Esta ilha está protegida.' ISLAND_PROTECTED_OPPED: '&7&oVocê pode ignorar esta restrição usando "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lIlha | &7Membros da Ilha de {0} &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)' ISLAND_TEAM_STATUS_ONLINE: '&a(Online)' ISLAND_TEAM_STATUS_ROLES: '&e&lIlha | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Offline)' ISLAND_TOP_STATUS_ONLINE: '&a(Online)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Privado]' ISLAND_WAS_CLOSED: '&e&lIlha | &7&oA ilha em que você estava foi fechada e você foi teletransportado de volta para o spawn...' ISLAND_WORTH_ERROR: '&c&lErro | &7Ocorreu um erro inesperado ao calcular sua ilha. Entre em contato com os administradores se o problema persistir.' ISLAND_WORTH_RESULT: '&e&lIlha | &7O valor da sua ilha é {0} [Nível {1}]' ISLAND_WORTH_TIME_OUT: '&c&lErro | &7A tarefa de cálculo expirou. Tente novamente mais tarde...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou na sua ilha.' JOIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou na sua ilha.' JOIN_FULL_ISLAND: '&c&lErro | &7Esta ilha atingiu a quantidade máxima de membros permitidos.' JOIN_WHILE_IN_ISLAND: '&c&lErro | &7Você já está dentro de uma ilha.' JOINED_ISLAND: '&e&lIlha | &7Você entrou na ilha de {0}.' JOINED_ISLAND_NAME: '&e&lIlha | &7Você entrou na ilha {0}.' JOINED_ISLAND_AS_COOP: '&e&lIlha | &7Você agora é um membro cooperativo da ilha de {0}.' JOINED_ISLAND_AS_COOP_NAME: '&e&lIlha | &7Agora você é um membro cooperativo da ilha {0}.' KICK_ANNOUNCEMENT: '&e&lIlha | &7{0} foi expulso da ilha por {1}.' KICK_ISLAND_LEADER: '&c&lErro | &7Você não pode expulsar o líder da ilha, use /is admin disband em vez disso.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode expulsar jogadores com uma função de ilha inferior à sua.' LACK_CHANGE_PERMISSION: '&c&lErro | &7Você deve ter esta permissão para alterá-la para outras funções.' LAST_ROLE_DEMOTE: '&c&lErro | &7Você não pode mais rebaixar este jogador.' LAST_ROLE_PROMOTE: '&c&lErro | &7Você não pode mais promover este jogador.' LEAVE_ANNOUNCEMENT: '&e&lIlha | &7{0} deixou a ilha.' LEAVE_ISLAND_AS_LEADER: |- &c&lErro | &7Você não pode deixar sua ilha quando você a possui. &c&lErro | &7Você pode transferir a propriedade usando /is transfer. LEFT_ISLAND: '&e&lIlha | &7Você saiu da sua ilha.' LEFT_ISLAND_COOP: '&e&lIlha | &7Você não é mais um membro cooperativo da ilha de {0}.' LEFT_ISLAND_COOP_NAME: '&e&lIlha | &7Você não é mais um membro cooperativo da ilha {0}.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lErro | &7Você deve fornecer um material sólido.' MAXIMUM_LEVEL: '&c&lErro | &7O nível máximo para esta atualização é {0}.' MESSAGE_SENT: '&e&lIlha | &7A mensagem foi enviada com sucesso para {0}!' MISSION_CANNOT_COMPLETE: '&c&lErro | &7Você não pode concluir esta missão ainda.' MISSION_NO_AUTO_REWARD: '&e&lMissão | &7Você tem todos os materiais necessários para concluir {0} - use /is missions para concluir!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lErro | &7Você deve concluir {0} antes de concluir esta missão.' MISSION_STATUS_COMPLETE: '&e&lMissão | &7Alterou o status da missão {0} para concluída para {1}.' MISSION_STATUS_COMPLETE_ALL: '&e&lMissão | &7Alterou o status de todas as missões para concluídas para {0}.' MISSION_STATUS_RESET: '&e&lMissão | &7Redefiniu o status da missão {0} para {1}.' MISSION_STATUS_RESET_ALL: '&e&lMissão | &7Redefiniu o status de todas as missões para {0}.' MODULE_ALREADY_INITIALIZED: '&e&lMódulo | &7Este módulo já está carregado.' MODULE_INFO: | &e&lMódulo | &7{0} por {1} &e&lMódulo | &7&m-------------------- &e&lMódulo | &7{2} MODULE_LOADED_SUCCESS: '&e&lMódulo | &7Carregou o módulo {0} com sucesso.' MODULE_LOADED_FAILURE: '&e&lMódulo | &7Não foi possível carregar o módulo {0}. Verifique o console para obter mais informações.' MODULE_UNLOADED_SUCCESS: '&e&lMódulo | &7Descarregado o módulo com sucesso.' MODULES_LIST: '&fMódulos ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lIlha | &7{0} alterou o nome da ilha para {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lErro | &7Você não pode usar esse nome.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lErro | &7Você não pode usar nomes de jogadores como nomes de ilhas.' NAME_TOO_LONG: '&c&lErro | &7Os nomes de ilhas não podem ter mais de {0} caracteres.' NAME_TOO_SHORT: '&c&lErro | &7Os nomes de ilhas não podem ter menos de {0} caracteres.' NO_BAN_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para banir jogadores.' NO_CLOSE_BYPASS: '&c&lErro | &7Esta ilha não está aberta ao público.' NO_CLOSE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para fechar a ilha ao público.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para adicionar jogadores como membros cooperativos.' NO_DELETE_WARP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para excluir warps.' NO_DEMOTE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para rebaixar jogadores.' NO_DEPOSIT_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para depositar dinheiro no banco da ilha.' NO_DISBAND_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para dissolver sua ilha.' NO_EXPEL_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para expulsar jogadores de sua ilha.' NO_INVITE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para convidar jogadores.' NO_ISLAND_CHEST_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para acessar o baú da ilha.' NO_ISLAND_INVITE: '&c&lErro | &7Não foi possível encontrar nenhum convite desta ilha.' NO_ISLANDS_TO_PURGE: '&c&lErro | &7Não havia ilhas para expurgar.' NO_KICK_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para expulsar jogadores.' NO_MORE_DISBANDS: '&c&lErro | &7Você não pode dissolver mais nenhuma ilha.' NO_MORE_WARPS: '&c&lErro | &7Sua ilha não pode ter mais nenhuma teletransportação.' NO_NAME_PERMISSION: '&c&lErro | &7Você não pode alterar o nome da sua ilha.' NO_OPEN_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para abrir a ilha ao público.' NO_PERMISSION_CHECK_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para obter informações sobre permissões.' NO_PROMOTE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para promover jogadores.' NO_RANKUP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para aumentar a classificação.' NO_RATINGS_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para verificar as classificações.' NO_SET_BIOME_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o bioma da ilha.' NO_SET_DISCORD_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o discord da ilha.' NO_SET_HOME_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para definir o local de teletransporte da ilha.' NO_SET_PAYPAL_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o e-mail do PayPal da ilha.' NO_SET_ROLE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para definir funções para os jogadores.' NO_SET_SETTINGS_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar as configurações da ilha.' NO_SET_WARP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para poder definir teletransportes de ilha.' NO_TRANSFER_PERMISSION: '&c&lErro | &7Você deve ser o líder da ilha para poder transferir a liderança.' NO_UNCOOP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para remover jogadores de serem membros cooperativos.' NO_UPGRADE_PERMISSION: '&c&lErro | &7Você não tem permissão para fazer upgrade para outro nível.' NO_WITHDRAW_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para sacar dinheiro do banco da ilha.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lErro | &7Você não tem dinheiro suficiente para depositar {0} dólares no banco da sua ilha.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lErro | &7Você não tem dinheiro suficiente.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lErro | &7Você não tem dinheiro suficiente para usar os teleportes de ilha.' OPEN_MENU_WHILE_SLEEPING: '&7&oVocê está cansado demais para interagir com os menus, não acha?' PANEL_TOGGLE_OFF: |- &e&lPainel | &7Painel da ilha desativado &cOFF&7. &e&lPainel | &7Executar /is te teleportará para a ilha. PANEL_TOGGLE_ON: |- &e&lPainel | &7Painel da ilha ativado &aON&7. &e&lPainel | &7Executar /is abrirá o painel para você. PERMISSION_CHANGED: '&e&lIlha | &7Atualizada com sucesso a permissão {0} da ilha de {1}.' PERMISSION_CHANGED_NAME: '&e&lIlha | &7Atualizada com sucesso a permissão {0} da ilha {1}.' PERMISSION_CHANGED_ALL: '&e&lIlha | &7Atualizada com sucesso a permissão {0} para todas as ilhas.' PERSISTENT_DATA_EMPTY: '&c&lErro | &7Nenhum dado foi encontrado para sua consulta.' PERSISTENT_DATA_MODIFY: '&e&lDados | &7Definidos com sucesso os dados para {0} com {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lDados | &7Dados de {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Dados removidos com sucesso para {0} do caminho {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIlha | &7Redefiniu com sucesso todas as permissões para {0} para os valores padrão!' PERMISSIONS_RESET_ROLES: '&e&lIlha | &7Redefiniu com sucesso todas as permissões da ilha para os valores padrão!' PLACEHOLDER_NO: 'Não' PLACEHOLDER_YES: 'Sim' PLAYER_ALREADY_BANNED: '&c&lErro | &7Este jogador já foi banido.' PLAYER_ALREADY_COOP: '&c&lErro | &7Este jogador já é cooperativo.' PLAYER_ALREADY_IN_ISLAND: '&c&lErro | &7Este jogador já está dentro de uma ilha.' PLAYER_ALREADY_IN_ROLE: '&c&lErro | &7{0} já é um {1}.' PLAYER_EXPEL_BYPASS: '&c&lErro | &7Este usuário não pode ser expulso da ilha.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou no servidor.' PLAYER_NOT_BANNED: '&c&lErro | &7Este jogador não está banido.' PLAYER_NOT_COOP: '&c&lErro | &7Este jogador não é cooperativo.' PLAYER_NOT_INSIDE_ISLAND: '&c&lErro | &7Este jogador não está dentro da sua ilha.' PLAYER_NOT_ONLINE: '&c&lErro | &7Este jogador não está online!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lIlha | &7{0} saiu do servidor.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode promover jogadores com uma função de ilha inferior à sua.' PROMOTED_MEMBER: '&e&lIlha | &7Você promoveu {0} para um {1} na ilha dele.' PURGE_CLEAR: '&e&lIlha | &7Todas as ilhas na fila para serem expurgadas foram limpas com sucesso.' PURGED_ISLANDS: |- &e&lIlha | &7{0} ilhas serão purgadas quando o servidor reiniciar. &e&lIlha | &7Você pode cancelar a qualquer momento usando /is admin purge cancel. RANKUP_SUCCESS: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para a ilha de {1}.' RANKUP_SUCCESS_ALL: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para todas as ilhas.' RANKUP_SUCCESS_NAME: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para {1}.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIlha | &7{0} classificou sua ilha {1} de 5!.' RATE_CHANGE_OTHER: '&e&lIlha | &7Você alterou a classificação de {0} para {1}.' RATE_OWN_ISLAND: '&c&lErro | &7Você não pode classificar sua própria ilha.' RATE_REMOVE_ALL: '&e&lIlha | &7Todas as classificações de {0} foram removidas com sucesso.' RATE_REMOVE_ALL_ISLANDS: '&e&lIlha | &7Todas as classificações de todas as ilhas foram removidas com sucesso.' RATE_SUCCESS: '&e&lIlha | &7Você classificou esta ilha com {0} estrelas!' REACHED_BLOCK_LIMIT: '&e&lAtualizações | &7Você atingiu o limite da ilha para o bloco {0}.' REACHED_ENTITY_LIMIT: '&e&lAtualizações | &7Você atingiu o limite da ilha para a entidade {0}.' RECALC_ALREADY_RUNNING: '&c&lErro | &7Sua ilha já está sendo recalculada.' RECALC_ALREADY_RUNNING_OTHER: '&c&lErro | &7Esta ilha já está sendo recalculada.' RECALC_ALL_ISLANDS: '&e&lIlha | &7Recalculando todas as ilhas...' RECALC_ALL_ISLANDS_DONE: '&e&lIlha | &7Concluída com sucesso a recalculação de todas as ilhas.' RECALC_PROCCESS_REQUEST: '&e&lIlha | &7Processando sua solicitação...' RELOAD_COMPLETED: '&e&lIlha | &7Recarregamento concluído!' RELOAD_PROCCESS_REQUEST: '&e&lIlha | &7Começando a recarregar as configurações...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lIlha | &7{0} revogou o convite de {1} para a ilha.' RESET_WORLD_SUCCEED: '&e&lIlha | &7Redefiniu com sucesso o mundo {0} para a ilha de {1}.' RESET_WORLD_SUCCEED_ALL: '&e&lIlha | &7Redefinido com sucesso o mundo {0} para todas as ilhas.' RESET_WORLD_SUCCEED_NAME: '&e&lIlha | &7Redefinido com sucesso o mundo {0} para {1}.' SAME_NAME_CHANGE: '&c&lErro | &7Você deve digitar um nome diferente do nome atual da sua ilha.' SCHEMATIC_LEFT_SELECT: '&e&lEsquemas | &7Posição selecionada nº 2 ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lErro | &7Você não selecionou duas posições.' SCHEMATIC_PROCCESS_REQUEST: '&e&lEsquemas | &7Processando sua solicitação...' SCHEMATIC_READY_TO_CREATE: | &e&lschematic | &7Você selecionou duas posições. Execute /is admin schematic para criar um novo esquema. &e&lschematic | &7Certifique-se de estar no local de teleportação ao executar o comando. SCHEMATIC_RIGHT_SELECT: '&e&lschematic | &7Posição selecionada nº 1 ({0})' SCHEMATIC_SAVED: '&e&lschematic | &7Esquema salvo com sucesso!' SELF_ROLE_CHANGE: '&c&lErro | &7Você não pode alterar sua função.' SET_UPGRADE_LEVEL: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para a ilha de {1}.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para {1}.' SET_WARP: '&e&lIlha | &7Criou com sucesso um novo warp em {0}.' SET_WARP_OUTSIDE: '&c&lErro | &7Você não pode definir warps fora da sua ilha.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha de {1}.' SETTINGS_UPDATED_NAME: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha {1}.' SETTINGS_UPDATED_ALL: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para todas as ilhas.' SIZE_BIGGER_MAX: '&c&lErro | &7Você não pode definir um tamanho maior que o tamanho máximo da ilha.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Teletransportado com sucesso {0} para spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Atualizado com sucesso o local de spawn para {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lAtualizações | &7Todos os valores de atualização da ilha de {0} foram sincronizados com sucesso.' SYNC_UPGRADES_ALL: '&e&lAtualizações | &7Todos os valores de atualização de todas as ilhas foram sincronizados com sucesso.' SYNC_UPGRADES_NAME: '&e&lAtualizações | &7Todos os valores de atualização de {0} foram sincronizados com sucesso.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lErro | &7Você não está dentro da sua ilha.' TELEPORT_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode se teletransportar para fora do seu alcance de proteção.' TELEPORT_WARMUP: '&7&oVocê será teletransportado em {0}... Não se mova!' TELEPORT_WARMUP_CANCEL: '&7&oVocê se moveu e então o teletransporte foi cancelado.' TITLE_SENT: '&e&lIlha | &7Enviado com sucesso {0} o título!' TELEPORTED_FAILED: '&e&lIlha | &7Parece que esta ilha não tem blocos seguros. Entre em contato com um membro da equipe.' TELEPORTED_SUCCESS: '&e&lIlha | &7Você foi teletransportado para sua ilha.' TELEPORTED_TO_WARP: '&e&lIlha | &7Teletransportado com sucesso para esta dobra de ilha.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIlha | &7O jogador {0} teletransportou-se para a ilha warp {1}.' TOGGLED_BYPASS_OFF: '&e&lIgnorar | &7Modo de desvio alternado &cOFF&7.' TOGGLED_BYPASS_ON: '&e&lIgnorar | &7Modo de desvio alternado &aON&7.' TOGGLED_FLY_OFF: '&e&lVoar | &7Voar ilha alternado &cOFF&7.' TOGGLED_FLY_ON: '&e&lVoar | &7Voar ilha alternado &aON&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lEsquemas | &7Alternando modo esquemático &cOFF&7.' TOGGLED_SCHEMATIC_ON: |- &e&lschematic | &7Modo de esquemas ativado &aON&7. &e&lschematic | &7Selecione uma área usando um machado dourado. TOGGLED_SPY_OFF: '&e&lSpy | &7Alternado bate-papo espião &cOFF&7.' TOGGLED_SPY_ON: '&e&lSpy | &7Alternado bate-papo espião &aON&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Alternando empilhador de blocos &cOFF&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Alternando empilhador de blocos &aON&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Alternando bate-papo da equipe &cOFF&7.' TOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Alternando bate-papo da equipe &aON&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lBorder | &7Alternando borda do mundo &cOFF&7.' TOGGLED_WORLD_BORDER_ON: '&e&lBorder | &7Alternando a fronteira mundial &aON&7.' TRANSFER_ADMIN: '&e&lIlha | &7Você transferiu a liderança de {0} para {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lErro | &7{0} já é o líder de sua ilha.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lErro | &7Estes jogadores não estão nas mesmas ilhas.' TRANSFER_ADMIN_NOT_LEADER: '&c&lErro | &7Este jogador não é líder de nenhuma ilha.' TRANSFER_ALREADY_LEADER: '&c&lErro | &7Você já é o líder desta ilha.' TRANSFER_BROADCAST: '&e&lIlha | &7A liderança da ilha foi transferida para {0}.' UNBAN_ANNOUNCEMENT: '&e&lIlha | &7{0} foi DESBANIDO da ilha por {1}.' UNCOOP_ANNOUNCEMENT: '&e&lIlha | &7{0} removeu {1} de ser um membro cooperativo.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIlha | &7Não há membros da ilha online e, portanto, você foi descoopado automaticamente.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIlha | &7{0} saiu do jogo e não é mais um membro cooperativo.' UNIGNORED_ISLAND: A ilha de '&e&lIlha | &7{0}' agora não é mais ignorada das ilhas principais.' UNIGNORED_ISLAND_NAME: '&e&lIlha | &7A ilha {0} agora não é mais ignorada das ilhas principais.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIlha | &7&oParece que este warp não é seguro. Tente outro warp.' UPDATED_PERMISSION: '&e&lIlha | &7Permissões atualizadas para {0}.' UPDATED_SETTINGS: '&e&lIlha | &7Configurações da ilha [{0}] atualizado.' UPGRADE_COOLDOWN_FORMAT: '&c&lErro | &7Você só pode atualizar novamente em {0}.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lErro | &7Você não pode usar esse comando em outras ilhas.' WARP_ALREADY_EXIST: '&c&lErro | &7Já existe um warp com este nome.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lWarps | &7Digite uma nova lore (digite "-cancel" para cancelar): &e&lWarps | &7Você pode separar linhas usando "\n". WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Digite um nome (digite "-cancel" para cancelar):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Digite um novo tipo de material (digite "-cancel" para cancelar):' WARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7O ícone da categoria foi atualizado com sucesso.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lErro | &7Os nomes das categorias de warp não podem estar vazios.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lErro | Os nomes de categorias do Warp não podem ter mais de 255 caracteres.' WARP_CATEGORY_SLOT: '&e&lWarps | &7Digite um novo slot (digite "-cancel" para cancelar):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lErro | &7Este slot já foi ocupado por outra categoria.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7O slot da categoria foi alterado com sucesso para {0}.' WARP_CATEGORY_RENAME: '&e&lWarps | &7Digite um novo nome (digite "-cancel" para cancelar):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lErro | &7Este nome já foi ocupado por outra categoria.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Categoria renomeada com sucesso para {0}.' WARP_ICON_NEW_LORE: | &e&lWarps | &7Digite um novo lore (Digite "-cancel" para cancelar): &e&lWarps | &7Você pode separar as linhas usando "\n". WARP_ICON_NEW_NAME: '&e&lWarps | &7Digite um nome (digite "-cancel" para cancelar):' WARP_ICON_NEW_TYPE: '&e&lWarps | &7Digite um novo tipo de material (digite "-cancel" para cancelar):' WARP_ICON_UPDATED: '&e&lWarps | &7O ícone do warp foi atualizado com sucesso.' WARP_ILLEGAL_NAME: '&c&lErro | &7Os nomes do warp não podem estar vazios.' WARP_LOCATION_UPDATE: '&e&lWarps | &7Atualizou com sucesso a localização do warp para a sua localização.' WARP_NAME_TOO_LONG: '&c&lErro | Os nomes do warp não podem ter mais de 255 caracteres.' WARP_PUBLIC_UPDATE: '&e&lWarps | &7Abriu o warp com sucesso para o público.' WARP_PRIVATE_UPDATE: '&e&lWarps | &7Fechou o warp com sucesso para o público.' WARP_RENAME: '&e&lWarps | &7Digite um novo nome (digite "-cancel" para cancelar):' WARP_RENAME_ALREADY_EXIST: '&c&lErro | &7Este nome já foi usado por outro warp.' WARP_RENAME_SUCCESS: '&e&lWarps | &7Renomeou o warp com sucesso para {0}.' WITHDRAW_ALL_MONEY: |- &e&lBanco | &7O banco da ilha tem apenas {0} dólares dentro dele. &e&lBanco | &7&oRetirando todo o dinheiro..." WITHDRAW_ANNOUNCEMENT: '&e&lBanco | &7{0} retirou ${1} do banco da ilha!' WITHDRAW_ERROR: '&c&lErro | &7{0}.' WITHDRAWN_MONEY: '&e&lBanco | &7Você sacou ${0} do banco da ilha de {1}!' WITHDRAWN_MONEY_NAME: '&e&lBanco | &7Você sacou ${0} do banco da ilha de {1}!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lWorlds | &7O mundo {0} ainda não está desbloqueado!' ================================================ FILE: src/main/resources/lang/ru-RU.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # You can find a tutorial about configuring messages here: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lОстров | &7Успешно добавлен игрок {0} на остров {1}.' ADMIN_ADD_PLAYER_NAME: '&e&lОстров | &7Успешно добавлен игрок {0} на остров {1}.' ADMIN_DEPOSIT_MONEY: '&e&lБанк | &7Вы внесли ${0} на банковский счет острова {1}.' ADMIN_DEPOSIT_MONEY_NAME: '&e&lБанк | &7Вы внесли ${0} на банковский счет острова {1}.' ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Разработано Ome_R' ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Список команд администратора [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Используйте /is admin {0} для следующей страницы.' ALREADY_IN_ISLAND: '&c&lОшибка | &7Вы уже на острове.' ALREADY_IN_ISLAND_OTHER: '&c&lОшибка | &7Этот игрок уже является членом вашего острова.' BAN_ANNOUNCEMENT: '&e&lОстров | &7{0} был ЗАБАНЕН на острове {1}.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lОшибка | &7Вы можете банить только игроков с более низкой ролью на острове.' BANK_DEPOSIT_CUSTOM: '&e&lБанк | &7Введите сумму, которую хотите внести:' BANK_DEPOSIT_COMPLETED: 'Внесение завершено' BANK_LIMIT_EXCEED: '&c&lОшибка | &7Вы превысили лимит банка.' BANK_WITHDRAW_CUSTOM: '&e&lБанк | &7Введите сумму, которую хотите снять:' BANK_WITHDRAW_COMPLETED: 'Снятие завершено' BANNED_FROM_ISLAND: '&c&lОшибка | &7Вы забанены на этом острове.' BLOCK_COUNT_CHECK: '&e&lОстров | &7На этом острове x{0} {1}.' BLOCK_COUNTS_CHECK: | &e&lОстров | &7На этом острове следующие блоки: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lОстров | &7На этом острове нет отслеживаемых блоков.' BLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}' BLOCK_LEVEL: '&e&lУровень | &7Уровень блока {0} составляет {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lУровень | &7Блок {0} бесполезен.' BLOCK_VALUE: '&e&lЦена | &7Блок {0} стоит {1}.' BLOCK_VALUE_WORTHLESS: '&e&lЦена | &7Блок {0} бесполезен.' BONUS_SYNC_ALL: '&e&lОстров | &7Успешно синхронизирован бонус острова для всех островов.' BONUS_SYNC_NAME: '&e&lОстров | &7Успешно синхронизирован бонус острова для {0}.' BONUS_SYNC: '&e&lОстров | &7Успешно синхронизирован бонус острова для острова {0}.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Синий' BORDER_PLAYER_COLOR_NAME_RED: 'Красный' BORDER_PLAYER_COLOR_NAME_GREEN: 'Зеленый' BORDER_PLAYER_COLOR_UPDATED: '&e&lГраница | &7Успешно изменен цвет вашей личной границы на {0}.' BUILD_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не можете строить за пределами вашей защитной зоны.' CANNOT_SET_ROLE: '&c&lОшибка | &7Вы не можете установить роль игрока на {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lОшибка | &7Вы можете изменять права только для роли острова ниже вашей.' CHANGED_BANK_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит банка для острова {0}.' CHANGED_BANK_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит банка для всех островов.' CHANGED_BANK_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит банка для {0}.' CHANGED_BIOME: '&e&lОстров | &7Успешно изменен биом на {0}. Вам может понадобиться переподключиться к серверу, чтобы увидеть изменения.' CHANGED_BIOME_ALL: '&e&lОстров | &7Успешно изменен биом на {0} для всех островов.' CHANGED_BIOME_NAME: '&e&lОстров | &7Успешно изменен биом на {0} для острова {1}.' CHANGED_BIOME_OTHER: '&e&lОстров | &7Успешно изменен биом на {0} для острова {1}.' CHANGED_BLOCK_AMOUNT: '&e&lБлоки | &7Успешно изменено количество блоков на {0} до {1}.' CHANGED_BLOCK_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для острова {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для всех островов.' CHANGED_BLOCK_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для {1}.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для острова {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для всех островов.' CHANGED_CHEST_SIZE_NAME: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для {2}.' CHANGED_COOP_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит игроков-кооператоров для острова {0}.' CHANGED_COOP_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит игроков-кооператоров для всех островов.' CHANGED_COOP_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит игроков-кооператоров для {0}.' CHANGED_CROP_GROWTH: '&e&lУлучшения | &7Успешно обновлен множитель роста культур для острова {0}.' CHANGED_CROP_GROWTH_ALL: '&e&lУлучшения | &7Успешно обновлен множитель роста культур для всех островов.' CHANGED_CROP_GROWTH_NAME: '&e&lУлучшения | &7Успешно обновлен множитель роста культур для {0}.' CHANGED_DISCORD: '&e&lОстров | &7Успешно изменен Discord острова на {0}.' CHANGED_ENTITY_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит {0} сущностей для острова {1}.' CHANGED_ENTITY_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит {0} сущностей для всех островов.' CHANGED_ENTITY_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит {0} сущностей для {1}.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lУлучшения | &7Успешно обновлен уровень эффекта острова {0} для острова {1}.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lУлучшения | &7Успешно обновлен уровень эффекта острова {0} для всех островов.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lУлучшения | &7Успешно обновлен уровень эффекта острова {0} для {1}.' CHANGED_ISLAND_SIZE: '&e&lУлучшения | &7Успешно обновлен размер острова {0}.' CHANGED_ISLAND_SIZE_ALL: '&e&lУлучшения | &7Успешно обновлен размер острова для всех островов.' CHANGED_ISLAND_SIZE_NAME: '&e&lУлучшения | &7Успешно обновлен размер острова для {0}.' CHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oИгроки могут строить за пределами своего острова, поэтому размер острова не имеет значения. Вы можете отключить эту функцию в конфигурации, чтобы размер острова снова имел значение.' CHANGED_LANGUAGE: '&e&lЯзык | &7Успешно изменен ваш язык на русский.' CHANGED_MOB_DROPS: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для острова {0}.' CHANGED_MOB_DROPS_ALL: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для всех островов.' CHANGED_MOB_DROPS_NAME: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для {0}.' CHANGED_NAME: '&e&lОстров | &7Вы изменили название вашего острова на {0}&7.' CHANGED_NAME_OTHER: '&e&lОстров | &7Вы изменили название острова {0} на {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lОстров | &7Вы изменили имя {0}&7 на {1}&7.' CHANGED_PAYPAL: '&e&lОстров | &7Успешно изменен PayPal острова на {0}.' CHANGED_ROLE_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит роли {0} для острова {1}.' CHANGED_ROLE_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит роли {0} для всех островов.' CHANGED_ROLE_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит роли {0} для {1}.' CHANGED_SPAWNER_RATES: '&e&lУлучшения | &7Успешно обновлен множитель ставок спавнера для острова {0}.' CHANGED_SPAWNER_RATES_ALL: '&e&lУлучшения | &7Успешно обновлен множитель ставок спавнера для всех островов.' CHANGED_SPAWNER_RATES_NAME: '&e&lУлучшения | &7Успешно обновлен множитель ставок спавнера для {0}.' CHANGED_TEAM_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит команды для острова {0}.' CHANGED_TEAM_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит команды для всех островов.' CHANGED_TEAM_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит команды для {0}.' CHANGED_TELEPORT_LOCATION: '&e&lОстров | &7Успешно обновлено местоположение телепорта.' CHANGED_WARPS_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит варпов для острова {0}.' CHANGED_WARPS_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит варпов для всех островов.' CHANGED_WARPS_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит варпов для {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'количество' COMMAND_ARGUMENT_BIOME: 'биом' COMMAND_ARGUMENT_BORDER_COLOR: 'цвет-границы' COMMAND_ARGUMENT_COMMAND: 'команда...' COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'дискорд...' COMMAND_ARGUMENT_EFFECT: 'эффект-зелья' COMMAND_ARGUMENT_EMAIL: 'email' COMMAND_ARGUMENT_ENTITY: 'сущность' COMMAND_ARGUMENT_ISLAND_NAME: 'название-острова' COMMAND_ARGUMENT_ISLAND_ROLE: 'роль-острова' COMMAND_ARGUMENT_LEADER: 'лидер' COMMAND_ARGUMENT_LEVEL: 'уровень' COMMAND_ARGUMENT_LIMIT: 'лимит' COMMAND_ARGUMENT_MATERIAL: 'материал' COMMAND_ARGUMENT_MENU: 'название-меню' COMMAND_ARGUMENT_MESSAGE: 'сообщение...' COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: 'название-миссии' COMMAND_ARGUMENT_MODULE_NAME: 'название-модуля' COMMAND_ARGUMENT_MULTIPLIER: 'множитель' COMMAND_ARGUMENT_NAME: 'имя' COMMAND_ARGUMENT_NEW_LEADER: 'новый-лидер' COMMAND_ARGUMENT_PAGE: 'страница' COMMAND_ARGUMENT_PATH: 'путь' COMMAND_ARGUMENT_PERMISSION: 'разрешение' COMMAND_ARGUMENT_PLAYER_NAME: 'имя-игрока' COMMAND_ARGUMENT_PRIVATE: 'приватный' COMMAND_ARGUMENT_RATING: 'рейтинг' COMMAND_ARGUMENT_ROWS: 'строки' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'название-схемы' COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'настройки' COMMAND_ARGUMENT_SIZE: 'размер' COMMAND_ARGUMENT_TIME: 'время' COMMAND_ARGUMENT_TITLE_DURATION: 'длительность' COMMAND_ARGUMENT_TITLE_FADE_IN: 'появление' COMMAND_ARGUMENT_TITLE_FADE_OUT: 'исчезновение' COMMAND_ARGUMENT_UPGRADE_NAME: 'название-улучшения' COMMAND_ARGUMENT_VALUE: 'значение' COMMAND_ARGUMENT_WARP_NAME: 'название-варпа' COMMAND_ARGUMENT_WARP_CATEGORY: 'категория-варпа' COMMAND_ARGUMENT_WORLD: 'мир' COMMAND_COOLDOWN_FORMAT: '&c&lОшибка | &7Вы можете использовать команду только через {0}.' COMMAND_DESCRIPTION_ACCEPT: 'Принять приглашение от игрока.' COMMAND_DESCRIPTION_ADMIN: 'Использовать команды администратора.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Добавить пользователя на остров.' COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Увеличить лимит блоков для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Добавить бонус игроку.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Увеличить лимит игроков-кооператоров для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Увеличить множитель роста культур для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Добавить эффект острова для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Увеличить лимит сущностей для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Добавить процент материала для генератора булыжника.' COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Увеличить множитель дропа мобов для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Расширить размер острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Увеличить множитель ставок спавнера для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Увеличить лимит участников для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Увеличить лимит варпов для острова.' COMMAND_DESCRIPTION_ADMIN_BONUS: 'Предоставить бонус игроку.' COMMAND_DESCRIPTION_ADMIN_BYPASS: 'Включить/выключить режим обхода.' COMMAND_DESCRIPTION_ADMIN_CHEST: 'Открыть сундук острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Очистить ставки генератора для конкретного острова.' COMMAND_DESCRIPTION_ADMIN_CLOSE: 'Закрыть остров для публики.' COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Выполнить команду для всех членов островов.' COMMAND_DESCRIPTION_ADMIN_COUNT: 'Проверить количество блоков на конкретном острове.' COMMAND_DESCRIPTION_ADMIN_DATA: 'Взаимодействовать с постоянными данными игроков или островов.' COMMAND_DESCRIPTION_ADMIN_DEBUG: 'Включить/выключить вывод отладки.' COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Удалить варп для острова.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Понизить участника на острове другого игрока.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Внести деньги в банк острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Расформировать остров другого игрока навсегда.' COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Выдать расформирования игроку.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Игнорировать остров в списке лучших островов.' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Присоединиться к острову без приглашения.' COMMAND_DESCRIPTION_ADMIN_KICK: 'Выгнать игрока с его острова.' COMMAND_DESCRIPTION_ADMIN_MODULES: 'Управлять модулями плагина.' COMMAND_DESCRIPTION_ADMIN_MISSION: 'Изменить статус миссии для игрока.' COMMAND_DESCRIPTION_ADMIN_MSG: 'Отправить игроку сообщение без префиксов.' COMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Отправить сообщение всем участникам острова без префиксов.' COMMAND_DESCRIPTION_ADMIN_NAME: 'Изменить имя острова.' COMMAND_DESCRIPTION_ADMIN_OPEN: 'Открыть остров для публики.' COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Открыть пользовательское меню для игрока.' COMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Повысить участника на острове другого игрока.' COMMAND_DESCRIPTION_ADMIN_PURGE: 'Очистить острова.' COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Повысить уровень улучшения для острова.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Пересчитать стоимость острова.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Перезагрузить все настройки и задачи плагина.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Удалить лимит блоков с острова.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Удалить все оценки, выставленные игроком.' COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Сбросить мир для острова.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Создать схемы для плагина.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Установить биом для острова.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Установить количество блоков в конкретном месте.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Установить лимит блоков для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Установить количество рядов в сундуке острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Установить лимит кооператоров для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Установить множитель роста культур для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Установить количество расформирований для игрока.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Установить уровень эффекта острова для другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Установить лимит сущностей для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Передать остров другому игроку.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Установить множитель дропа мобов для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Установить необходимую роль для разрешения для всех островов.' COMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Установить рейтинг другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Установить лимит роли для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Настроить параметры для конкретного острова.' COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Изменить процент материала для генератора булыжника.' COMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Изменить размер острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Установить место спавна для сервера.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Установить множитель ставок спавнера для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Установить лимит участников для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Установить уровень улучшения для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Установить лимит варпов для острова.' COMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Открыть редактор настроек плагина.' COMMAND_DESCRIPTION_ADMIN_SHOW: 'Получить информацию об острове.' COMMAND_DESCRIPTION_ADMIN_SPAWN: 'Телепортироваться к месту спавна.' COMMAND_DESCRIPTION_ADMIN_SPY: 'Включить/выключить режим шпионства в чате.' COMMAND_DESCRIPTION_ADMIN_STATS: 'Показать статистику о плагине.' COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Синхронизировать бонус острова с генерируемыми мирами.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Синхронизировать значения улучшений для острова.' COMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Телепортироваться к другим островам.' COMMAND_DESCRIPTION_ADMIN_TITLE: 'Отправить игроку титул.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Отправить титул всем участникам острова.' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Удалить игнорирование острова из списка лучших.' COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Разблокировать мир для острова.' COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Снять деньги с банка острова другого игрока.' COMMAND_DESCRIPTION_BALANCE: 'Проверить количество денег в банке острова.' COMMAND_DESCRIPTION_BAN: 'Забанить игрока на своем острове.' COMMAND_DESCRIPTION_BANK: 'Открыть банк острова.' COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: 'Изменить биом острова.' COMMAND_DESCRIPTION_BORDER: 'Изменить цвет границы островов.' COMMAND_DESCRIPTION_CHEST: 'Открыть сундук острова.' COMMAND_DESCRIPTION_CLOSE: 'Закрыть остров для публики.' COMMAND_DESCRIPTION_COOP: 'Добавить игрока в кооперацию на вашем острове.' COMMAND_DESCRIPTION_COOPS: 'Открыть меню кооперации.' COMMAND_DESCRIPTION_COUNTS: 'Посмотреть количество блоков на вашем острове.' COMMAND_DESCRIPTION_CREATE: 'Создать новый остров.' COMMAND_DESCRIPTION_DEL_WARP: 'Удалить варп острова.' COMMAND_DESCRIPTION_DEMOTE: 'Понизить участника на вашем острове.' COMMAND_DESCRIPTION_DEPOSIT: 'Внести деньги с личного счета в банк острова.' COMMAND_DESCRIPTION_DISBAND: 'Расформировать свой остров навсегда.' COMMAND_DESCRIPTION_EXPEL: 'Выгнать посетителя с вашего острова.' COMMAND_DESCRIPTION_FLY: 'Включить/выключить полет на острове.' COMMAND_DESCRIPTION_HELP: 'Список всех команд.' COMMAND_DESCRIPTION_INVITE: 'Пригласить игрока на ваш остров.' COMMAND_DESCRIPTION_KICK: 'Выгнать игрока с вашего острова.' COMMAND_DESCRIPTION_LANG: 'Изменить личный язык.' COMMAND_DESCRIPTION_LEAVE: 'Покинуть свой остров.' COMMAND_DESCRIPTION_MEMBERS: 'Открыть меню участников.' COMMAND_DESCRIPTION_MISSION: 'Выполнить миссию.' COMMAND_DESCRIPTION_MISSIONS: 'Открыть меню миссий.' COMMAND_DESCRIPTION_NAME: 'Изменить имя вашего острова.' COMMAND_DESCRIPTION_OPEN: 'Открыть остров для публики.' COMMAND_DESCRIPTION_PANEL: 'Открыть панель острова.' COMMAND_DESCRIPTION_PARDON: 'Снять бан с игрока на вашем острове.' COMMAND_DESCRIPTION_PERMISSIONS: 'Получить все разрешения для роли острова.' COMMAND_DESCRIPTION_PROMOTE: 'Повысить участника на вашем острове.' COMMAND_DESCRIPTION_RANKUP: 'Повысить уровень улучшения.' COMMAND_DESCRIPTION_RATE: 'Оценить остров.' COMMAND_DESCRIPTION_RATINGS: 'Показать все оценки островов.' COMMAND_DESCRIPTION_SETTINGS: 'Открыть меню настроек.' COMMAND_DESCRIPTION_RECALC: 'Пересчитать стоимость острова.' COMMAND_DESCRIPTION_SET_DISCORD: 'Установить Discord для выплат острова.' COMMAND_DESCRIPTION_SET_PAYPAL: 'Установить электронную почту PayPal для выплат острова.' COMMAND_DESCRIPTION_SET_ROLE: 'Изменить роль игрока на вашем острове.' COMMAND_DESCRIPTION_SET_TELEPORT: 'Изменить место телепортации вашего острова.' COMMAND_DESCRIPTION_SET_WARP: 'Создать новый варп для острова.' COMMAND_DESCRIPTION_SHOW: 'Получить информацию об острове.' COMMAND_DESCRIPTION_TEAM: 'Получить информацию о статусе участников острова.' COMMAND_DESCRIPTION_TEAM_CHAT: 'Включить/выключить режим командного чата.' COMMAND_DESCRIPTION_TELEPORT: 'Телепортироваться на свой остров.' COMMAND_DESCRIPTION_TOGGLE: 'Включить/выключить границы острова и размещение сложенных блоков.' COMMAND_DESCRIPTION_TOP: 'Открыть панель лучших островов.' COMMAND_DESCRIPTION_TRANSFER: 'Передать руководство вашим островом.' COMMAND_DESCRIPTION_UNCOOP: 'Удалить игрока из кооперации на вашем острове.' COMMAND_DESCRIPTION_UPGRADE: 'Открыть панель улучшений.' COMMAND_DESCRIPTION_VALUE: 'Получить стоимость блока.' COMMAND_DESCRIPTION_VALUES: 'Открыть меню значений.' COMMAND_DESCRIPTION_VISIT: 'Телепортироваться к месту посетителей острова.' COMMAND_DESCRIPTION_VISITORS: 'Открыть меню посетителей.' COMMAND_DESCRIPTION_WARP: 'Телепортироваться к варпу острова.' COMMAND_DESCRIPTION_WARPS: 'Открыть меню варпов.' COMMAND_DESCRIPTION_WITHDRAW: 'Снять деньги из банка вашего острова на личный счет.' COMMAND_USAGE: '&cИспользование: /{0}' COOP_ANNOUNCEMENT: '&e&lОстров | &7{0} добавил {1} в качестве кооператора.' COOP_BANNED_PLAYER: '&c&lОшибка | &7Этот игрок забанен на острове и не может быть кооператором.' COOP_LIMIT_EXCEED: '&c&lОшибка | &7Вы достигли максимального количества кооператоров на острове.' CREATE_ISLAND: '&e&lОстров | &7Создан новый остров в {0} за {1}мс.' CREATE_ISLAND_FAILURE: '&c&lОшибка | &7Произошла ошибка при создании вашего острова. Пожалуйста, свяжитесь с администратором.' CREATE_WORLD_FAILURE: '&c&lОшибка | &7Произошла ошибка при генерации вашего мира. Пожалуйста, свяжитесь с администратором.' DEBUG_MODE_DISABLED: '&e&lОтладка | &7Режим отладки отключен.' DEBUG_MODE_ENABLED: '&e&lОтладка | &7Режим отладки включен.' DEBUG_MODE_FILTER_ADD: '&e&lОтладка | &7Фильтр отладки {0} включен.' DEBUG_MODE_FILTER_CLEAR: '&e&lОтладка | &7Все фильтры отладки отключены.' DEBUG_MODE_FILTER_REMOVE: '&e&lОтладка | &7Фильтр отладки {0} отключен.' DELETE_WARP: '&e&lОстров | &7Вы удалили варп {0}.' DELETE_WARP_SIGN_BROKE: '&7&oСуществует знак для этого варпа, он был сломан...' DEMOTE_LEADER: '&c&lОшибка | &7Вы не можете понизить лидеров острова.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lОшибка | &7Вы можете понизить только игроков с более низкой ролью, чем ваша.' DEMOTED_MEMBER: '&e&lОстров | &7Вы понизили {0} до роли {1} на его острове.' DEPOSIT_ANNOUNCEMENT: '&e&lБанк | &7{0} внес ${1} в банк острова!' DEPOSIT_ERROR: '&c&lОшибка | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не можете разрушать за пределами своей зоны защиты.' DISBAND_ANNOUNCEMENT: '&e&lОстров | &7Ваш остров был расформирован {0}.' DISBAND_GIVE: '&e&lОстров | &7Вы получили {0} расформирований.' DISBAND_GIVE_ALL: '&e&lОстров | &7Вы выдали {0} расформирований всем игрокам.' DISBAND_GIVE_OTHER: '&e&lОстров | &7Вы выдали {0} расформирований {1}.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oВаш остров был расформирован, и ${0} долларов были возвращены на ваш счет из банка острова.' DISBAND_SET: '&e&lОстров | &7Ваше количество расформирований было установлено на {0}.' DISBAND_SET_ALL: '&e&lОстров | &7Вы установили количество расформирований всех игроков на {0}.' DISBAND_SET_OTHER: '&e&lОстров | &7Вы установили количество расформирований {0} на {1}.' DISBANDED_ISLAND: '&e&lОстров | &7Вы расформировали свой остров.' DISBANDED_ISLAND_OTHER: '&e&lОстров | &7Вы расформировали остров {0}.' DISBANDED_ISLAND_OTHER_NAME: '&e&lОстров | &7Вы расформировали остров {0}.' ENTER_PVP_ISLAND: '&7&oВы были телепортированы на остров, где включен PvP. Вы защищены от PvP в течение следующих 10 секунд...' EXPELLED_PLAYER: '&e&lОстров | &7{0} был выгнан с острова.' FORMAT_QUAD: 'Q' FORMAT_TRILLION: 'T' FORMAT_BILLION: 'B' FORMAT_MILLION: 'M' FORMAT_THOUSANDS: 'K' FORMAT_SECONDS_NAME: 'секунд' FORMAT_SECOND_NAME: 'секунда' FORMAT_MINUTES_NAME: 'минут' FORMAT_MINUTE_NAME: 'минута' FORMAT_HOURS_NAME: 'часов' FORMAT_HOUR_NAME: 'час' FORMAT_DAYS_NAME: 'дней' FORMAT_DAY_NAME: 'день' GENERATOR_CLEARED: '&e&lОстров | &7Успешно очищены значения генератора для острова {0}.' GENERATOR_CLEARED_NAME: '&e&lОстров | &7Успешно очищены значения генератора для острова {0}.' GENERATOR_CLEARED_ALL: '&e&lОстров | &7Успешно очищены значения генератора для всех островов.' GENERATOR_UPDATED: '&e&lОстров | &7Успешно обновлены значения генератора {0} на остров {1}.' GENERATOR_UPDATED_NAME: '&e&lОстров | &7Успешно обновлены значения генератора {0} на остров {1}.' GENERATOR_UPDATED_ALL: '&e&lОстров | &7Успешно обновлены значения генератора {0} для всех островов.' GLOBAL_COMMAND_EXECUTED: '&e&lОстров | &7Успешно выполнена команда для участников острова {0}!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lОстров | &7Успешно выполнена команда для участников острова {0}!' GLOBAL_MESSAGE_SENT: '&e&lОстров | &7Сообщение успешно отправлено участникам острова {0}!' GLOBAL_MESSAGE_SENT_NAME: '&e&lОстров | &7Сообщение успешно отправлено участникам острова {0}!' GLOBAL_TITLE_SENT: '&e&lОстров | &7Успешно отправлен титул участникам острова {0}!' GLOBAL_TITLE_SENT_NAME: '&e&lОстров | &7Успешно отправлен титул участникам острова {0}!' GOT_BANNED: '&e&lОстров | &7Вы были ЗАБАНЕНЫ на острове {0}.' GOT_DEMOTED: '&e&lОстров | &7Вы были понижены до {0} на вашем острове.' GOT_EXPELLED: '&e&lОстров | &7&oВы были выгнаны с острова {0}.' GOT_INVITE: '&e&lОстров | &7{0} пригласил вас на свой остров.' GOT_INVITE_TOOLTIP: '&7Нажмите на сообщение, чтобы принять приглашение.' GOT_KICKED: '&e&lОстров | &7Вы были выгнаны с вашего острова {0}.' GOT_PROMOTED: '&e&lОстров | &7Вы были повышены до {0} на вашем острове.' GOT_REVOKED: '&e&lОстров | &7{0} отменил ваше приглашение на его остров.' GOT_UNBANNED: '&e&lОстров | &7Вы были СНЯТЫ с бана на острове {0}.' HIT_ISLAND_MEMBER: '&c&lОшибка | &7Вы не можете атаковать участников своего острова.' HIT_PLAYER_IN_ISLAND: '&c&lОшибка | &7Вы не можете атаковать игроков на острове.' IGNORED_ISLAND: '&e&lОстров | &7Остров {0} теперь игнорируется в списке лучших островов.' IGNORED_ISLAND_NAME: '&e&lОстров | &7Остров {0} теперь игнорируется в списке лучших островов.' INTERACT_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не можете взаимодействовать за пределами своей зоны защиты.' INVALID_AMOUNT: '&c&lОшибка | &7Недопустимая сумма {0}.' INVALID_BIOME: '&c&lОшибка | &7Недопустимый биом {0}.' INVALID_BLOCK: '&c&lОшибка | &7Недопустимое местоположение блока {0}.' INVALID_BORDER_COLOR: '&c&lОшибка | &7Недопустимый цвет границы {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lОшибка | &7Недопустимый эффект {0}.' INVALID_ENTITY: '&c&lОшибка | &7Недопустимое существо {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lОшибка | &7Недопустимый интервал {0}.' INVALID_ISLAND: '&c&lОшибка | &7У вас нет острова.' INVALID_ISLAND_LOCATION: '&c&lОшибка | &7В вашем местоположении нет острова.' INVALID_ISLAND_OTHER: '&c&lОшибка | &7У {0} нет острова.' INVALID_ISLAND_OTHER_NAME: '&c&lОшибка | &7Нет острова с именем {0}.' INVALID_ISLAND_PERMISSION: | &c&lОшибка | &7Не удалось найти разрешение острова {0}. &c&lОшибка | &7Разрешения острова: {1} INVALID_LEVEL: '&c&lОшибка | &7Недопустимый уровень {0}.' INVALID_LIMIT: '&c&lОшибка | &7Недопустимый лимит {0}.' INVALID_MATERIAL: '&c&lОшибка | &7Недопустимый материал {0}.' INVALID_MATERIAL_DATA: '&c&lОшибка | &7Недопустимые данные материала {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lОшибка | &7Недопустимая миссия {0}.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lОшибка | &7Недопустимый модуль {0}.' INVALID_MULTIPLIER: '&c&lОшибка | &7Недопустимый множитель {0}.' INVALID_PAGE: '&c&lОшибка | &7Недопустимая страница {0}.' INVALID_PERCENTAGE: '&c&lОшибка | &7Процент должен быть от 0 до 100.' INVALID_PLAYER: '&c&lОшибка | &7Не удается найти игрока с именем {0}.' INVALID_RATE: | &c&lОшибка | &7Не удалось найти рейтинг с именем {0}. &c&lОшибка | &7Рейтинги острова: {1} INVALID_ROWS: '&c&lОшибка | &7Недопустимое количество строк: {0}.' INVALID_ROLE: | &c&lОшибка | &7Не удалось найти роль острова {0}. &c&lОшибка | &7Роли острова: {1} INVALID_SCHEMATIC: '&c&lОшибка | &7Не удалось найти схему с именем {0}.' INVALID_SETTINGS: | &c&lОшибка | &7Не удалось найти настройки острова {0}. &c&lОшибка | &7Настройки острова: {1} INVALID_SIZE: '&c&lОшибка | &7Недопустимый размер {0}.' INVALID_SLOT: '&c&lОшибка | &7Недопустимый слот {0}.' INVALID_TITLE: '&c&lОшибка | &7Недопустимый введенный титул.' INVALID_TOGGLE_MODE: '&c&lОшибка | &7Не удается переключить {0}.' INVALID_UPGRADE: | &c&lОшибка | &7Не удалось найти улучшение с названием {0}. &c&lОшибка | &7Улучшения: {1} INVALID_VISIT_LOCATION: '&c&lОшибка | &7У этого острова нет местоположения для посетителей.' INVALID_VISIT_LOCATION_BYPASS: '&7&oУ вас режим обхода, телепортирую вас на остров...' INVALID_WARP: '&c&lОшибка | &7Недопустимый варп {0}.' INVALID_WORLD: '&c&lОшибка | &7Недопустимый мир {0}.' INVITE_ANNOUNCEMENT: '&e&lОстров | &7{0} пригласил {1} на остров.' INVITE_BANNED_PLAYER: '&c&lОшибка | &7Этот игрок забанен на острове и не может быть приглашен.' INVITE_TO_FULL_ISLAND: '&c&lОшибка | &7Вы не можете пригласить больше участников на ваш остров.' ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lОшибка | &7Остров с таким именем уже существует.' ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lБанк | &7Банк острова пуст.' ISLAND_BANK_SHOW: '&e&lБанк | &7Ваш остров имеет ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lБанк | &7Остров {0} имеет ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lБанк | &7Остров {0} имеет ${1}.' ISLAND_BEING_CALCULATED: '&c&lОшибка | &7Вы не можете взаимодействовать с блоками, пока остров пересчитывается!' ISLAND_CLOSED: '&e&lОстров | &7Остров успешно закрыт для публики.' ISLAND_CREATE_PROCESS_FAIL: '&c&lОшибка | &7У вас уже есть запущенная задача создания острова.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lОстров | &7Обработка вашего запроса...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lПолёт | &7Полёт на острове автоматически &cвыключен&7.' ISLAND_FLY_ENABLED: '&e&lПолёт | &7Полёт на острове автоматически &aвключён&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lОстров | &7&oВы были внутри острова, который был расформирован, поэтому вы были телепортированы обратно в спаун...' ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lОстров | &7&oВы были внутри острова, на котором был включен PVP, поэтому вы были телепортированы обратно в спаун...' ISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Разработано Ome_R' ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Список команд [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Используйте /is help {0} для следующей страницы.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lОстров | &7Лимит банка: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lОстров | &7Лимиты блоков: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lОстров | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lОстров | &7Лимит кооперации: {0}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lОстров | &7Множитель урожая: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lОстров | &7Множитель дропов: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lОстров | &7Эффекты острова: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lОстров | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lОстров | &7Лимиты сущностей: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lОстров | &7 {0}: {1}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lОстров | &7Ставки генераторов ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lОстров | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lОстров | &7Лимиты ролей: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lОстров | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lОстров | &7Размер границ: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lОстров | &7Множитель спаунеров: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lОстров | &7Лимит команды: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lОстров | &7Улучшения: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lОстров | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lОстров | &7Лимит варпов: {0}' ISLAND_INFO_BANK: '&e&lОстров | &7Банк: {0}' ISLAND_INFO_BONUS: '&e&lОстров | &7Бонус стоимости: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lОстров | &7Бонус уровня: {0}' ISLAND_INFO_CREATION_TIME: '&e&lОстров | &7Время создания: {0}' ISLAND_INFO_DISCORD: '&e&lОстров | &7Дискорд: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lОстров | &7Последнее обновление: {0} назад' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lОстров | &7Последнее обновление: &aВ настоящее время активно' ISLAND_INFO_LEVEL: '&e&lОстров | &7Уровень: {0}' ISLAND_INFO_LOCATION: '&e&lОстров | &7Дом: {0}' ISLAND_INFO_NAME: '&e&lОстров | &7Имя: {0}' ISLAND_INFO_OWNER: '&e&lОстров | &7Лидер: {0}' ISLAND_INFO_PAYPAL: '&e&lОстров | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lОстров | &7 - {0}' ISLAND_INFO_RATE: '&e&lОстров | &7Рейтинг: {0} &7({1}/5) - {2} общих рейтингов.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: '✦' ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lОстров | &7{0}ы: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lОстров | &7Количество посетителей: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lОстров | &7Стоимость: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lОстров | &7Остров успешно открыт для публики.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lПредпросмотр | &7Вы отошли слишком далеко, и режим предпросмотра больше не активен.' ISLAND_PREVIEW_CANCEL: '&e&lПредпросмотр | &7Вы отменили режим предпросмотра.' ISLAND_PREVIEW_CONFIRM_TEXT: 'ПОДТВЕРДИТЬ' ISLAND_PREVIEW_CANCEL_TEXT: 'ОТМЕНА' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lПредпросмотр | &7Вы начали режим предпросмотра для схемы {0}. &e&lПредпросмотр | &7Введите &a&lПОДТВЕРДИТЬ &7для создания нового острова или &c&lОТМЕНА &7для отмены режима предпросмотра. &e&lПредпросмотр | &7Вы не можете покидать территорию острова, иначе режим предпросмотра будет отменён автоматически. ISLAND_PROTECTED: '&c&lОшибка | &7Этот остров защищён.' ISLAND_PROTECTED_OPPED: '&7&oВы можете обойти это ограничение, используя "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lОстров | &7Члены острова {0} &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Оффлайн)' ISLAND_TEAM_STATUS_ONLINE: '&a(Онлайн)' ISLAND_TEAM_STATUS_ROLES: '&e&lОстров | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Оффлайн)' ISLAND_TOP_STATUS_ONLINE: '&a(Онлайн)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Частный]' ISLAND_WAS_CLOSED: '&e&lОстров | &7&oОстров, в котором вы были, был закрыт, и вы были телепортированы обратно на спавн...' ISLAND_WORTH_ERROR: '&c&lОшибка | &7Произошла неожиданная ошибка при расчете вашего острова. Свяжитесь с администрацией, если проблема сохраняется.' ISLAND_WORTH_RESULT: '&e&lОстров | &7Стоимость вашего острова {0} [Уровень {1}]' ISLAND_WORTH_TIME_OUT: '&c&lОшибка | &7Задача на расчет времени вышла за пределы. Попробуйте позже...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lОстров | &7{0} присоединился к вашему острову.' JOIN_ANNOUNCEMENT: '&e&lОстров | &7{0} присоединился к вашему острову.' JOIN_FULL_ISLAND: '&c&lОшибка | &7Этот остров достиг максимального количества разрешенных участников.' JOIN_WHILE_IN_ISLAND: '&c&lОшибка | &7Вы уже находитесь на острове.' JOINED_ISLAND: '&e&lОстров | &7Вы присоединились к острову {0}.' JOINED_ISLAND_NAME: '&e&lОстров | &7Вы присоединились к острову {0}.' JOINED_ISLAND_AS_COOP: '&e&lОстров | &7Вы теперь являетесь соучастником острова {0}.' JOINED_ISLAND_AS_COOP_NAME: '&e&lОстров | &7Вы теперь являетесь соучастником острова {0}.' KICK_ANNOUNCEMENT: '&e&lОстров | &7{0} был исключен из острова {1}.' KICK_ISLAND_LEADER: '&c&lОшибка | &7Вы не можете исключить лидера острова, используйте /is admin disband вместо этого.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lОшибка | &7Вы можете исключить только игроков с ролью ниже вашей.' LACK_CHANGE_PERMISSION: '&c&lОшибка | &7У вас нет разрешения на изменение этой роли.' LAST_ROLE_DEMOTE: '&c&lОшибка | &7Вы больше не можете понижать эту роль игрока.' LAST_ROLE_PROMOTE: '&c&lОшибка | &7Вы больше не можете повышать эту роль игрока.' LEAVE_ANNOUNCEMENT: '&e&lОстров | &7{0} покинул остров.' LEAVE_ISLAND_AS_LEADER: |- &c&lОшибка | &7Вы не можете покинуть свой остров, когда вы его владелец. &c&lОшибка | &7Вы можете передать право собственности, используя /is transfer. LEFT_ISLAND: '&e&lОстров | &7Вы покинули свой остров.' LEFT_ISLAND_COOP: '&e&lОстров | &7Вы больше не являетесь соучастником острова {0}.' LEFT_ISLAND_COOP_NAME: '&e&lОстров | &7Вы больше не являетесь соучастником острова {0}.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lОшибка | &7Вы должны предоставить твердый материал.' MAXIMUM_LEVEL: '&c&lОшибка | &7Максимальный уровень для этого улучшения - {0}.' MESSAGE_SENT: '&e&lОстров | &7Сообщение успешно отправлено {0}!' MISSION_CANNOT_COMPLETE: '&c&lОшибка | &7Вы не можете завершить эту миссию еще.' MISSION_NO_AUTO_REWARD: '&e&lМиссия | &7У вас есть все необходимые материалы для завершения {0} - используйте /is missions, чтобы завершить!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lОшибка | &7Вы должны завершить {0}, прежде чем завершить эту миссию.' MISSION_STATUS_COMPLETE: '&e&lМиссия | &7Изменен статус миссии {0} на завершенный для {1}.' MISSION_STATUS_COMPLETE_ALL: '&e&lМиссия | &7Изменен статус всех миссий на завершенный для {0}.' MISSION_STATUS_RESET: '&e&lМиссия | &7Сброшен статус миссии {0} для {1}.' MISSION_STATUS_RESET_ALL: '&e&lМиссия | &7Сброшен статус всех миссий для {0}.' MODULE_ALREADY_INITIALIZED: '&e&lМодуль | &7Этот модуль уже загружен.' MODULE_INFO: | &e&lМодуль | &7{0} от {1} &e&lМодуль | &7&m-------------------- &e&lМодуль | &7{2} MODULE_LOADED_SUCCESS: '&e&lМодуль | &7Успешно загружен модуль {0}.' MODULE_LOADED_FAILURE: '&e&lМодуль | &7Не удалось загрузить модуль {0}. Проверьте консоль для получения дополнительной информации.' MODULE_UNLOADED_SUCCESS: '&e&lМодуль | &7Успешно выгружен модуль.' MODULES_LIST: '&fМодули ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lОстров | &7{0} изменил имя своего острова на {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lОшибка | &7Вы не можете использовать это имя.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lОшибка | &7Вы не можете использовать имена игроков в качестве имен островов.' NAME_TOO_LONG: '&c&lОшибка | &7Имена островов не могут превышать {0} символов.' NAME_TOO_SHORT: '&c&lОшибка | &7Имена островов не могут быть короче {0} символов.' NO_BAN_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы забанить игроков.' NO_CLOSE_BYPASS: '&c&lОшибка | &7Этот остров не открыт для публики.' NO_CLOSE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы закрыть остров для публики.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы добавлять игроков как соучастников.' NO_DELETE_WARP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы удалять варпы.' NO_DEMOTE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы понижать игроков.' NO_DEPOSIT_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы вносить деньги в банк острова.' NO_DISBAND_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы распустить ваш остров.' NO_EXPEL_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы исключать игроков из вашего острова.' NO_INVITE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы приглашать игроков.' NO_ISLAND_CHEST_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы получить доступ к сундуку острова.' NO_ISLAND_INVITE: '&c&lОшибка | &7Не удалось найти никаких приглашений от этого острова.' NO_ISLANDS_TO_PURGE: '&c&lОшибка | &7Не было островов для очистки.' NO_KICK_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы исключать игроков.' NO_MORE_DISBANDS: '&c&lОшибка | &7Вы не можете распустить больше островов.' NO_MORE_WARPS: '&c&lОшибка | &7Ваш остров не может иметь больше варпов.' NO_NAME_PERMISSION: '&c&lОшибка | &7Вы не можете изменить имя вашего острова.' NO_OPEN_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы открыть остров для публики.' NO_PERMISSION_CHECK_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы получать информацию о разрешениях.' NO_PROMOTE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы повышать игроков.' NO_RANKUP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы повысить улучшения.' NO_RATINGS_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы проверять рейтинги.' NO_SET_BIOME_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы изменить биом острова.' NO_SET_DISCORD_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы изменить Discord острова.' NO_SET_HOME_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы установить место телепорта острова.' NO_SET_PAYPAL_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы изменить PayPal адрес острова.' NO_SET_ROLE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы установить роли для игроков.' NO_SET_SETTINGS_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы изменить настройки острова.' NO_SET_WARP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы установить варпы острова.' NO_TRANSFER_PERMISSION: '&c&lОшибка | &7Вы должны быть лидером острова, чтобы передать руководство.' NO_UNCOOP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы удалить игроков из кооперации.' NO_UPGRADE_PERMISSION: '&c&lОшибка | &7У вас нет разрешения на повышение до другого уровня.' NO_WITHDRAW_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы снять деньги из банка острова.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lОшибка | &7У вас недостаточно денег для внесения {0} долларов в банк вашего острова.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lОшибка | &7У вас недостаточно денег.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lОшибка | &7У вас недостаточно денег для использования варпов острова.' OPEN_MENU_WHILE_SLEEPING: '&7&oВам слишком лень взаимодействовать с меню, не так ли?' PANEL_TOGGLE_OFF: |- &e&lПанель | &7Панель острова отключена &cOFF&7. &e&lПанель | &7Использование /is телепортирует вас на остров. PANEL_TOGGLE_ON: |- &e&lПанель | &7Панель острова включена &aON&7. &e&lПанель | &7Использование /is откроет панель для вас. PERMISSION_CHANGED: '&e&lОстров | &7Успешно обновлено разрешение {0} острова {1}.' PERMISSION_CHANGED_NAME: '&e&lОстров | &7Успешно обновлено разрешение {0} острова {1}.' PERMISSION_CHANGED_ALL: '&e&lОстров | &7Успешно обновлено разрешение {0} для всех островов.' PERSISTENT_DATA_EMPTY: '&c&lОшибка | &7Не найдено данных для вашего запроса.' PERSISTENT_DATA_MODIFY: '&e&lДанные | &7Успешно установлены данные для {0} с {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lДанные | &7Данные для {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lДанные | &7Успешно удалены данные для {0} из пути {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lОстров | &7Успешно сброшены все разрешения для {0} на значения по умолчанию!' PERMISSIONS_RESET_ROLES: '&e&lОстров | &7Успешно сброшены все разрешения острова на значения по умолчанию!' PLACEHOLDER_NO: 'Нет' PLACEHOLDER_YES: 'Да' PLAYER_ALREADY_BANNED: '&c&lОшибка | &7Этот игрок уже забанен.' PLAYER_ALREADY_COOP: '&c&lОшибка | &7Этот игрок уже в кооперации.' PLAYER_ALREADY_IN_ISLAND: '&c&lОшибка | &7Этот игрок уже на острове.' PLAYER_ALREADY_IN_ROLE: '&c&lОшибка | &7{0} уже является {1}.' PLAYER_EXPEL_BYPASS: '&c&lОшибка | &7Этот пользователь не может быть исключен с острова.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lОстров | &7{0} присоединился к серверу.' PLAYER_NOT_BANNED: '&c&lОшибка | &7Этот игрок не забанен.' PLAYER_NOT_COOP: '&c&lОшибка | &7Этот игрок не в кооперации.' PLAYER_NOT_INSIDE_ISLAND: '&c&lОшибка | &7Этот игрок не на вашем острове.' PLAYER_NOT_ONLINE: '&c&lОшибка | &7Этот игрок не онлайн!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lОстров | &7{0} покинул сервер.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lОшибка | &7Вы можете повышать только игроков с более низкой ролью острова.' PROMOTED_MEMBER: '&e&lОстров | &7Вы повысили {0} до {1} на его острове.' PURGE_CLEAR: '&e&lОстров | &7Успешно очищены все запланированные для удаления острова.' PURGED_ISLANDS: |- &e&lОстров | &7{0} островов будет удалено при перезагрузке сервера. &e&lОстров | &7Вы можете отменить это в любое время, используя /is admin purge cancel. RANKUP_SUCCESS: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для острова {1}.' RANKUP_SUCCESS_ALL: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для всех островов.' RANKUP_SUCCESS_NAME: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для {1}.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lОстров | &7{0} оценил ваш остров на {1} из 5.' RATE_CHANGE_OTHER: '&e&lОстров | &7Вы изменили рейтинг {0} на {1}.' RATE_OWN_ISLAND: '&c&lОшибка | &7Вы не можете оценить свой собственный остров.' RATE_REMOVE_ALL: '&e&lОстров | &7Успешно удалены все оценки для {0}.' RATE_REMOVE_ALL_ISLANDS: '&e&lОстров | &7Успешно удалены все оценки всех островов.' RATE_SUCCESS: '&e&lОстров | &7Вы оценили этот остров на {0} звезд!' REACHED_BLOCK_LIMIT: '&e&lУлучшения | &7Вы достигли предела для {0} блока острова.' REACHED_ENTITY_LIMIT: '&e&lУлучшения | &7Вы достигли предела для сущности {0} на острове.' RECALC_ALREADY_RUNNING: '&c&lОшибка | &7Ваш остров уже пересчитывается.' RECALC_ALREADY_RUNNING_OTHER: '&c&lОшибка | &7Этот остров уже пересчитывается.' RECALC_ALL_ISLANDS: '&e&lОстров | &7Пересчет всех островов...' RECALC_ALL_ISLANDS_DONE: '&e&lОстров | &7Успешно завершен пересчет всех островов.' RECALC_PROCCESS_REQUEST: '&e&lОстров | &7Обработка вашего запроса...' RELOAD_COMPLETED: '&e&lОстров | &7Перезагрузка завершена!' RELOAD_PROCCESS_REQUEST: '&e&lОстров | &7Начинается перезагрузка конфигураций...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lОстров | &7{0} отозвал приглашение {1} на остров.' RESET_WORLD_SUCCEED: '&e&lОстров | &7Успешно сброшен мир {0} для острова {1}.' RESET_WORLD_SUCCEED_ALL: '&e&lОстров | &7Успешно сброшен мир {0} для всех островов.' RESET_WORLD_SUCCEED_NAME: '&e&lОстров | &7Успешно сброшен мир {0} для {1}.' SAME_NAME_CHANGE: '&c&lОшибка | &7Вы должны ввести другое имя, отличное от текущего имени острова.' SCHEMATIC_LEFT_SELECT: '&e&lСхемы | &7Выбрана позиция #2 ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lОшибка | &7Вы не выбрали две позиции.' SCHEMATIC_PROCCESS_REQUEST: '&e&lСхемы | &7Обработка вашего запроса...' SCHEMATIC_READY_TO_CREATE: | &e&lСхемы | &7Вы выбрали две позиции. Выполните /is admin schematic , чтобы создать новую схему. &e&lСхемы | &7Убедитесь, что вы находитесь на месте телепортации при выполнении команды. SCHEMATIC_RIGHT_SELECT: '&e&lСхемы | &7Выбрана позиция #1 ({0})' SCHEMATIC_SAVED: '&e&lСхемы | &7Схема успешно сохранена!' SELF_ROLE_CHANGE: '&c&lОшибка | &7Вы не можете изменить свою роль.' SET_UPGRADE_LEVEL: '&e&lУлучшения | &7Успешно обновлен уровень {0} для острова {1}.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lУлучшения | &7Успешно обновлен уровень {0} для {1}.' SET_WARP: '&e&lОстров | &7Успешно создан новый варп на {0}.' SET_WARP_OUTSIDE: '&c&lОшибка | &7Вы не можете устанавливать варпы за пределами вашего острова.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.' SETTINGS_UPDATED_NAME: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.' SETTINGS_UPDATED_ALL: '&e&lОстров | &7Успешно обновлены настройки {0} для всех островов.' SIZE_BIGGER_MAX: '&c&lОшибка | &7Вы не можете установить размер больше максимального размера острова.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lСпавн | &7Успешно телепортирован {0} на спавн.' SPAWN_SET_SUCCESS: '&e&lСпавн | &7Успешно обновлено место спавна на {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Шпион] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lУлучшения | &7Успешно синхронизированы все значения улучшений для острова {0}.' SYNC_UPGRADES_ALL: '&e&lУлучшения | &7Успешно синхронизированы все значения улучшений для всех островов.' SYNC_UPGRADES_NAME: '&e&lУлучшения | &7Успешно синхронизированы все значения улучшений для {0}.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не находитесь на своем острове.' TELEPORT_OUTSIDE_ISLAND: '&c&lОшибка | &7Вы не можете телепортироваться за пределы вашей защитной зоны.' TELEPORT_WARMUP: '&7&oВас телепортируют через {0}... Не двигайтесь!' TELEPORT_WARMUP_CANCEL: '&7&oВы двинулись, поэтому телепортация отменена.' TITLE_SENT: '&e&lОстров | &7Успешно отправлен титул {0}!' TELEPORTED_FAILED: '&e&lОстров | &7Похоже, что на этом острове нет безопасных блоков. Пожалуйста, свяжитесь с администратором.' TELEPORTED_SUCCESS: '&e&lОстров | &7Вы были телепортированы на свой остров.' TELEPORTED_TO_WARP: '&e&lОстров | &7Успешно телепортирован на этот варп острова.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lОстров | &7Игрок {0} телепортировался на варп острова {1}.' TOGGLED_BYPASS_OFF: '&e&lОбход | &7Режим обхода отключен &cOFF&7.' TOGGLED_BYPASS_ON: '&e&lОбход | &7Режим обхода включен &aON&7.' TOGGLED_FLY_OFF: '&e&lПолет | &7Режим полета на острове отключен &cOFF&7.' TOGGLED_FLY_ON: '&e&lПолет | &7Режим полета на острове включен &aON&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lСхемы | &7Режим схем отключен &cOFF&7.' TOGGLED_SCHEMATIC_ON: |- &e&lСхемы | &7Режим схем включен &aON&7. &e&lСхемы | &7Выберите область с помощью золотого топора. TOGGLED_SPY_OFF: '&e&lШпион | &7Шпионский чат отключен &cOFF&7.' TOGGLED_SPY_ON: '&e&lШпион | &7Шпионский чат включен &aON&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lСклад | &7Режим укладки блоков отключен &cOFF&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lСклад | &7Режим укладки блоков включен &aON&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lЧат | &7Командный чат отключен &cOFF&7.' TOGGLED_TEAM_CHAT_ON: '&e&lЧат | &7Командный чат включен &aON&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lГраница | &7Границы мира отключены &cOFF&7.' TOGGLED_WORLD_BORDER_ON: '&e&lГраница | &7Границы мира включены &aON&7.' TRANSFER_ADMIN: '&e&lОстров | &7Вы передали руководство {0} игроку {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lОшибка | &7{0} уже является лидером своего острова.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lОшибка | &7Эти игроки не находятся на одних и тех же островах.' TRANSFER_ADMIN_NOT_LEADER: '&c&lОшибка | &7Этот игрок не является лидером ни одного острова.' TRANSFER_ALREADY_LEADER: '&c&lОшибка | &7Вы уже являетесь лидером этого острова.' TRANSFER_BROADCAST: '&e&lОстров | &7Руководство острова было передано {0}.' UNBAN_ANNOUNCEMENT: '&e&lОстров | &7{0} был разморожен на острове {1}.' UNCOOP_ANNOUNCEMENT: '&e&lОстров | &7{0} убрал {1} из состава кооперативов.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lОстров | &7Игроков в кооперации нет, поэтому вы были автоматически исключены.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lОстров | &7{0} покинул игру и больше не является членом кооперации.' UNIGNORED_ISLAND: '&e&lОстров | &7Остров {0} больше не игнорируется в топах.' UNIGNORED_ISLAND_NAME: '&e&lОстров | &7Остров {0} больше не игнорируется в топах.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lОстров | &7&oПохоже, этот варп небезопасен. Попробуйте другой варп.' UPDATED_PERMISSION: '&e&lОстров | &7Обновлены права для {0}.' UPDATED_SETTINGS: '&e&lОстров | &7Обновлены настройки острова {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lОшибка | &7Вы можете улучшить только через {0}.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lОшибка | &7Вы не можете использовать эту команду на других островах.' WARP_ALREADY_EXIST: '&c&lОшибка | &7Варп с таким именем уже существует.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lВарпы | &7Введите новую лор (введите "-cancel" для отмены): &e&lВарпы | &7Вы можете разделять строки, используя "\n". WARP_CATEGORY_ICON_NEW_NAME: '&e&lВарпы | &7Введите имя (введите "-cancel" для отмены):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lВарпы | &7Введите новый тип материала (введите "-cancel" для отмены):' WARP_CATEGORY_ICON_UPDATED: '&e&lВарпы | &7Успешно обновлен значок категории.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lОшибка | &7Имена категорий варпов не могут быть пустыми.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lОшибка | Имена категорий варпов не могут превышать 255 символов.' WARP_CATEGORY_SLOT: '&e&lВарпы | &7Введите новый слот (введите "-cancel" для отмены):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lОшибка | &7Этот слот уже занят другой категорией.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lВарпы | &7Успешно изменен слот категории на {0}.' WARP_CATEGORY_RENAME: '&e&lВарпы | &7Введите новое имя (введите "-cancel" для отмены):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lОшибка | &7Это имя уже занято другой категорией.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lВарпы | &7Успешно переименована категория в {0}.' WARP_ICON_NEW_LORE: | &e&lВарпы | &7Введите новую лор (введите "-cancel" для отмены): &e&lВарпы | &7Вы можете разделять строки, используя "\n". WARP_ICON_NEW_NAME: '&e&lВарпы | &7Введите имя (введите "-cancel" для отмены):' WARP_ICON_NEW_TYPE: '&e&lВарпы | &7Введите новый тип материала (введите "-cancel" для отмены):' WARP_ICON_UPDATED: '&e&lВарпы | &7Успешно обновлен значок варпа.' WARP_ILLEGAL_NAME: '&c&lОшибка | &7Имена варпов не могут быть пустыми.' WARP_LOCATION_UPDATE: '&e&lВарпы | &7Успешно обновлено местоположение варпа на ваше текущее местоположение.' WARP_NAME_TOO_LONG: '&c&lОшибка | Имена варпов не могут превышать 255 символов.' WARP_PUBLIC_UPDATE: '&e&lВарпы | &7Успешно открыт варп для публики.' WARP_PRIVATE_UPDATE: '&e&lВарпы | &7Успешно закрыт варп для публики.' WARP_RENAME: '&e&lВарпы | &7Введите новое имя (введите "-cancel" для отмены):' WARP_RENAME_ALREADY_EXIST: '&c&lОшибка | &7Это имя уже занято другим варпом.' WARP_RENAME_SUCCESS: '&e&lВарпы | &7Успешно переименован варп в {0}.' WITHDRAW_ALL_MONEY: |- &e&lБанк | &7В банке острова только {0} долларов. &e&lБанк | &7&oСнимаю все деньги..." WITHDRAW_ANNOUNCEMENT: '&e&lБанк | &7{0} снял ${1} из банка острова!' WITHDRAW_ERROR: '&c&lОшибка | &7{0}.' WITHDRAWN_MONEY: '&e&lБанк | &7Вы сняли ${0} из банка острова {1}!' WITHDRAWN_MONEY_NAME: '&e&lБанк | &7Вы сняли ${0} из банка острова {1}!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lМиры | &7Мир {0} еще не разблокирован!' ================================================ FILE: src/main/resources/lang/tr-TR.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## Translated by losadev ## ## ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # You can find a tutorial about configuring messages here: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lAda | &7Oyuncu {0} başarıyla {1}''in adasına eklendi.' ADMIN_ADD_PLAYER_NAME: '&e&lAda | &7Oyuncu {0} başarıyla {1} adasına eklendi.' ADMIN_DEPOSIT_MONEY: '&e&lBanka | &7{1}''in ada bankasına ${0} yatırdın.' ADMIN_DEPOSIT_MONEY_NAME: '&e&lBanka | &7{1} adasının bankasına ${0} yatırdın.' ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Geliştiren: Ome_R' ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Yönetici Komutları Listesi [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Sonraki sayfa için /is admin {0} kullan.' ALREADY_IN_ISLAND: '&c&lHata | &7Zaten bir adadasın.' ALREADY_IN_ISLAND_OTHER: '&c&lHata | &7Bu oyuncu zaten adanın bir üyesi.' BAN_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan YASAKLANDI.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip oyuncuları yasaklayabilirsin.' BANK_DEPOSIT_CUSTOM: '&e&lBanka | &7Yatırmak istediğin miktarı yaz:' BANK_DEPOSIT_COMPLETED: Para Yatırma Tamamlandı BANK_LIMIT_EXCEED: '&c&lHata | &7Banka limitini aştın.' BANK_WITHDRAW_CUSTOM: '&e&lBanka | &7Çekmek istediğin miktarı yaz:' BANK_WITHDRAW_COMPLETED: Para Çekme Tamamlandı BANNED_FROM_ISLAND: '&c&lHata | &7Bu adadan yasaklandın.' BLOCK_COUNT_CHECK: '&e&lAda | &7Bu adada x{0} {1} bulunuyor.' BLOCK_COUNTS_CHECK: | &e&lAda | &7Bu adada aşağıdaki bloklar bulunuyor: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lAda | &7Bu adada takip edilen blok bulunmuyor.' BLOCK_COUNTS_CHECK_MATERIAL: x{0} {1} BLOCK_LEVEL: '&e&lSeviye | &7{0} bloğunun seviyesi {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lSeviye | &7{0} bloğu değersiz.' BLOCK_VALUE: '&e&lDeğer | &7{0} bloğunun değeri {1}.' BLOCK_VALUE_WORTHLESS: '&e&lDeğer | &7{0} bloğu değersiz.' BONUS_SYNC_ALL: '&e&lAda | &7Ada bonusu tüm adalarla başarıyla senkronize edildi.' BONUS_SYNC_NAME: '&e&lAda | &7Ada bonusu {0} ile başarıyla senkronize edildi.' BONUS_SYNC: '&e&lAda | &7Ada bonusu {0}''ın adasıyla başarıyla senkronize edildi.' BORDER_PLAYER_COLOR_NAME_BLUE: Mavi BORDER_PLAYER_COLOR_NAME_RED: Kırmızı BORDER_PLAYER_COLOR_NAME_GREEN: Yeşil BORDER_PLAYER_COLOR_UPDATED: '&e&lSınır | &7Kişisel sınır rengin başarıyla {0} olarak değiştirildi.' BUILD_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında inşa edemezsin.' CANNOT_SET_ROLE: '&c&lHata | &7Oyuncunun rolünü {0} olarak ayarlayamazsın.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip rollerin izinlerini değiştirebilirsin.' CHANGED_BANK_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının banka limiti başarıyla güncellendi.' CHANGED_BANK_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların banka limiti başarıyla güncellendi.' CHANGED_BANK_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının banka limiti başarıyla güncellendi.' CHANGED_BIOME: '&e&lAda | &7Biyom başarıyla {0} olarak değiştirildi. Değişiklikleri görmek için sunucuya tekrar bağlanman gerekebilir.' CHANGED_BIOME_ALL: '&e&lAda | &7Tüm adalar için biyom başarıyla {0} olarak değiştirildi.' CHANGED_BIOME_NAME: '&e&lAda | &7{1} adası için biyom başarıyla {0} olarak değiştirildi.' CHANGED_BIOME_OTHER: '&e&lAda | &7{1}''in adası için biyom başarıyla {0} olarak değiştirildi.' CHANGED_BLOCK_AMOUNT: '&e&lBloklar | &7{0} konumundaki blok miktarı başarıyla {1} olarak değiştirildi.' CHANGED_BLOCK_LIMIT: '&e&lYükseltmeler | &7{0} Bloğunun {1}''in adası için limiti başarıyla güncellendi.' CHANGED_BLOCK_LIMIT_ALL: '&e&lYükseltmeler | &7{0} Bloğunun tüm adalar için limiti başarıyla güncellendi.' CHANGED_BLOCK_LIMIT_NAME: '&e&lYükseltmeler | &7{0} Bloğunun {1} adası için limiti başarıyla güncellendi.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lSandık | &7{2}''in adası için #{0} sayfasının satırları başarıyla {1} olarak güncellendi.' CHANGED_CHEST_SIZE_ALL: '&e&lSandık | &7Tüm adalar için #{0} sayfasının satırları başarıyla {1} olarak güncellendi.' CHANGED_CHEST_SIZE_NAME: '&e&lSandık | &7{2} adası için #{0} sayfasının satırları başarıyla {1} olarak güncellendi.' CHANGED_COOP_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının co-op oyuncu limiti başarıyla güncellendi.' CHANGED_COOP_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların co-op oyuncu limiti başarıyla güncellendi.' CHANGED_COOP_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının co-op oyuncu limiti başarıyla güncellendi.' CHANGED_CROP_GROWTH: '&e&lYükseltmeler | &7{0}''ın adasının bitki büyüme çarpanı başarıyla güncellendi.' CHANGED_CROP_GROWTH_ALL: '&e&lYükseltmeler | &7Tüm adaların bitki büyüme çarpanı başarıyla güncellendi.' CHANGED_CROP_GROWTH_NAME: '&e&lYükseltmeler | &7{0} adasının bitki büyüme çarpanı başarıyla güncellendi.' CHANGED_DISCORD: '&e&lAda | &7Ada discordu başarıyla {0} olarak değiştirildi.' CHANGED_ENTITY_LIMIT: '&e&lYükseltmeler | &7{0} varlıklarının {1}''in adası için limiti başarıyla güncellendi.' CHANGED_ENTITY_LIMIT_ALL: '&e&lYükseltmeler | &7{0} varlıklarının tüm adalar için limiti başarıyla güncellendi.' CHANGED_ENTITY_LIMIT_NAME: '&e&lYükseltmeler | &7{0} varlıklarının {1} adası için limiti başarıyla güncellendi.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&lYükseltmeler | &7{0} ada etkisinin {1}''in adası için seviyesi başarıyla güncellendi.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lYükseltmeler | &7{0} ada etkisinin tüm adalar için seviyesi başarıyla güncellendi.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lYükseltmeler | &7{0} ada etkisinin {1} adası için seviyesi başarıyla güncellendi.' CHANGED_ISLAND_SIZE: '&e&lYükseltmeler | &7{0}''ın adasının boyutu başarıyla güncellendi.' CHANGED_ISLAND_SIZE_ALL: '&e&lYükseltmeler | &7Tüm adaların boyutu başarıyla güncellendi.' CHANGED_ISLAND_SIZE_NAME: '&e&lYükseltmeler | &7{0} adasının boyutu başarıyla güncellendi.' CHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oOyuncular adalarının dışında inşa edebildiği için ada boyutunun bir etkisi yoktur. Bu özelliği yapılandırma dosyasından kapatırsan ada boyutu tekrar etkili olacaktır.' CHANGED_LANGUAGE: '&e&lDil | &7Kişisel dilin başarıyla İngilizce olarak değiştirildi.' CHANGED_MOB_DROPS: '&e&lYükseltmeler | &7{0}''ın adasının mob düşürme çarpanı başarıyla güncellendi.' CHANGED_MOB_DROPS_ALL: '&e&lYükseltmeler | &7Tüm adaların mob düşürme çarpanı başarıyla güncellendi.' CHANGED_MOB_DROPS_NAME: '&e&lYükseltmeler | &7{0} adasının mob düşürme çarpanı başarıyla güncellendi.' CHANGED_NAME: '&e&lAda | &7Adanın adını {0}&7 olarak değiştirdin.' CHANGED_NAME_OTHER: '&e&lAda | &7{0} adasının adını {1}&7 olarak değiştirdin.' CHANGED_NAME_OTHER_NAME: '&e&lAda | &7{0}&7 adının adını {1}&7 olarak değiştirdin.' CHANGED_PAYPAL: '&e&lAda | &7Ada paypalı başarıyla {0} olarak değiştirildi.' CHANGED_ROLE_LIMIT: '&e&lYükseltmeler | &7{0} rolünün {1}''in adası için limiti başarıyla güncellendi.' CHANGED_ROLE_LIMIT_ALL: '&e&lYükseltmeler | &7{0} rolünün tüm adalar için limiti başarıyla güncellendi.' CHANGED_ROLE_LIMIT_NAME: '&e&lYükseltmeler | &7{0} rolünün {1} adası için limiti başarıyla güncellendi.' CHANGED_SPAWNER_RATES: '&e&lYükseltmeler | &7{0}''ın adasının spawner oranları çarpanı başarıyla güncellendi.' CHANGED_SPAWNER_RATES_ALL: '&e&lYükseltmeler | &7Tüm adaların spawner oranları çarpanı başarıyla güncellendi.' CHANGED_SPAWNER_RATES_NAME: '&e&lYükseltmeler | &7{0} adasının spawner oranları çarpanı başarıyla güncellendi.' CHANGED_TEAM_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının takım limiti başarıyla güncellendi.' CHANGED_TEAM_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların takım limiti başarıyla güncellendi.' CHANGED_TEAM_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının takım limiti başarıyla güncellendi.' CHANGED_TELEPORT_LOCATION: '&e&lAda | &7Işınlanma konumu başarıyla güncellendi.' CHANGED_WARPS_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının ışınlanma limiti başarıyla güncellendi.' CHANGED_WARPS_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların ışınlanma limiti başarıyla güncellendi.' CHANGED_WARPS_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının ışınlanma limiti başarıyla güncellendi.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: miktar COMMAND_ARGUMENT_BIOME: biyom COMMAND_ARGUMENT_BORDER_COLOR: sınır-rengi COMMAND_ARGUMENT_COMMAND: komut... COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: discord... COMMAND_ARGUMENT_EFFECT: iksir-efekti COMMAND_ARGUMENT_EMAIL: e-posta COMMAND_ARGUMENT_ENTITY: varlık COMMAND_ARGUMENT_ISLAND_NAME: ada-adı COMMAND_ARGUMENT_ISLAND_ROLE: ada-rolü COMMAND_ARGUMENT_LEADER: lider COMMAND_ARGUMENT_LEVEL: seviye COMMAND_ARGUMENT_LIMIT: limit COMMAND_ARGUMENT_MATERIAL: materyal COMMAND_ARGUMENT_MENU: menü-adı COMMAND_ARGUMENT_MESSAGE: mesaj... COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: görev-adı COMMAND_ARGUMENT_MODULE_NAME: modül-adı COMMAND_ARGUMENT_MULTIPLIER: çarpan COMMAND_ARGUMENT_NAME: isim COMMAND_ARGUMENT_NEW_LEADER: yeni-lider COMMAND_ARGUMENT_PAGE: sayfa COMMAND_ARGUMENT_PATH: yol COMMAND_ARGUMENT_PERMISSION: izin COMMAND_ARGUMENT_PLAYER_NAME: oyuncu-adı COMMAND_ARGUMENT_PRIVATE: özel COMMAND_ARGUMENT_RATING: değerlendirme COMMAND_ARGUMENT_ROWS: satırlar COMMAND_ARGUMENT_SCHEMATIC_NAME: şematik-adı COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: havayı-kaydet COMMAND_ARGUMENT_SETTINGS: ayarlar COMMAND_ARGUMENT_SIZE: boyut COMMAND_ARGUMENT_TIME: süre COMMAND_ARGUMENT_TITLE_DURATION: süre COMMAND_ARGUMENT_TITLE_FADE_IN: giriş-solması COMMAND_ARGUMENT_TITLE_FADE_OUT: çıkış-solması COMMAND_ARGUMENT_UPGRADE_NAME: yükseltme-adı COMMAND_ARGUMENT_VALUE: değer COMMAND_ARGUMENT_WARP_NAME: ışınlanma-adı COMMAND_ARGUMENT_WARP_CATEGORY: ışınlanma-kategorisi COMMAND_ARGUMENT_WORLD: dünya COMMAND_COOLDOWN_FORMAT: '&c&lHata | &7Komutu sadece {0} içinde kullanabilirsin.' COMMAND_DESCRIPTION_ACCEPT: Bir oyuncudan gelen daveti kabul et. COMMAND_DESCRIPTION_ADMIN: Yönetici komutlarını kullan. COMMAND_DESCRIPTION_ADMIN_ADD: Bir adaya kullanıcı ekle. COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Başka bir oyuncunun adası için blok limitini artır. COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Bir oyuncuya bonus ekle. COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Başka bir oyuncunun adası için co-op oyuncu limitini artır. COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Başka bir oyuncunun adası için bitki büyüme çarpanını artır. COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Başka bir oyuncunun adası için bir ada efekti ekle. COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Başka bir oyuncunun adası için varlık limitini artır. COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Çakıl taşı jeneratörü için bir materyalin yüzdesini ekle. COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Başka bir oyuncunun adası için mob düşürme çarpanını artır. COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Başka bir oyuncunun ada boyutunu genişlet. COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Başka bir oyuncunun adası için spawner oranları çarpanını artır. COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Başka bir oyuncunun adası için üye limitini artır. COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Bir adanın ışınlanma limitini artır. COMMAND_DESCRIPTION_ADMIN_BONUS: Bir oyuncuya bonus ver. COMMAND_DESCRIPTION_ADMIN_BYPASS: Bypass modunu aç/kapat. COMMAND_DESCRIPTION_ADMIN_CHEST: Başka bir adanın ada sandığını aç. COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Belirli bir ada için jeneratör oranlarını temizle. COMMAND_DESCRIPTION_ADMIN_CLOSE: Bir adayı halka kapat. COMMAND_DESCRIPTION_ADMIN_CMD_ALL: Tüm adaların üyeleri için bir komut çalıştır. COMMAND_DESCRIPTION_ADMIN_COUNT: Belirli bir adadaki blok sayısını kontrol et. COMMAND_DESCRIPTION_ADMIN_DATA: Oyuncuların veya adaların kalıcı verileriyle etkileşime geç. COMMAND_DESCRIPTION_ADMIN_DEBUG: Hata ayıklama çıktılarını aç/kapat. COMMAND_DESCRIPTION_ADMIN_DEL_WARP: Bir ada için bir ışınlanma noktasını sil. COMMAND_DESCRIPTION_ADMIN_DEMOTE: Başka bir oyuncunun adasındaki bir üyeyi rütbe düşür. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Başka bir oyuncunun ada bankasına para yatır. COMMAND_DESCRIPTION_ADMIN_DISBAND: Başka bir oyuncunun adasını kalıcı olarak dağıt. COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Bir oyuncuya ada dağıtma hakkı ver. COMMAND_DESCRIPTION_ADMIN_IGNORE: En iyi adalardan bir adayı yoksay. COMMAND_DESCRIPTION_ADMIN_JOIN: Davet olmadan bir adaya katıl. COMMAND_DESCRIPTION_ADMIN_KICK: Bir oyuncuyu adasından at. COMMAND_DESCRIPTION_ADMIN_MODULES: Eklentinin modüllerini yönet. COMMAND_DESCRIPTION_ADMIN_MISSION: Bir oyuncu için bir görevin durumunu değiştir. COMMAND_DESCRIPTION_ADMIN_MSG: Bir oyuncuya ön ek olmadan mesaj gönder. COMMAND_DESCRIPTION_ADMIN_MSG_ALL: Tüm ada üyelerine ön ek olmadan mesaj gönder. COMMAND_DESCRIPTION_ADMIN_NAME: Bir adanın adını değiştir. COMMAND_DESCRIPTION_ADMIN_OPEN: Bir adayı halka aç. COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Bir oyuncu için özel bir menü aç. COMMAND_DESCRIPTION_ADMIN_PROMOTE: Başka bir oyuncunun adasındaki bir üyeyi rütbe yükselt. COMMAND_DESCRIPTION_ADMIN_PURGE: Adaları temizle. COMMAND_DESCRIPTION_ADMIN_RANKUP: Bir ada için bir yükseltmeyi seviye atlat. COMMAND_DESCRIPTION_ADMIN_RECALC: Bir adanın değerini yeniden hesapla. COMMAND_DESCRIPTION_ADMIN_RELOAD: Eklentinin tüm yapılandırmalarını ve görevlerini yeniden yükle. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Bir adadan blok limitini kaldır. COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Bir oyuncu tarafından verilen tüm değerlendirmeleri kaldır. COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Bir ada için bir dünyayı sıfırla. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Eklenti için şematikler oluştur. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Bir adanın biyomunu ayarla. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Belirli bir konumdaki blok miktarını ayarla. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Başka bir oyuncunun adası için blok limiti belirle. COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Başka bir oyuncunun adası için sandık satırlarını ayarla. COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Başka bir oyuncunun adası için co-op oyuncu limitini ayarla. COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Başka bir oyuncunun adası için bitki büyüme çarpanını ayarla. COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Bir oyuncunun ada dağıtma miktarını ayarla. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Başka bir oyuncunun adasının ada efekt seviyesini ayarla. COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Başka bir oyuncunun adası için varlık limitini ayarla. COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Bir adayı başkasına devret. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Başka bir oyuncunun adası için mob düşürme çarpanını ayarla. COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Tüm adalar için bir izne gerekli rolü ayarla. COMMAND_DESCRIPTION_ADMIN_SET_RATE: Başka bir oyuncunun değerlendirmesini ayarla. COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: Başka bir oyuncunun adası için rol limitini ayarla. COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Belirli bir ada için ayarları aç/kapat. COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Çakıl taşı jeneratörü için bir materyalin yüzdesini değiştir. COMMAND_DESCRIPTION_ADMIN_SET_SIZE: Başka bir oyuncunun ada boyutunu değiştir. COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Sunucunun doğuş konumunu ayarla. COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Başka bir oyuncunun adası için spawner oranları çarpanını ayarla. COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Başka bir oyuncunun adası için üye limitini ayarla. COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Başka bir oyuncunun adası için bir yükseltmenin seviyesini ayarla. COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Bir adanın ışınlanma limitini ayarla. COMMAND_DESCRIPTION_ADMIN_SETTINGS: Eklenti ayarları düzenleyicisini aç. COMMAND_DESCRIPTION_ADMIN_SHOW: Bir ada hakkında bilgi al. COMMAND_DESCRIPTION_ADMIN_SPAWN: Doğuş konumuna ışınlan. COMMAND_DESCRIPTION_ADMIN_SPY: Sohbet casusluk modunu aç/kapat. COMMAND_DESCRIPTION_ADMIN_STATS: Eklenti hakkında istatistikleri göster. COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: Bir adanın bonusunu oluşturulan dünyalarla senkronize et. COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Bir ada için yükseltme değerlerini senkronize et. COMMAND_DESCRIPTION_ADMIN_TELEPORT: Diğer adalara ışınlan. COMMAND_DESCRIPTION_ADMIN_TITLE: Bir oyuncuya başlık gönder. COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: Tüm ada üyelerine başlık gönder. COMMAND_DESCRIPTION_ADMIN_UNIGNORE: En iyi adalardan bir adayı yoksaymayı bırak. COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Bir ada için bir dünyanın kilidini aç. COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Başka bir oyuncunun ada bankasından para çek. COMMAND_DESCRIPTION_BALANCE: Bir adanın bankasındaki para miktarını kontrol et. COMMAND_DESCRIPTION_BAN: Adandan bir oyuncuyu yasakla. COMMAND_DESCRIPTION_BANK: Adanın bankasını aç. COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Adanın biyomunu değiştir. COMMAND_DESCRIPTION_BORDER: Adaların sınır rengini değiştir. COMMAND_DESCRIPTION_CHEST: Adanın sandığını aç. COMMAND_DESCRIPTION_CLOSE: Adanı halka kapat. COMMAND_DESCRIPTION_COOP: Adana bir oyuncuyu co-op olarak ekle. COMMAND_DESCRIPTION_COOPS: co-oplar menüsünü aç. COMMAND_DESCRIPTION_COUNTS: Adandaki blok sayılarını gör. COMMAND_DESCRIPTION_CREATE: Yeni bir ada oluştur. COMMAND_DESCRIPTION_DEL_WARP: Bir ada ışınlanmasını sil. COMMAND_DESCRIPTION_DEMOTE: Adandaki bir üyeyi rütbe düşür. COMMAND_DESCRIPTION_DEPOSIT: Kişisel hesabından adanın bankasına para yatır. COMMAND_DESCRIPTION_DISBAND: Adanı kalıcı olarak dağıt. COMMAND_DESCRIPTION_EXPEL: Adandan bir ziyaretçiyi kov. COMMAND_DESCRIPTION_FLY: Ada uçuşunu aç/kapat. COMMAND_DESCRIPTION_HELP: Tüm komutların listesi. COMMAND_DESCRIPTION_INVITE: Adana bir oyuncuyu davet et. COMMAND_DESCRIPTION_KICK: Adandan bir oyuncuyu at. COMMAND_DESCRIPTION_LANG: Kişisel dilini değiştir. COMMAND_DESCRIPTION_LEAVE: Adandan ayrıl. COMMAND_DESCRIPTION_MEMBERS: Üyeler menüsünü aç. COMMAND_DESCRIPTION_MISSION: Bir görevi tamamla. COMMAND_DESCRIPTION_MISSIONS: Görevler menüsünü aç. COMMAND_DESCRIPTION_NAME: Adanın adını değiştir. COMMAND_DESCRIPTION_OPEN: Adanı halka aç. COMMAND_DESCRIPTION_PANEL: Ada panelini aç. COMMAND_DESCRIPTION_PARDON: Adandan bir oyuncunun yasağını kaldır. COMMAND_DESCRIPTION_PERMISSIONS: Bir ada rolü için tüm izinleri al. COMMAND_DESCRIPTION_PROMOTE: Adandaki bir üyeyi rütbe yükselt. COMMAND_DESCRIPTION_RANKUP: Bir yükseltmeyi seviye atlat. COMMAND_DESCRIPTION_RATE: Bir adayı değerlendir. COMMAND_DESCRIPTION_RATINGS: Tüm ada değerlendirmelerini göster. COMMAND_DESCRIPTION_SETTINGS: Ayarlar menüsünü aç. COMMAND_DESCRIPTION_RECALC: Ada değerini yeniden hesapla. COMMAND_DESCRIPTION_SET_DISCORD: Ada ödemeleri için adanın discordunu ayarla. COMMAND_DESCRIPTION_SET_PAYPAL: Ada ödemeleri için adanın paypal e-postasını ayarla. COMMAND_DESCRIPTION_SET_ROLE: Adandaki bir oyuncunun rolünü değiştir. COMMAND_DESCRIPTION_SET_TELEPORT: Adanın ışınlanma konumunu değiştir. COMMAND_DESCRIPTION_SET_WARP: Yeni bir ada ışınlanması oluştur. COMMAND_DESCRIPTION_SHOW: Bir ada hakkında bilgi al. COMMAND_DESCRIPTION_TEAM: Ada üyelerinin durumu hakkında bilgi al. COMMAND_DESCRIPTION_TEAM_CHAT: Takım sohbet modunu aç/kapat. COMMAND_DESCRIPTION_TELEPORT: Adana ışınlan. COMMAND_DESCRIPTION_TOGGLE: Ada sınırlarını ve istiflenmiş blok yerleşimlerini aç/kapat. COMMAND_DESCRIPTION_TOP: En iyi adalar panelini aç. COMMAND_DESCRIPTION_TRANSFER: Adanın liderliğini devret. COMMAND_DESCRIPTION_UNCOOP: Adandan bir oyuncuyu co-op üyeliğinden çıkar. COMMAND_DESCRIPTION_UPGRADE: Yükseltmeler panelini aç. COMMAND_DESCRIPTION_VALUE: Bir bloğun değerini al. COMMAND_DESCRIPTION_VALUES: Değerler menüsünü aç. COMMAND_DESCRIPTION_VISIT: Bir adanın ziyaretçi konumuna ışınlan. COMMAND_DESCRIPTION_VISITORS: Ziyaretçiler menüsünü aç. COMMAND_DESCRIPTION_WARP: Bir ada ışınlanmasına ışınlan. COMMAND_DESCRIPTION_WARPS: Işınlanmalar menüsünü aç. COMMAND_DESCRIPTION_WITHDRAW: Adanın bankasından kişisel hesabına para çek. COMMAND_USAGE: '&cHatalı Kullanım: /{0}' COOP_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i co-op üyesi olarak ekledi.' COOP_BANNED_PLAYER: '&c&lHata | &7Bu oyuncu adadan yasaklandı ve co-op olamaz.' COOP_LIMIT_EXCEED: '&c&lHata | &7Ada, sahip olabileceği maksimum co-op oyuncu sayısına ulaştı.' CREATE_ISLAND: '&e&lAda | &7Yeni bir ada {0} konumunda {1}ms içinde oluşturuldu.' CREATE_ISLAND_FAILURE: '&c&lHata | &7Adanı oluştururken bir hata oluştu. Lütfen sorunu araştırmak için yöneticiyle iletişime geç.' CREATE_WORLD_FAILURE: '&c&lHata | &7Dünyanı oluştururken bir hata oluştu. Lütfen sorunu araştırmak için yöneticiyle iletişime geç.' DEBUG_MODE_DISABLED: '&e&lHata Ayıklama | &7Hata ayıklama modu &cKAPALI&7.' DEBUG_MODE_ENABLED: '&e&lHata Ayıklama | &7Hata ayıklama modu &aAÇIK&7.' DEBUG_MODE_FILTER_ADD: '&e&lHata Ayıklama | &7Hata ayıklama filtresi {0} &aAÇIK&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lHata Ayıklama | &7Tüm hata ayıklama filtreleri &cKAPALI&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lHata Ayıklama | &7Hata ayıklama filtresi {0} &cKAPALI&7.' DELETE_WARP: '&e&lAda | &7{0} ışınlanmasını sildin.' DELETE_WARP_SIGN_BROKE: '&7&oO ışınlanma için bir tabela vardı, kırıldı...' DEMOTE_LEADER: '&c&lHata | &7Ada liderlerini rütbe düşüremezsin.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip oyuncuları rütbe düşürebilirsin.' DEMOTED_MEMBER: '&e&lAda | &7{0}''ı adasında {1} olarak rütbe düşürdün.' DEPOSIT_ANNOUNCEMENT: '&e&lBanka | &7{0} ada bankasına ${1} yatırdı!' DEPOSIT_ERROR: '&c&lHata | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında kıramazsın.' DISBAND_ANNOUNCEMENT: '&e&lAda | &7Adan {0} tarafından dağıtıldı.' DISBAND_GIVE: '&e&lAda | &7{0} dağıtma hakkı aldın.' DISBAND_GIVE_ALL: '&e&lAda | &7Tüm oyunculara {0} dağıtma hakkı verdin.' DISBAND_GIVE_OTHER: '&e&lAda | &7{1}''e {0} dağıtma hakkı verdin.' DISBAND_ISLAND_BALANCE_REFUND: '&7&oAdan dağıtıldı ve ada bankasından hesabına ${0} dolar iade edildi.' DISBAND_SET: '&e&lAda | &7Dağıtma sayın {0} olarak ayarlandı.' DISBAND_SET_ALL: '&e&lAda | &7Tüm oyuncuların dağıtma sayısını {0} olarak ayarladın.' DISBAND_SET_OTHER: '&e&lAda | &7{0}''ın dağıtma sayısını {1} olarak ayarladın.' DISBANDED_ISLAND: '&e&lAda | &7Adanı dağıttın.' DISBANDED_ISLAND_OTHER: '&e&lAda | &7{0}''ın adasını dağıttın.' DISBANDED_ISLAND_OTHER_NAME: '&e&lAda | &7{0} adasını dağıttın.' ENTER_PVP_ISLAND: '&7&oPVP etkin olan bir adaya ışınlandın. Sonraki 10 saniye boyunca PVP''ye karşı dokunulmazsın...' EXPELLED_PLAYER: '&e&lAda | &7{0} adadan kovuldu.' FORMAT_QUAD: Q FORMAT_TRILLION: T FORMAT_BILLION: B FORMAT_MILLION: M FORMAT_THOUSANDS: K FORMAT_SECONDS_NAME: saniye FORMAT_SECOND_NAME: saniye FORMAT_MINUTES_NAME: dakika FORMAT_MINUTE_NAME: dakika FORMAT_HOURS_NAME: saat FORMAT_HOUR_NAME: saat FORMAT_DAYS_NAME: gün FORMAT_DAY_NAME: gün GENERATOR_CLEARED: '&e&lAda | &7{0}''ın adası için jeneratör miktarları başarıyla temizlendi.' GENERATOR_CLEARED_NAME: '&e&lAda | &7{0} adasının jeneratör miktarları başarıyla temizlendi.' GENERATOR_CLEARED_ALL: '&e&lAda | &7Tüm adalar için jeneratör miktarları başarıyla temizlendi.' GENERATOR_UPDATED: '&e&lAda | &7{0}''ın jeneratör miktarı başarıyla {1}''in adasına güncellendi.' GENERATOR_UPDATED_NAME: '&e&lAda | &7{0}''ın jeneratör miktarı başarıyla {1} adasına güncellendi.' GENERATOR_UPDATED_ALL: '&e&lAda | &7{0}''ın jeneratör miktarı tüm adalar için başarıyla güncellendi.' GLOBAL_COMMAND_EXECUTED: '&e&lAda | &7Komut {0}''ın ada üyelerinde başarıyla çalıştırıldı!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&lAda | &7Komut {0} adasının üyelerinde başarıyla çalıştırıldı!' GLOBAL_MESSAGE_SENT: '&e&lAda | &7{0}''ın ada üyelerine mesaj başarıyla gönderildi!' GLOBAL_MESSAGE_SENT_NAME: '&e&lAda | &7{0} adasının üyelerine mesaj başarıyla gönderildi!' GLOBAL_TITLE_SENT: '&e&lAda | &7{0}''ın ada üyelerine başlık başarıyla gönderildi!' GLOBAL_TITLE_SENT_NAME: '&e&lAda | &7{0} adasının üyelerine başlık başarıyla gönderildi!' GOT_BANNED: '&e&lAda | &7{0}''ın adasından YASAKLANDIN.' GOT_DEMOTED: '&e&lAda | &7Adanda {0} olarak rütbe düşürüldün.' GOT_EXPELLED: '&e&lAda | &7&o{0} tarafından adadan kovuldun.' GOT_INVITE: '&e&lAda | &7{0} seni adasına davet etti.' GOT_INVITE_TOOLTIP: '&7Daveti kabul etmek için mesaja tıkla.' GOT_KICKED: '&e&lAda | &7{0} tarafından adandan atıldın.' GOT_PROMOTED: '&e&lAda | &7Adanda {0} olarak rütbe yükseltildin.' GOT_REVOKED: '&e&lAda | &7{0} adasına olan davetini geri çekti.' GOT_UNBANNED: '&e&lAda | &7{0}''ın adasından YASAĞIN KALDIRILDI.' HIT_ISLAND_MEMBER: '&c&lHata | &7Ada üyelerine vuramazsın.' HIT_PLAYER_IN_ISLAND: '&c&lHata | &7Adaların içindeki oyunculara vuramazsın.' IGNORED_ISLAND: '&e&lAda | &7{0}''ın adası artık en iyi adalardan yoksayılıyor.' IGNORED_ISLAND_NAME: '&e&lAda | &7{0} adası artık en iyi adalardan yoksayılıyor.' INTERACT_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında etkileşime geçemezsin.' INVALID_AMOUNT: '&c&lHata | &7Geçersiz miktar {0}.' INVALID_BIOME: '&c&lHata | &7Geçersiz biyom {0}.' INVALID_BLOCK: '&c&lHata | &7Geçersiz blok konumu {0}.' INVALID_BORDER_COLOR: '&c&lHata | &7Geçersiz sınır rengi {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lHata | &7Geçersiz efekt {0}.' INVALID_ENTITY: '&c&lHata | &7Geçersiz varlık {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lHata | &7Geçersiz aralık {0}.' INVALID_ISLAND: '&c&lHata | &7Bir adan yok.' INVALID_ISLAND_LOCATION: '&c&lHata | &7Konumunda bir ada bulunmuyor.' INVALID_ISLAND_OTHER: '&c&lHata | &7{0}''ın bir adası yok.' INVALID_ISLAND_OTHER_NAME: '&c&lHata | &7{0} adında bir ada bulunmuyor.' INVALID_ISLAND_PERMISSION: | &c&lHata | &7Ada izni {0} bulunamadı. &c&lHata | &7Ada İzinleri: {1} INVALID_LEVEL: '&c&lHata | &7Geçersiz seviye {0}.' INVALID_LIMIT: '&c&lHata | &7Geçersiz limit {0}.' INVALID_MATERIAL: '&c&lHata | &7Geçersiz materyal {0}.' INVALID_MATERIAL_DATA: '&c&lHata | &7Geçersiz materyal-veri {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lHata | &7Geçersiz görev {0}.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lHata | &7Geçersiz modül {0}.' INVALID_MULTIPLIER: '&c&lHata | &7Geçersiz çarpan {0}.' INVALID_PAGE: '&c&lHata | &7Geçersiz sayfa {0}.' INVALID_PERCENTAGE: '&c&lHata | &7Yüzde 0 ile 100 arasında olmalıdır.' INVALID_PLAYER: '&c&lHata | &7{0} adında bir oyuncu bulunamadı.' INVALID_RATE: | &c&lHata | &7{0} adında bir değerlendirme bulunamadı. &c&lHata | &7Ada Değerlendirmeleri: {1} INVALID_ROWS: '&c&lHata | &7Geçersiz satır sayısı: {0}' INVALID_ROLE: | &c&lHata | &7Ada rolü {0} bulunamadı. &c&lHata | &7Ada Rolleri: {1} INVALID_SCHEMATIC: '&c&lHata | &7{0} adında bir şematik bulunamadı.' INVALID_SETTINGS: | &c&lHata | &7Ada ayarları {0} bulunamadı. &c&lHata | &7Ada Ayarları: {1} INVALID_SIZE: '&c&lHata | &7Geçersiz boyut {0}.' INVALID_SLOT: '&c&lHata | &7Geçersiz yuva {0}.' INVALID_TITLE: '&c&lHata | &7Geçersiz başlık girildi.' INVALID_TOGGLE_MODE: '&c&lHata | &7{0} açılamaz/kapatılamaz.' INVALID_UPGRADE: | &c&lHata | &7{0} adında bir yükseltme bulunamadı. &c&lHata | &7Yükseltmeler: {1} INVALID_VISIT_LOCATION: '&c&lHata | &7Bu adanın ziyaretçi konumu yok.' INVALID_VISIT_LOCATION_BYPASS: '&7&oBypass modundasın, adaya ışınlanıyorsun...' INVALID_WARP: '&c&lHata | &7Geçersiz ışınlanma {0}.' INVALID_WORLD: '&c&lHata | &7Geçersiz dünya {0}.' INVITE_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i adaya davet etti.' INVITE_BANNED_PLAYER: '&c&lHata | &7Bu oyuncu adadan yasaklandı ve davet edilemez.' INVITE_TO_FULL_ISLAND: '&c&lHata | &7Adana daha fazla üye davet edemezsin.' ISLAND_ALREADY_CLOSED: '&c&lHata | &7Ada zaten halka kapalı.' ISLAND_ALREADY_EXIST: '&c&lHata | &7Bu adla bir ada zaten var.' ISLAND_ALREADY_OPENED: '&c&lHata | &7Ada zaten halka açık.' ISLAND_BANK_EMPTY: '&e&lBanka | &7Ada bankası boş.' ISLAND_BANK_SHOW: '&e&lBanka | &7Adanda ${0} var.' ISLAND_BANK_SHOW_OTHER: '&e&lBanka | &7{0}''ın adasında ${1} var.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanka | &7{0} adasında ${1} var.' ISLAND_BEING_CALCULATED: '&c&lHata | &7Ada yeniden hesaplanırken bloklarla etkileşime geçemezsin!' ISLAND_CLOSED: '&e&lAda | &7Ada başarıyla halka kapatıldı.' ISLAND_CREATE_PROCESS_FAIL: '&c&lHata | &7Zaten devam eden bir ada oluşturma görevin var.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lAda | &7İsteğiniz işleniyor...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lUçuş | &7Ada uçuşu otomatik olarak &ckapatıldı&7.' ISLAND_FLY_ENABLED: '&e&lUçuş | &7Ada uçuşu otomatik olarak &aaçıldı&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lAda | &7&oDağıtılan bir adanın içindeydin, bu yüzden doğuşa ışınlandın...' ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lAda | &7&oPVP''nin açıldığı bir adanın içindeydin, bu yüzden doğuşa ışınlandın...' ISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Geliştiren: Ome_R' ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Komutlar Listesi [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Sonraki sayfa için /is help {0} kullan.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lAda | &7Banka Limiti: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lAda | &7Blok Limitleri: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lAda | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lAda | &7co-op Limiti: {0}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lAda | &7Bitki Çarpanı: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lAda | &7Düşürme Çarpanı: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lAda | &7Ada Efektleri: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lAda | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lAda | &7Varlık Limitleri: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lAda | &7 {0}: {1}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lAda | &7Jeneratör Oranları ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lAda | &7 {0}: %{1} ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lAda | &7Rol Limitleri: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lAda | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lAda | &7Sınır Boyutu: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lAda | &7Spawner Çarpanı: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lAda | &7Takım Limiti: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lAda | &7Yükseltmeler: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lAda | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lAda | &7Işınlanma Limiti: {0}' ISLAND_INFO_BANK: '&e&lAda | &7Banka: {0}' ISLAND_INFO_BONUS: '&e&lAda | &7Değer Bonusu: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lAda | &7Seviye Bonusu: {0}' ISLAND_INFO_CREATION_TIME: '&e&lAda | &7Oluşturma Süresi: {0}' ISLAND_INFO_DISCORD: '&e&lAda | &7Discord: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lAda | &7Son Güncelleme: {0} önce' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lAda | &7Son Güncelleme: &aŞu Anda Aktif' ISLAND_INFO_LEVEL: '&e&lAda | &7Seviye: {0}' ISLAND_INFO_LOCATION: '&e&lAda | &7Ev: {0}' ISLAND_INFO_NAME: '&e&lAda | &7Adı: {0}' ISLAND_INFO_OWNER: '&e&lAda | &7Lider: {0}' ISLAND_INFO_PAYPAL: '&e&lAda | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lAda | &7 - {0}' ISLAND_INFO_RATE: '&e&lAda | &7Değerlendirme: {0} &7({1}/5) - {2} toplam değerlendirme.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: ✦ ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lAda | &7{0}lar: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lAda | &7Ziyaretçi Sayısı: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lAda | &7Değer: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lAda | &7Ada başarıyla halka açıldı.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lÖnizleme | &7Çok uzaklaştın ve artık önizleme modunda değilsin.' ISLAND_PREVIEW_CANCEL: '&e&lÖnizleme | &7Önizleme modunu iptal ettin.' ISLAND_PREVIEW_CONFIRM_TEXT: 'ONAYLA' ISLAND_PREVIEW_CANCEL_TEXT: 'İPTAL ET' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lÖnizleme | &7{0} şematiği için önizleme modunu başlattı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. &e&lÖnizleme | &7Ada alanından ayrılamazsın, aksi takdirde önizleme modu otomatik olarak iptal edilir. ISLAND_PROTECTED: '&c&lHata | &7Bu ada korumalı.' ISLAND_PROTECTED_OPPED: '&7&o"/is admin bypass" komutunu kullanarak bu kısıtlamayı atlayabilirsin.' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lAda | &7{0}''ın Adası Üyeleri &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Çevrimdışı)' ISLAND_TEAM_STATUS_ONLINE: '&a(Çevrimiçi)' ISLAND_TEAM_STATUS_ROLES: '&e&lAda | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Çevrimdışı)' ISLAND_TOP_STATUS_ONLINE: '&a(Çevrimiçi)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Özel]' ISLAND_WAS_CLOSED: '&e&lAda | &7&oİçinde bulunduğun ada kapatıldı ve doğuşa ışınlandın...' ISLAND_WORTH_ERROR: '&c&lHata | &7Adanı hesaplarken beklenmedik bir hata oluştu. Sorun devam ederse yöneticilerle iletişime geç.' ISLAND_WORTH_RESULT: '&e&lAda | &7Adanın değeri {0} [Seviye {1}]' ISLAND_WORTH_TIME_OUT: '&c&lHata | &7Hesaplama görevi zaman aşımına uğradı. Daha sonra tekrar dene...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lAda | &7{0} adana katıldı.' JOIN_ANNOUNCEMENT: '&e&lAda | &7{0} adana katıldı.' JOIN_FULL_ISLAND: '&c&lHata | &7Bu ada, izin verilen maksimum üye sayısına ulaştı.' JOIN_WHILE_IN_ISLAND: '&c&lHata | &7Zaten bir adadasın.' JOINED_ISLAND: '&e&lAda | &7{0}''ın adasına katıldın.' JOINED_ISLAND_NAME: '&e&lAda | &7{0} adasına katıldın.' JOINED_ISLAND_AS_COOP: '&e&lAda | &7Artık {0}''ın adasında co-op üyesisin.' JOINED_ISLAND_AS_COOP_NAME: '&e&lAda | &7Artık {0} adasında co-op üyesisin.' KICK_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan atıldı.' KICK_ISLAND_LEADER: '&c&lHata | &7Ada liderini atamazsın, bunun yerine /is admin disband kullan.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip oyuncuları atabilirsin.' LACK_CHANGE_PERMISSION: '&c&lHata | &7Bu izni başka rollere değiştirebilmek için bu izne sahip olmalısın.' LAST_ROLE_DEMOTE: '&c&lHata | &7Bu oyuncuyu artık rütbe düşüremezsin.' LAST_ROLE_PROMOTE: '&c&lHata | &7Bu oyuncuyu artık rütbe yükseltemezsin.' LEAVE_ANNOUNCEMENT: '&e&lAda | &7{0} adadan ayrıldı.' LEAVE_ISLAND_AS_LEADER: |- &c&lHata | &7Sahibi olduğun adandan ayrılamazsın. &c&lHata | &7Liderliği /is transfer kullanarak devredebilirsin.' LEFT_ISLAND: '&e&lAda | &7Adandan ayrıldın.' LEFT_ISLAND_COOP: '&e&lAda | &7Artık {0}''ın adasında co-op üyesi değilsin.' LEFT_ISLAND_COOP_NAME: '&e&lAda | &7Artık {0} adasında co-op üyesi değilsin.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lHata | &7Katı bir materyal sağlamalısın.' MAXIMUM_LEVEL: '&c&lHata | &7Bu yükseltme için maksimum seviye {0}.' MESSAGE_SENT: '&e&lAda | &7{0}''e mesaj başarıyla gönderildi!' MISSION_CANNOT_COMPLETE: '&c&lHata | &7Bu görevi henüz tamamlayamazsın.' MISSION_NO_AUTO_REWARD: '&e&lGörev | &7{0}''i bitirmek için gerekli tüm materyallere sahipsin - tamamlamak için /is missions kullan!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lHata | &7Bu görevi tamamlamadan önce {0}''i tamamlamalısın.' MISSION_STATUS_COMPLETE: '&e&lGörev | &7{1} için {0} görevinin durumu tamamlandı olarak değiştirildi.' MISSION_STATUS_COMPLETE_ALL: '&e&lGörev | &7{0} için tüm görevlerin durumu tamamlandı olarak değiştirildi.' MISSION_STATUS_RESET: '&e&lGörev | &7{1} için {0} görevinin durumu sıfırlandı.' MISSION_STATUS_RESET_ALL: '&e&lGörev | &7{0} için tüm görevlerin durumu sıfırlandı.' MODULE_ALREADY_INITIALIZED: '&e&lModül | &7Bu modül zaten yüklü.' MODULE_INFO: | &e&lModül | &7{0} geliştiren: {1} &e&lModül | &7&m-------------------- &e&lModül | &7{2} MODULE_LOADED_SUCCESS: '&e&lModül | &7{0} modülü başarıyla yüklendi.' MODULE_LOADED_FAILURE: '&e&lModül | &7{0} modülü yüklenemedi. Daha fazla bilgi için konsolu kontrol et.' MODULE_UNLOADED_SUCCESS: '&e&lModül | &7Modül başarıyla kaldırıldı.' MODULES_LIST: '&fModüller ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lAda | &7{0} adasının adını {1}&7 olarak değiştirdi.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lHata | &7Bu adı kullanamazsın.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lHata | &7Oyuncu adlarını ada adı olarak kullanamazsın.' NAME_TOO_LONG: '&c&lHata | &7Ada adları {0} karakterden uzun olamaz.' NAME_TOO_SHORT: '&c&lHata | &7Ada adları {0} karakterden kısa olamaz.' NO_BAN_PERMISSION: '&c&lHata | &7Oyuncuları yasaklayabilmek için en az {0} olmalısın.' NO_CLOSE_BYPASS: '&c&lHata | &7Bu ada halka açık değil.' NO_CLOSE_PERMISSION: '&c&lHata | &7Adanı halka kapatabilmek için en az {0} olmalısın.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lHata | &7Oyuncuları co-op üyesi olarak ekleyebilmek için en az {0} olmalısın.' NO_DELETE_WARP_PERMISSION: '&c&lHata | &7Işınlanmaları silebilmek için en az {0} olmalısın.' NO_DEMOTE_PERMISSION: '&c&lHata | &7Oyuncuları rütbe düşürebilmek için en az {0} olmalısın.' NO_DEPOSIT_PERMISSION: '&c&lHata | &7Ada bankasına para yatırabilmek için en az {0} olmalısın.' NO_DISBAND_PERMISSION: '&c&lHata | &7Adanı dağıtabilmek için en az {0} olmalısın.' NO_EXPEL_PERMISSION: '&c&lHata | &7Adandan oyuncuları kovabilmek için en az {0} olmalısın.' NO_INVITE_PERMISSION: '&c&lHata | &7Oyuncuları davet edebilmek için en az {0} olmalısın.' NO_ISLAND_CHEST_PERMISSION: '&c&lHata | &7Ada sandığına erişebilmek için en az {0} olmalısın.' NO_ISLAND_INVITE: '&c&lHata | &7Bu adadan herhangi bir davet bulunamadı.' NO_ISLANDS_TO_PURGE: '&c&lHata | &7Temizlenecek ada bulunamadı.' NO_KICK_PERMISSION: '&c&lHata | &7Oyuncuları atabilmek için en az {0} olmalısın.' NO_MORE_DISBANDS: '&c&lHata | &7Daha fazla ada dağıtamazsın.' NO_MORE_WARPS: '&c&lHata | &7Adanın daha fazla ışınlanma noktası olamaz.' NO_NAME_PERMISSION: '&c&lHata | &7Adanın adını değiştiremezsin.' NO_OPEN_PERMISSION: '&c&lHata | &7Adanı halka açabilmek için en az {0} olmalısın.' NO_PERMISSION_CHECK_PERMISSION: '&c&lHata | &7İzinler hakkında bilgi alabilmek için en az {0} olmalısın.' NO_PROMOTE_PERMISSION: '&c&lHata | &7Oyuncuları rütbe yükseltebilmek için en az {0} olmalısın.' NO_RANKUP_PERMISSION: '&c&lHata | &7Yükseltmeleri seviye atlamak için iznin yok.' NO_RATINGS_PERMISSION: '&c&lHata | &7Değerlendirmeleri kontrol edebilmek için en az {0} olmalısın.' NO_SET_BIOME_PERMISSION: '&c&lHata | &7Ada biyomunu değiştirebilmek için en az {0} olmalısın.' NO_SET_DISCORD_PERMISSION: '&c&lHata | &7Ada discordunu değiştirebilmek için en az {0} olmalısın.' NO_SET_HOME_PERMISSION: '&c&lHata | &7Adanın ışınlanma konumunu ayarlayabilmek için en az {0} olmalısın.' NO_SET_PAYPAL_PERMISSION: '&c&lHata | &7Ada paypal e-postasını değiştirebilmek için en az {0} olmalısın.' NO_SET_ROLE_PERMISSION: '&c&lHata | &7Oyuncular için rol ayarlayabilmek için en az {0} olmalısın.' NO_SET_SETTINGS_PERMISSION: '&c&lHata | &7Ada ayarlarını değiştirebilmek için en az {0} olmalısın.' NO_SET_WARP_PERMISSION: '&c&lHata | &7Ada ışınlanmalarını ayarlayabilmek için en az {0} olmalısın.' NO_TRANSFER_PERMISSION: '&c&lHata | &7Liderliği devredebilmek için adanın lideri olmalısın.' NO_UNCOOP_PERMISSION: '&c&lHata | &7Oyuncuları co-op üyeliğinden çıkarabilmek için en az {0} olmalısın.' NO_UPGRADE_PERMISSION: '&c&lHata | &7Başka bir seviyeye yükseltmek için iznin yok.' NO_WITHDRAW_PERMISSION: '&c&lHata | &7Ada bankasından para çekebilmek için en az {0} olmalısın.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lHata | &7Adanın bankasına {0} dolar yatırmak için yeterli paran yok.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lHata | &7Yeterli paran yok.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lHata | &7Ada ışınlanmalarını kullanmak için yeterli paran yok.' OPEN_MENU_WHILE_SLEEPING: '&7&oMenülerle etkileşime geçmek için çok mu yorgunsun, sence de öyle değil mi?' PANEL_TOGGLE_OFF: |- &e&lPanel | &7Ada paneli &cKAPALI&7. &e&lPanel | &7/is çalıştırmak seni adaya ışınlayacak. PANEL_TOGGLE_ON: |- &e&lPanel | &7Ada paneli &aAÇIK&7. &e&lPanel | &7/is çalıştırmak paneli senin için açacak. PERMISSION_CHANGED: '&e&lAda | &7{1}''in adasının {0} izni başarıyla güncellendi.' PERMISSION_CHANGED_NAME: '&e&lAda | &7{1} adasının {0} izni başarıyla güncellendi.' PERMISSION_CHANGED_ALL: '&e&lAda | &7Tüm adalar için {0} izni başarıyla güncellendi.' PERSISTENT_DATA_EMPTY: '&c&lHata | &7Sorgun için veri bulunamadı.' PERSISTENT_DATA_MODIFY: '&e&lVeri | &7{0} için veri {1} ile {2} olarak başarıyla ayarlandı.' PERSISTENT_DATA_SHOW: '&e&lVeri | &7{0} verisi: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lVeri | &7{0} için {1} yolundan veri başarıyla kaldırıldı.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lAda | &7{0} için tüm izinler varsayılan değerlere başarıyla sıfırlandı!' PERMISSIONS_RESET_ROLES: '&e&lAda | &7Adanın tüm izinleri varsayılan değerlere başarıyla sıfırlandı!' PLACEHOLDER_NO: Hayır PLACEHOLDER_YES: Evet PLAYER_ALREADY_BANNED: '&c&lHata | &7Bu oyuncu zaten yasaklı.' PLAYER_ALREADY_COOP: '&c&lHata | &7Bu oyuncu zaten co-op.' PLAYER_ALREADY_IN_ISLAND: '&c&lHata | &7Bu oyuncu zaten bir adada.' PLAYER_ALREADY_IN_ROLE: '&c&lHata | &7{0} zaten bir {1}.' PLAYER_EXPEL_BYPASS: '&c&lHata | &7Bu kullanıcı adadan kovulamaz.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lAda | &7{0} sunucuya katıldı.' PLAYER_NOT_BANNED: '&c&lHata | &7Bu oyuncu yasaklı değil.' PLAYER_NOT_COOP: '&c&lHata | &7Bu oyuncu co-op değil.' PLAYER_NOT_INSIDE_ISLAND: '&c&lHata | &7Bu oyuncu adanın içinde değil.' PLAYER_NOT_ONLINE: '&c&lHata | &7Bu oyuncu çevrimiçi değil!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lAda | &7{0} sunucudan ayrıldı.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip oyuncuları rütbe yükseltebilirsin.' PROMOTED_MEMBER: '&e&lAda | &7{0}''ı adasında {1} olarak rütbe yükselttin.' PURGE_CLEAR: '&e&lAda | &7Temizlenecek tüm sıralanmış adalar başarıyla temizlendi.' PURGED_ISLANDS: |- &e&lAda | &7Sunucu yeniden başladığında {0} ada temizlenecek. &e&lAda | &7İstediğin zaman /is admin purge cancel kullanarak iptal edebilirsin.' RANKUP_SUCCESS: '&e&lAda | &7{1}''in adası için {0} yükseltmesinin seviyesi başarıyla güncellendi.' RANKUP_SUCCESS_ALL: '&e&lAda | &7Tüm adalar için {0} yükseltmesinin seviyesi başarıyla güncellendi.' RANKUP_SUCCESS_NAME: '&e&lAda | &7{1} adası için {0} yükseltmesinin seviyesi başarıyla güncellendi.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lAda | &7{0} adanı 5 üzerinden {1} olarak değerlendirdi!.' RATE_CHANGE_OTHER: '&e&lAda | &7{0}''ın değerlendirmesini {1} olarak değiştirdin.' RATE_OWN_ISLAND: '&c&lHata | &7Kendi adanı değerlendiremezsin.' RATE_REMOVE_ALL: '&e&lAda | &7{0}''ın tüm değerlendirmeleri başarıyla kaldırıldı.' RATE_REMOVE_ALL_ISLANDS: '&e&lAda | &7Tüm adaların tüm değerlendirmeleri başarıyla kaldırıldı.' RATE_SUCCESS: '&e&lAda | &7Bu adayı {0} yıldızla değerlendirdin!' REACHED_BLOCK_LIMIT: '&e&lYükseltmeler | &7Ada için {0} Bloğu limitine ulaştın.' REACHED_ENTITY_LIMIT: '&e&lYükseltmeler | &7Varlık {0} için adanın limitine ulaştın.' RECALC_ALREADY_RUNNING: '&c&lHata | &7Adan zaten yeniden hesaplanıyor.' RECALC_ALREADY_RUNNING_OTHER: '&c&lHata | &7Bu ada zaten yeniden hesaplanıyor.' RECALC_ALL_ISLANDS: '&e&lAda | &7Tüm adalar yeniden hesaplanıyor...' RECALC_ALL_ISLANDS_DONE: '&e&lAda | &7Tüm adaların yeniden hesaplanması başarıyla tamamlandı.' RECALC_PROCCESS_REQUEST: '&e&lAda | &7İsteğiniz işleniyor...' RELOAD_COMPLETED: '&e&lAda | &7Yeniden yükleme tamamlandı!' RELOAD_PROCCESS_REQUEST: '&e&lAda | &7Yapılandırmalar yeniden yükleniyor...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''e adaya olan davetini geri çekti.' RESET_WORLD_SUCCEED: '&e&lAda | &7{1}''in adası için {0} dünyası başarıyla sıfırlandı.' RESET_WORLD_SUCCEED_ALL: '&e&lAda | &7Tüm adalar için {0} dünyası başarıyla sıfırlandı.' RESET_WORLD_SUCCEED_NAME: '&e&lAda | &7{1} adası için {0} dünyası başarıyla sıfırlandı.' SAME_NAME_CHANGE: '&c&lHata | &7Mevcut ada adından farklı bir ad girmelisin.' SCHEMATIC_LEFT_SELECT: '&e&lŞematikler | &7Konum #2 ({0}) seçildi.' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lHata | &7İki konum seçmedin.' SCHEMATIC_PROCCESS_REQUEST: '&e&lŞematikler | &7İsteğiniz işleniyor...' SCHEMATIC_READY_TO_CREATE: | &e&lŞematikler | &7İki konum seçtin. Yeni bir şematik oluşturmak için /is admin schematic komutunu çalıştır. &e&lŞematikler | &7Komutu çalıştırırken ışınlanma konumunda durduğundan emin ol. SCHEMATIC_RIGHT_SELECT: '&e&lŞematikler | &7Konum #1 ({0}) seçildi.' SCHEMATIC_SAVED: '&e&lŞematikler | &7Şematik başarıyla kaydedildi!' SELF_ROLE_CHANGE: '&c&lHata | &7Kendi rolünü değiştiremezsin.' SET_UPGRADE_LEVEL: '&e&lYükseltmeler | &7{1}''in adası için {0} seviyesi başarıyla güncellendi.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lYükseltmeler | &7{1} adası için {0} seviyesi başarıyla güncellendi.' SET_WARP: '&e&lAda | &7{0} konumunda yeni bir ışınlanma noktası başarıyla oluşturuldu.' SET_WARP_OUTSIDE: '&c&lHata | &7Adanın dışında ışınlanma noktası ayarlayamazsın.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lAda | &7{1}''in adası için {0} ayarları başarıyla güncellendi.' SETTINGS_UPDATED_NAME: '&e&lAda | &7{1} adası için {0} ayarları başarıyla güncellendi.' SETTINGS_UPDATED_ALL: '&e&lAda | &7Tüm adalar için {0} ayarları başarıyla güncellendi.' SIZE_BIGGER_MAX: '&c&lHata | &7Maksimum ada boyutundan daha büyük bir boyut ayarlayamazsın.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lDoğuş | &7{0} başarıyla doğuşa ışınlandı.' SPAWN_SET_SUCCESS: '&e&lDoğuş | &7Doğuş konumu {0} olarak başarıyla güncellendi.' SPY_TEAM_CHAT_FORMAT: '&7[Casus] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&lYükseltmeler | &7{0}''ın adasının tüm yükseltme değerleri başarıyla senkronize edildi.' SYNC_UPGRADES_ALL: '&e&lYükseltmeler | &7Tüm adaların tüm yükseltme değerleri başarıyla senkronize edildi.' SYNC_UPGRADES_NAME: '&e&lYükseltmeler | &7{0} adasının tüm yükseltme değerleri başarıyla senkronize edildi.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lHata | &7Adanın içinde değilsin.' TELEPORT_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışına ışınlanamazsın.' TELEPORT_WARMUP: '&7&o{0} içinde ışınlanacaksın... Hareket etme!' TELEPORT_WARMUP_CANCEL: '&7&oHareket ettin ve ışınlanma iptal edildi.' TITLE_SENT: '&e&lAda | &7{0}''e başlık başarıyla gönderildi!' TELEPORTED_FAILED: '&e&lAda | &7Görünüşe göre bu adanın güvenli blokları yok. Lütfen bir yetkiliyle iletişime geç.' TELEPORTED_SUCCESS: '&e&lAda | &7Adana ışınlandın.' TELEPORTED_TO_WARP: '&e&lAda | &7Bu ada ışınlanmasına başarıyla ışınlandın.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lAda | &7Oyuncu {0} {1} ada ışınlanmasına ışınlandı.' TOGGLED_BYPASS_OFF: '&e&lBypass | &7Bypass modu &cKAPALI&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Bypass modu &aAÇIK&7.' TOGGLED_FLY_OFF: '&e&lUçuş | &7Ada uçuşu &cKAPALI&7.' TOGGLED_FLY_ON: '&e&lUçuş | &7Ada uçuşu &aAÇIK&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lŞematikler | &7Şematik modu &cKAPALI&7.' TOGGLED_SCHEMATIC_ON: |- &e&lŞematikler | &7Şematik modu &aAÇIK&7. &e&lŞematikler | &7Altın bir balta kullanarak bir alan seç. TOGGLED_SPY_OFF: '&e&lCasus | &7Sohbet casusluğu &cKAPALI&7.' TOGGLED_SPY_ON: '&e&lCasus | &7Sohbet casusluğu &aAÇIK&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lİstifleyici | &7Blok istifleyici &cKAPALI&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lİstifleyici | &7Blok istifleyici &aAÇIK&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lSohbet | &7Takım sohbeti &cKAPALI&7.' TOGGLED_TEAM_CHAT_ON: '&e&lSohbet | &7Takım sohbeti &aAÇIK&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lSınır | &7Dünya sınırı &cKAPALI&7.' TOGGLED_WORLD_BORDER_ON: '&e&lSınır | &7Dünya sınırı &aAÇIK&7.' TRANSFER_ADMIN: '&e&lAda | &7{0}''ın liderliğini {1}''e devrettin.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lHata | &7{0} zaten adasının lideri.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lHata | &7Bu oyuncular aynı adalarda değil.' TRANSFER_ADMIN_NOT_LEADER: '&c&lHata | &7Bu oyuncu hiçbir adanın lideri değil.' TRANSFER_ALREADY_LEADER: '&c&lHata | &7Zaten bu adanın liderisin.' TRANSFER_BROADCAST: '&e&lAda | &7Adanın liderliği {0}''e devredildi.' UNBAN_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan YASAĞI KALDIRILDI.' UNCOOP_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i co-op üyeliğinden çıkardı.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&lAda | &7Çevrimiçi ada üyesi yok ve bu yüzden otomatik olarak co-op üyeliğinden çıkarıldın.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lAda | &7{0} oyundan ayrıldı ve artık co-op üyesi değil.' UNIGNORED_ISLAND: '&e&lAda | &7{0}''ın adası artık en iyi adalardan yoksayılmıyor.' UNIGNORED_ISLAND_NAME: '&e&lAda | &7{0} adası artık en iyi adalardan yoksayılmıyor.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lDünyalar | &7{0} dünyan artık kilitli değil!' UNSAFE_WARP: '&e&lAda | &7&oBu ışınlanma güvensiz görünüyor. Lütfen başka bir ışınlanmayı dene.' UPDATED_PERMISSION: '&e&lAda | &7{0} için izinler güncellendi.' UPDATED_SETTINGS: '&e&lAda | &7Ada ayarları {0} güncellendi.' UPGRADE_COOLDOWN_FORMAT: '&c&lHata | &7Sadece {0} içinde tekrar yükseltme yapabilirsin.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lHata | &7Bu komutu başka adalarda kullanamazsın.' WARP_ALREADY_EXIST: '&c&lHata | &7Bu adla bir ışınlanma noktası zaten var.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lIşınlanmalar | &7Yeni bir açıklama gir (İptal etmek için "-cancel" yaz): &e&lIşınlanmalar | &7Satırları "\n" kullanarak ayırabilirsin. WARP_CATEGORY_ICON_NEW_NAME: '&e&lIşınlanmalar | &7Bir ad gir (İptal etmek için "-cancel" yaz):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&lIşınlanmalar | &7Yeni bir materyal türü gir (İptal etmek için "-cancel" yaz):' WARP_CATEGORY_ICON_UPDATED: '&e&lIşınlanmalar | &7Kategorinin simgesi başarıyla güncellendi.' WARP_CATEGORY_ILLEGAL_NAME: '&c&lHata | &7Işınlanma kategorisi adları boş olamaz.' WARP_CATEGORY_NAME_TOO_LONG: '&c&lHata | Işınlanma kategorisi adları 255 karakterden uzun olamaz.' WARP_CATEGORY_SLOT: '&e&lIşınlanmalar | &7Yeni bir yuva gir (İptal etmek için "-cancel" yaz):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lHata | &7Bu yuva zaten başka bir kategori tarafından alınmış.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lIşınlanmalar | &7Kategorinin yuvası başarıyla {0} olarak değiştirildi.' WARP_CATEGORY_RENAME: '&e&lIşınlanmalar | &7Yeni bir ad gir (İptal etmek için "-cancel" yaz):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lHata | &7Bu ad zaten başka bir kategori tarafından alınmış.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lIşınlanmalar | &7Kategori adı başarıyla {0} olarak değiştirildi.' WARP_ICON_NEW_LORE: | &e&lIşınlanmalar | &7Yeni bir açıklama gir (İptal etmek için "-cancel" yaz): &e&lIşınlanmalar | &7Satırları "\n" kullanarak ayırabilirsin. WARP_ICON_NEW_NAME: '&e&lIşınlanmalar | &7Bir ad gir (İptal etmek için "-cancel" yaz):' WARP_ICON_NEW_TYPE: '&e&lIşınlanmalar | &7Yeni bir materyal türü gir (İptal etmek için "-cancel" yaz):' WARP_ICON_UPDATED: '&e&lIşınlanmalar | &7Işınlanmanın simgesi başarıyla güncellendi.' WARP_ILLEGAL_NAME: '&c&lHata | &7Işınlanma adları boş olamaz.' WARP_LOCATION_UPDATE: '&e&lIşınlanmalar | &7Işınlanmanın konumu senin konumuna başarıyla güncellendi.' WARP_NAME_TOO_LONG: '&c&lHata | Işınlanma adları 255 karakterden uzun olamaz.' WARP_PUBLIC_UPDATE: '&e&lIşınlanmalar | &7Işınlanma başarıyla halka açıldı.' WARP_PRIVATE_UPDATE: '&e&lIşınlanmalar | &7Işınlanma başarıyla halka kapatıldı.' WARP_RENAME: '&e&lIşınlanmalar | &7Yeni bir ad gir (İptal etmek için "-cancel" yaz):' WARP_RENAME_ALREADY_EXIST: '&c&lHata | &7Bu ad zaten başka bir ışınlanma tarafından alınmış.' WARP_RENAME_SUCCESS: '&e&lIşınlanmalar | &7Işınlanma adı başarıyla {0} olarak değiştirildi.' WITHDRAW_ALL_MONEY: |- &e&lBanka | &7Ada bankasında sadece {0} dolar var. &e&lBanka | &7&oTüm para çekiliyor...' WITHDRAW_ANNOUNCEMENT: '&e&lBanka | &7{0} ada bankasından ${1} çekti!' WITHDRAW_ERROR: '&c&lHata | &7{0}.' WITHDRAWN_MONEY: '&e&lBanka | &7{1}''in ada bankasından ${0} çektin!' WITHDRAWN_MONEY_NAME: '&e&lBanka | &7{1} adasının bankasından ${0} çektin!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lDünyalar | &7{0} dünyası henüz kilitli değil!' ================================================ FILE: src/main/resources/lang/vi-VN.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Phát triển bởi Ome_R ## ## ## ###################################################### # If you wish to create a new language file, please copy this one. # Make sure you give the name a correct language name. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # Bạn có thể xem hướng dẫn chỉnh sửa tệp ngôn ngữ này tại đây: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&lĐảo | &7Thêm thành công người chơi {0} vào đảo của {1}.' ADMIN_ADD_PLAYER_NAME: '&e&lĐảo | &7Thêm thành công người chơi {0} vào đảo {1}.' ADMIN_DEPOSIT_MONEY: '&e&lNgân Hàng | &7Bạn đã gửi ${0} vào ngân hàng đảo của {1}.' ADMIN_DEPOSIT_MONEY_NAME: '&e&lNgân Hàng | &7Bạn đã gửi ${0} vào ngân hàng đảo tên {1}.' ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Phát triển bởi Ome_R' ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Danh sách các lệnh cho quản trị viên [{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Dùng /is admin {0} để xem trang kế tiếp.' ALREADY_IN_ISLAND: '&c&lLỗi | &7Bạn đã ở trong đảo rồi.' ALREADY_IN_ISLAND_OTHER: '&c&lLỗi | &7Người chơi này đã là thành viên trong đảo của bạn.' BAN_ANNOUNCEMENT: '&e&lĐảo | &7{0} vừa bị&c&n Cấm&7 trong đảo bởi {1}.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể cấm người chơi có vai trò trong đảo thấp hơn bạn.' BANK_DEPOSIT_CUSTOM: '&e&lNgân Hàng | &7Nhập số lượng tiền bạn muốn gửi:' BANK_DEPOSIT_COMPLETED: 'Gửi tiền thành công' BANK_LIMIT_EXCEED: '&c&lLỗi | &7Bạn đã vượt quá giới hạn của ngân hàng.' BANK_WITHDRAW_CUSTOM: '&e&lNgân Hàng | &7Nhập số lượng tiền bạn muốn rút:' BANK_WITHDRAW_COMPLETED: 'Rút tiền thành công' BANNED_FROM_ISLAND: '&c&lLỗi | &7Bạn đã bị cấm trong hòn đảo này.' BLOCK_COUNT_CHECK: '&e&lĐảo | &7Đảo này có x{0} {1}.' BLOCK_COUNTS_CHECK: | &e&lĐảo | &7Hòn đảo này có các khối sau: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&lĐảo | &7Đảo này không có khối được theo dõi.' BLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}' BLOCK_LEVEL: '&e&lCấp Độ | &7Khối {0} có giá trị cấp độ là {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lCấp Độ | &7Khối {0} vô giá trị.' BLOCK_VALUE: '&e&lĐáng giá | &7Khối {0} được đánh giá với {1}.' BLOCK_VALUE_WORTHLESS: '&e&lĐáng giá | &7Khối {0} vô giá trị.' BONUS_SYNC_ALL: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo đến tất cả các đảo.' BONUS_SYNC_NAME: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo đến {0}.' BONUS_SYNC: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo của {0}.' BORDER_PLAYER_COLOR_NAME_BLUE: 'Xanh dương' BORDER_PLAYER_COLOR_NAME_RED: 'Đỏ' BORDER_PLAYER_COLOR_NAME_GREEN: 'Xanh lá' BORDER_PLAYER_COLOR_UPDATED: '&e&lBiên Giới | &7Thành công thay đổi màu giới hạn đảo của bạn thành {0}.' BUILD_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không thể xây dựng ngoài phạm vi bảo vệ của đảo bạn.' CANNOT_SET_ROLE: '&c&lLỗi | &7Bạn không thể đặt vai trò của người chơi thành {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể thay đổi quyền thành vai trò trong đảo thấp hơn vai trò của bạn.' CHANGED_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}.' CHANGED_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.' CHANGED_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}.' CHANGED_BIOME: '&e&lĐảo | &7Thay đổi thành công quần xã thành {0}. Bạn có thể cần kết nối lại với máy chủ để xem các thay đổi.' CHANGED_BIOME_ALL: '&e&lĐảo | &7Thành công thay đổi quần xã thành {0} cho tất cả các đảo.' CHANGED_BIOME_NAME: '&e&lĐảo | &7Thành công thay đổi quần xã thành {0} cho đảo {1}.' CHANGED_BIOME_OTHER: '&e&lĐảo | &7Thành công thay đổi quần xã thành {0} cho đảo của {1}.' CHANGED_BLOCK_AMOUNT: '&e&lKhối | &7Thành công thay đổi số lượng khối từ {0} thành {1}.' CHANGED_BLOCK_LIMIT: '&e&lNâng Cấp | &7Thay đổi thành công giới hạn khối {0} đảo của {1}.' CHANGED_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.' CHANGED_BLOCK_LIMIT_NAME: '&e&lNâng Cấp | &7Thay đổi thành công giới hạn khối {0} đảo của {1}.' CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_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}.' CHANGED_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.' CHANGED_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}.' CHANGED_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}.' CHANGED_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.' CHANGED_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}.' CHANGED_CROP_GROWTH: '&e&lNâng Cấp | &7Thay thành công hệ số tăng trưởng cây trồng của đảo {0}.' CHANGED_CROP_GROWTH_ALL: '&e&lNâng Cấp | &7Thay thành công hệ số tăng trưởng cây trồng của tất cả các đảo.' CHANGED_CROP_GROWTH_NAME: '&e&lNâng Cấp | &7Thay thành công hệ số tăng trưởng cây trồng của đảo {0}.' CHANGED_DISCORD: '&e&lĐảo | &7Thay đổi thành công discord của đảo thành {0}.' CHANGED_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}.' CHANGED_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.' CHANGED_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}.' CHANGED_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}.' CHANGED_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.' CHANGED_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}.' CHANGED_ISLAND_SIZE: '&e&lNâng Cấp | &7Nâng cấp thành công kích thước đảo của {0}.' CHANGED_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.' CHANGED_ISLAND_SIZE_NAME: '&e&lNâng Cấp | &7Thay đổi thành công kích thước đảo {0}.' CHANGED_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.' CHANGED_LANGUAGE: '&e&lNgôn Ngữ | &7Thành công thay đổi ngôn ngữ của bạn thành Tiếng Việt.' CHANGED_MOB_DROPS: '&e&lNâng Cấp | &7Thay đổi thành công tỉ lệ rơi đồ quái vật của đảo {0}.' CHANGED_MOB_DROPS_ALL: '&e&lNâng Cấp | &7Thay đổi thành công tỉ lệ rơi đồ quái vật của tất cả các đảo.' CHANGED_MOB_DROPS_NAME: '&e&lNâng Cấp | &7Thay đổi thành công tỉ lệ rơi đồ quái vật của đảo {0}.' CHANGED_NAME: '&e&lĐảo | &7Bạn đã thay đổi tên đảo bạn thành {0}&7.' CHANGED_NAME_OTHER: '&e&lĐảo | &7Bạn đã thay đổi tên đảo của {0} thành {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&lĐảo | &7Bạn đã thay đổi tên của {0}&7 thành {1}&7.' CHANGED_PAYPAL: '&e&lNâng Cấp | &7Thay đổi thành công paypal của đảo thành {0}.' CHANGED_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}.' CHANGED_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.' CHANGED_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}.' CHANGED_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 {0}.' CHANGED_SPAWNER_RATES_ALL: '&e&lNâng Cấp | &7Cập nhật thành công tỷ lệ nhân giống sinh sản của tất cả các đảo.' CHANGED_SPAWNER_RATES_NAME: '&e&lNâng Cấp | &7Cập nhật thành công tỷ lệ nhân giống sinh sản của đảo {0}.' CHANGED_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}.' CHANGED_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 cả các đảo.' CHANGED_TEAM_LIMIT_NAME: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn đội của đảo {0}.' CHANGED_TELEPORT_LOCATION: '&e&lĐảo | &7Cập nhật thành công vị trí dịch chuyển.' CHANGED_WARPS_LIMIT: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn khu vực đải của {0}' CHANGED_WARPS_LIMIT_ALL: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn khu vực của tất cả các đảo.' CHANGED_WARPS_LIMIT_NAME: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn khu vực của đảo {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: so-luong COMMAND_ARGUMENT_BIOME: quan-xa COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: lenh... COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: discord... COMMAND_ARGUMENT_EFFECT: hieu-ung-thuoc COMMAND_ARGUMENT_EMAIL: email COMMAND_ARGUMENT_ENTITY: vat-the COMMAND_ARGUMENT_ISLAND_NAME: ten-dao COMMAND_ARGUMENT_ISLAND_ROLE: vai-tro-dao COMMAND_ARGUMENT_LEADER: lanh-dao COMMAND_ARGUMENT_LEVEL: cap-do COMMAND_ARGUMENT_LIMIT: gioi-han COMMAND_ARGUMENT_MATERIAL: vat-lieu COMMAND_ARGUMENT_MENU: ten-giao-dien COMMAND_ARGUMENT_MESSAGE: tin-nhan... COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: ten-nhiem-vu COMMAND_ARGUMENT_MODULE_NAME: ten-module COMMAND_ARGUMENT_MULTIPLIER: he-so COMMAND_ARGUMENT_NAME: ten COMMAND_ARGUMENT_NEW_LEADER: lanh-dao-moi COMMAND_ARGUMENT_PAGE: trang COMMAND_ARGUMENT_PATH: 'path' COMMAND_ARGUMENT_PERMISSION: quyen COMMAND_ARGUMENT_PLAYER_NAME: ten-nguoi-choi COMMAND_ARGUMENT_PRIVATE: rieng-tu COMMAND_ARGUMENT_RATING: danh-gia COMMAND_ARGUMENT_ROWS: so-dong COMMAND_ARGUMENT_SCHEMATIC_NAME: ten-schematic COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: cai-dat COMMAND_ARGUMENT_SIZE: kich-thuoc COMMAND_ARGUMENT_TIME: thoi-gian COMMAND_ARGUMENT_TITLE_DURATION: thoi-luong COMMAND_ARGUMENT_TITLE_FADE_IN: 'mo-vao(fade-in)' COMMAND_ARGUMENT_TITLE_FADE_OUT: 'mo-ra(fade-out)' COMMAND_ARGUMENT_UPGRADE_NAME: ten-nang-cap COMMAND_ARGUMENT_VALUE: gia-tri COMMAND_ARGUMENT_WARP_NAME: ten-khu-vuc COMMAND_ARGUMENT_WARP_CATEGORY: danh-sach-khu-vuc COMMAND_ARGUMENT_WORLD: the-gioi COMMAND_COOLDOWN_FORMAT: '&c&lLỗi | &7Bạn chỉ có thể sử dụng lệnh trong {0}.' COMMAND_DESCRIPTION_ACCEPT: Chấp nhận lời mời từ người chơi. COMMAND_DESCRIPTION_ADMIN: Sử dụng các lệnh của admin. COMMAND_DESCRIPTION_ADMIN_BONUS: Cấp tiền thưởng cho người chơi. COMMAND_DESCRIPTION_ADMIN_ADD: Thêm người vào đảo. COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Tăng giới hạn khối cho đảo của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Thêm thưởng cho người chơi.' COMMAND_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.' COMMAND_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.' COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Thêm hiệu ứng đảo của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Tăng giới hạn vật thể của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Thêm phần trăm vật liệu cho máy tạo đá cuội.' COMMAND_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.' COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Mở rộng đảo của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Tăng hệ số tỷ lệ lồng sinh sản của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Tăng giới hạn thành viên đảo của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Tăng giới hạn khu vực của một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_BYPASS: Chuyển đổi chế độ bypass. COMMAND_DESCRIPTION_ADMIN_CHEST: 'Mở rương của hòn đảo của hòn đảo khác.' COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Xóa một tỷ lệ máy tạo quặng cho một hòn đảo cụ thể. COMMAND_DESCRIPTION_ADMIN_CLOSE: Đóng một hòn đảo thành công cộng. COMMAND_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.' COMMAND_DESCRIPTION_ADMIN_COUNT: Kiểm tra số khối trên một hòn đảo cụ thể. COMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or islands.' COMMAND_DESCRIPTION_ADMIN_DEBUG: Chuyển đổi đầu ra gỡ lỗi. COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Xóa một khu vực cho một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: Hạ cấp thành viên ở đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Gửi tiền vào ngân hàng đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_DISBAND: Giải tán vĩnh viễn hòn đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Giải tán cho người chơi. COMMAND_DESCRIPTION_ADMIN_IGNORE: Bỏ qua một hòn đảo từ những hòn đảo hàng đầu. COMMAND_DESCRIPTION_ADMIN_JOIN: Tham gia một hòn đảo mà không cần lời mời. COMMAND_DESCRIPTION_ADMIN_KICK: Đá một người chơi khỏi đảo. COMMAND_DESCRIPTION_ADMIN_MODULES: 'Quản lý các module của plugin.' COMMAND_DESCRIPTION_ADMIN_MISSION: Thay đổi trạng thái của một nhiệm vụ cho người chơi. COMMAND_DESCRIPTION_ADMIN_MSG: Gửi cho người chơi một tin nhắn mà không có bất kỳ tiền tố. COMMAND_DESCRIPTION_ADMIN_MSG_ALL: Gửi cho tất cả các thành viên đảo một tin nhắn mà không cần bất kỳ prefixes. COMMAND_DESCRIPTION_ADMIN_NAME: Thay đổi tên của một hòn đảo. COMMAND_DESCRIPTION_ADMIN_OPEN: Mở một hòn đảo cho công cộng. COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Mở một giao diện tùy chọn cho người chơi.' COMMAND_DESCRIPTION_ADMIN_PROMOTE: Thăng chức thành viên ở đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_PURGE: Lọc bỏ số lượng lớn đảo. COMMAND_DESCRIPTION_ADMIN_RANKUP: Cập nhật mức độ nâng cấp cho hòn đảo. COMMAND_DESCRIPTION_ADMIN_RECALC: Tính lại giá trị của một hòn đảo. COMMAND_DESCRIPTION_ADMIN_RELOAD: Tải lại tất cả các config và tác vụ của plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Xóa giới hạn khối khỏi một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Xóa tất cả các xếp hạng được cung cấp bởi một người chơi. COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Tái tạo lại thế giới cho một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Tạo các schematic cho plugin. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Đặt quần xã cho đảo. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Đặt số lượng khối ở một vị trí cụ thể.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Đặt giới hạn khối cho đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Đặt số dòng rương của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Đặt giới hạn người chơi co-op của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Đặt hệ số tăng trưởng cây trồng cho đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Đặt số lượng người cho đảo của người chơi. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Đặt hiệu ứng đảo của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Đặt giới hạn vật thể của người chơi khác. COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Chuyển một hòn đảo cho người khác. COMMAND_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 khác. COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Đặt vai trò bắt buộc để cấp quyền cho tất cả các đảo. COMMAND_DESCRIPTION_ADMIN_SET_RATE: Đặt đánh giá của người chơi khác. COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Đặt giới hạn vai trò của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Chuyển đổi cài đặt cho một hòn đảo cụ thể. COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Thay đổi tỷ lệ phần trăm của vật liệu cho máy tạo quặng. COMMAND_DESCRIPTION_ADMIN_SET_SIZE: Thay đổi kích thước đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Đặt vị trí trung tâm của máy chủ. COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Đặt tỉ lệ nhân đôi lồng sinh sản cho hòn đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Đặt giới hạn thành viên cho đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Đặt mức nâng cấp cho đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Đặt giới hạn khu vực của một hòn đảo. COMMAND_DESCRIPTION_ADMIN_SETTINGS: Mở cài đặt điều chỉnh plugin. COMMAND_DESCRIPTION_ADMIN_SHOW: Lấy thông tin của một hòn đảo. COMMAND_DESCRIPTION_ADMIN_SPAWN: Dịch chuyển đến vị trí trung tâm. COMMAND_DESCRIPTION_ADMIN_SPY: Chuyển đổi chế độ gián điệp trò chuyện COMMAND_DESCRIPTION_ADMIN_STATS: Coi thông kê về plugin. COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Đồng bộ hóa các giá trị nâng cấp cho một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_TELEPORT: Dịch chuyển đến hòn đảo khác COMMAND_DESCRIPTION_ADMIN_TITLE: 'Gửi cho người chơi một title.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Gửi cho tất cả thành viên đảo một title.' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: Ngừng bỏ qua một hòn đảo từ những hòn đảo hàng đầu. COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Mở khóa một thế giới cho một hòn đảo. COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Rút tiền từ ngân hàng đảo của người chơi khác. COMMAND_DESCRIPTION_BALANCE: 'Kiểm tra số tiền bên trong ngân hàng của một hòn đảo.' COMMAND_DESCRIPTION_BAN: Cấm một người chơi từ đảo của bạn. COMMAND_DESCRIPTION_BANK: 'Mở ngân hàng đảo.' COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Thẩy đổi quần xã của hòn đảo. COMMAND_DESCRIPTION_BORDER: Thay đổi màu giới hạn đảo. COMMAND_DESCRIPTION_CHEST: 'Mở rương đảo.' COMMAND_DESCRIPTION_CLOSE: Đóng đảo thành công cộng. COMMAND_DESCRIPTION_COOP: Thêm thành viên co-op cho đảo bạn. COMMAND_DESCRIPTION_COOPS: Mở menu co-op. COMMAND_DESCRIPTION_COUNTS: Xem số khối trong đảo của bạn. COMMAND_DESCRIPTION_CREATE: Tạo một hòn đảo mới. COMMAND_DESCRIPTION_DEL_WARP: Xóa một khu vực của đảo. COMMAND_DESCRIPTION_DEMOTE: Hạ cấp một thành viên trong hòn đảo của bạn. COMMAND_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 đảo. COMMAND_DESCRIPTION_DISBAND: Giải tán hòn đảo của bạn vĩnh viễn. COMMAND_DESCRIPTION_EXPEL: Kick một vị khách từ đảo của bạn. COMMAND_DESCRIPTION_FLY: Chuyển chế độ bay cho đảo. COMMAND_DESCRIPTION_HELP: Danh sách tất cả các lệnh. COMMAND_DESCRIPTION_INVITE: Mời một người chơi đến đảo của bạn. COMMAND_DESCRIPTION_KICK: Kick một người chơi từ đảo của bạn. COMMAND_DESCRIPTION_LANG: Thay đổi ngôn ngữ cá nhân của bạn. COMMAND_DESCRIPTION_LEAVE: Rời khỏi hòn đảo của bạn. COMMAND_DESCRIPTION_MEMBERS: Mở menu thành viên. COMMAND_DESCRIPTION_MISSION: Hoàn thành nhiệm vụ. COMMAND_DESCRIPTION_MISSIONS: Mở menu nhiệm vụ. COMMAND_DESCRIPTION_NAME: Thay đảo tên đảo của bạn. COMMAND_DESCRIPTION_OPEN: Mở đảo cho công cộng. COMMAND_DESCRIPTION_PANEL: Mở bảng điều khiển của đảo. COMMAND_DESCRIPTION_PARDON: Bỏ cấm một người chơi từ đảo của bạn. COMMAND_DESCRIPTION_PERMISSIONS: Xem tất cả các quyền cho vai trò đảo. COMMAND_DESCRIPTION_PROMOTE: Thăng chức một thành viên trong hòn đảo của bạn. COMMAND_DESCRIPTION_RANKUP: Tăng cấp một bản nâng cấp. COMMAND_DESCRIPTION_RATE: Đánh giá một hòn đảo. COMMAND_DESCRIPTION_RATINGS: Hiện thị tất cả đánh giá đảo. COMMAND_DESCRIPTION_SETTINGS: Mở menu cài đặt đảo. COMMAND_DESCRIPTION_RECALC: Tính lại giá trị đảo. COMMAND_DESCRIPTION_SET_DISCORD: Đặt discord của đảo đối với các khoản thanh toán trên đảo. COMMAND_DESCRIPTION_SET_PAYPAL: Đặt email paypal của đảo cho các khoản thanh toán trên đảo. COMMAND_DESCRIPTION_SET_ROLE: Thay đổi vai trò của một người chơi trong hòn đảo của bạn. COMMAND_DESCRIPTION_SET_TELEPORT: Thay đổi vị trí dịch chuyển trên đảo của bạn. COMMAND_DESCRIPTION_SET_WARP: Tạo một khu vực đảo mới. COMMAND_DESCRIPTION_SHOW: Xem thông tin về một hòn đảo. COMMAND_DESCRIPTION_TEAM: Xem thông tin về tình trạng thành viên đảo. COMMAND_DESCRIPTION_TEAM_CHAT: Chuyển đổi chế độ trò chuyện nhóm. COMMAND_DESCRIPTION_TELEPORT: Dịch chuyển đến đảo của bạn. COMMAND_DESCRIPTION_TOGGLE: Chuyển đổi biên giới đảo và vị trí khối xếp chồng lên nhau. COMMAND_DESCRIPTION_TOP: Mở bảng đảo hàng đầu. COMMAND_DESCRIPTION_TRANSFER: Chuyển lãnh đạo đảo của bạn. COMMAND_DESCRIPTION_UNCOOP: Loại bỏ người chơi thành viên co-op trong đảo bạn. COMMAND_DESCRIPTION_UPGRADE: Mở bảng nâng cấp. COMMAND_DESCRIPTION_VALUE: Xem giá trị giá trị của một khối. COMMAND_DESCRIPTION_VALUES: Mở menu giá trị. COMMAND_DESCRIPTION_VISIT: Dịch chuyển đến vị trí của du khách trên đảo. COMMAND_DESCRIPTION_VISITORS: Mở menu khách. COMMAND_DESCRIPTION_WARP: Dịch chuyển đến một khu vực đảo. COMMAND_DESCRIPTION_WARPS: Mở menu khu vực. COMMAND_DESCRIPTION_WITHDRAW: Rút tiền từ ngân hàng đảo vào tài khoản cá nhân của bạn. COMMAND_USAGE: '&cCách dùng: /{0}' COOP_ANNOUNCEMENT: '&e&lĐảo | &7{0} thêm {1} với tư cách thành viên co-op.' COOP_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 thành viên co-op.' COOP_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ó.' CREATE_ISLAND: '&e&lĐảo | &7Tạo một hòn đảo mới tại {0} trong {1}ms.' CREATE_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 đề.' CREATE_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 đề.' DEBUG_MODE_DISABLED: '&e&lGỡ Lỗi | &7Chế độ gỡ lỗi đã được &cTẮT&7.' DEBUG_MODE_ENABLED: '&e&lGỡ Lỗi | &7Chế độ gỡ lỗi đã được &aBẬT&7.' DEBUG_MODE_FILTER_ADD: '&e&lGỡ lỗi | &7Đã bật bộ lọc gỡ lỗi {0} &aBẬT&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lGỡ lỗi | &7Đã xóa tất cả bộ lọc gỡ lỗi &cTẮT&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lGỡ lỗi | &7Đã tắt bộ lọc gỡ lỗi {0} &cTẮT&7.' DELETE_WARP: '&e&lĐảo | &7Bạn đã xóa khu vực {0}.' DELETE_WARP_SIGN_BROKE: '&7&oChỗ đó từng có một bảng khu vực, nhưng nó đã bị hỏng...' DEMOTE_LEADER: '&c&lLỗi | &7Bạn không thể hạ cấp lãnh đạo đảo.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể hạ cấp người chơi có vai trò đảo thấp hơn của bạn.' DEMOTED_MEMBER: '&e&lĐảo | &7Bạn đã hạ cấp {0} thành {1} trong đảo của họ.' DEPOSIT_ANNOUNCEMENT: '&e&lNgân Hàng | &7{0} đã gửi {1}$ vào ngân hàng đảo!' DEPOSIT_ERROR: '&c&lLỗi | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không thể phá hủy bên ngoài phạm vi bảo vệ của đảo bạn.' DISBAND_ANNOUNCEMENT: '&e&lĐảo | &7Đảo của bạn đã bị giải tán bởi {0}.' DISBAND_GIVE: '&e&lĐảo | &7Bạn đã nhận được {0} lượt giải tán.' DISBAND_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.' DISBAND_GIVE_OTHER: '&e&lĐảo | &7Bạn đã cho {0} giải tán đến {1}.' DISBAND_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.' DISBAND_SET: '&e&lĐảo | &7Số lượng giải tán của bạn đã được đặt thành {0}.' DISBAND_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}.' DISBAND_SET_OTHER: '&e&lĐảo | &7Bạn đã đặt số lần giải tán của {0} thành {1}.' DISBANDED_ISLAND: '&e&lĐảo | &7Bạn đã giải tán hòn đảo của bạn.' DISBANDED_ISLAND_OTHER: '&e&lĐảo | &7Bạn đã giải tán đảo của {0}.' DISBANDED_ISLAND_OTHER_NAME: '&e&lĐảo | &7Bạn đã giải tán đảo {0}.' ENTER_PVP_ISLAND: '&7&oBạn đã được dịch chuyển đến một hòn đảo có bật PVP. Bạn được miễn sát thương với PVP trong 10 giây tiếp theo...' EXPELLED_PLAYER: '&e&lĐảo | &7{0} đã bị trục xuất khỏi đảo.' FORMAT_QUAD: 'Q' FORMAT_TRILLION: 'T' FORMAT_BILLION: 'B' FORMAT_MILLION: 'M' FORMAT_THOUSANDS: 'K' FORMAT_SECONDS_NAME: giây FORMAT_SECOND_NAME: giây FORMAT_MINUTES_NAME: phút FORMAT_MINUTE_NAME: phút FORMAT_HOURS_NAME: giờ FORMAT_HOUR_NAME: giờ FORMAT_DAYS_NAME: ngày FORMAT_DAY_NAME: ngày GENERATOR_CLEARED: '&e&lĐảo | &7Xóa thành công số lượng máy tạo quặng cho đảo của {0}.' GENERATOR_CLEARED_NAME: '&e&lĐảo | &7Xóa thành công số lượng máy tạo quặng cho đảo {0}.' GENERATOR_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.' GENERATOR_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}.' GENERATOR_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}.' GENERATOR_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.' GLOBAL_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}!' GLOBAL_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}!' GLOBAL_MESSAGE_SENT: '&e&lĐảo | &7Gửi thành công tin nhắn đến thành viên đảo của {0}!' GLOBAL_MESSAGE_SENT_NAME: '&e&lĐảo | &7Gửi thành công tin nhắn đến thành viên của đảo {0}!' GLOBAL_TITLE_SENT: '&e&lĐảo | &7Gửi title cho thành viên đảo của {0} thành công!' GLOBAL_TITLE_SENT_NAME: '&e&lĐảo | &7Gửi title cho thành viên đảo {0} thành công!' GOT_BANNED: '&e&lĐảo | &7Bạn đã bị &cCẤM&7 khỏi đảo của {0}.' GOT_DEMOTED: '&e&lĐảo | &7Bạn đã bị hạ cấp xuống thành {0} trong đảo của bạn.' GOT_EXPELLED: '&e&lĐảo | &7&oBạn đã bị trục xuất khỏi đảo bởi {0}...' GOT_INVITE: '&e&lĐảo | &7{0} mời bạn đến đảo của họ.' GOT_INVITE_TOOLTIP: '&7Nhấp vào tin nhắn để chấp nhận lời mời.' GOT_KICKED: '&e&lĐảo | &7Bạn đã bị kick khỏi đảo của bạn bởi {0}.' GOT_PROMOTED: '&e&lĐảo | &7Bạn đã được thăng chức {0} trong đảo của bạn.' GOT_REVOKED: '&e&lĐảo | &7{0} đã thu hồi lời mời bạn đến đảo của họ.' GOT_UNBANNED: '&e&lĐảo | &7Bạn đã được dỡ bỏ lệnh cấm khỏi đảo của {0}.' HIT_ISLAND_MEMBER: '&c&lLỗi| &7Bạn không thể đánh thành viên đảo của bạn.' HIT_PLAYER_IN_ISLAND: '&c&lLỗi | &7Bạn không thể đánh người chơi trong đảo.' IGNORED_ISLAND: '&e&lĐảo | &7Đảo của {0} bây giờ không còn hiển thị trong danh sách đảo hàng đầu.' IGNORED_ISLAND_NAME: '&e&lĐảo | &7Đảo {0} bây giờ không còn hiển thị trong danh sách đảo hàng đầu.' INTERACT_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không thể tương tác ngoài phạm vi bảo vệ của đảo bạn.' INVALID_AMOUNT: '&c&lLỗi | &7Số lượng không hợp lệ {0}.' INVALID_BIOME: '&c&lLỗi | &7Quần xã không chính xác {0}.' INVALID_BLOCK: '&c&lLỗi | &7Vị trí khối không hợp lệ {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lLỗi | &7Hiệu ứng không hợp lệ {0}.' INVALID_ENTITY: '&c&lLỗi | &7Vật thể không chính xác {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lLỗi | &7Thời gian nghỉ không hợp lệ {0}.' INVALID_ISLAND: '&c&lLỗi | &7Bạn không có một hòn đảo.' INVALID_ISLAND_LOCATION: '&c&lLỗi | &7Không có đảo nào ở vị trí của bạn.' INVALID_ISLAND_OTHER: '&c&lLỗi | &7{0} không có đảo.' INVALID_ISLAND_OTHER_NAME: '&c&lLỗi | &7Không có đảo nào với tên {0}.' INVALID_ISLAND_PERMISSION: | &c&lLỗi | &7Không thể tìm thấy quyền của đảo {0}. &c&lLỗi | &7Quyền của đảo: {1} INVALID_LEVEL: '&c&lLỗi | &7Cấp độ không hợp lệ {0}.' INVALID_LIMIT: '&c&lLỗi | &7Giới hạn không hợp lệ {0}.' INVALID_MATERIAL: '&c&lLỗi | &7Vật liệu không hợp lệ {0}.' INVALID_MATERIAL_DATA: '&c&lLỗi | &7Dữ liệu-vật liệu không hợp lệ {0}.' INVALID_MENU: '&c&lLỗi | &7Menu không hợp lệ {0}.' INVALID_MISSION: '&c&lLỗi | &7Nhiệm vụ không hợp lệ {0}.' INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lLỗi | &7Module không hợp lệ {0}.' INVALID_MULTIPLIER: '&c&lLỗi | &7Hệ số không hợp lệ {0}.' INVALID_PAGE: '&c&lLỗi | &7Trang không hợp lệ {0}.' INVALID_PERCENTAGE: '&c&lLỗi | &7Tỷ lệ phần trăm phải nằm trong khoảng từ 0 đến 100.' INVALID_PLAYER: '&c&lLỗi | &7Không thể tìm thấy người chơi tên {0}' INVALID_RATE: | &c&lLỗi | &7Không thể tìm thấy một đánh giá với tên {0}. &c&lLỗi | &7Các đánh giá đảo: {1} INVALID_ROWS: '&c&lLỗi | &7Số lượng dòng không hợp lệ: {0}' INVALID_ROLE: | &c&lLỗi | &7Không thể tìm thấy vai trò đảo {0}. &c&lLỗi | &7Các vai trò của đảo: {1} INVALID_SCHEMATIC: '&c&lLỗi | &7không thể tìm thấy schematic với tên {0}.' INVALID_SETTINGS: | &c&lLỗi | &7Không thể tìm thấy cài đặt đảo {0}. &c&lLỗi | &7Các điều chỉnh đảo: {1} INVALID_SIZE: '&c&lLỗi | &7Kích thước không hợp lệ {0}.' INVALID_SLOT: '&c&lLỗi | &7Vị trí không hợp lệ {0}.' INVALID_TITLE: '&c&lLỗi | &7Đã nhập title không hợp lệ.' INVALID_TOGGLE_MODE: '&c&lLỗi | &7Không thể chuyển đổi {0}.' INVALID_UPGRADE: | &c&lLỗi | &7Không thể tìm thấy bản nâng cấp được gọi là {0}. &c&lLỗi | &7Nâng cấp: {1} INVALID_VISIT_LOCATION: '&c&lLỗi | &7Hòn đảo này không có vị trí du khách.' INVALID_VISIT_LOCATION_BYPASS: '&7&oBạn có chế độ bypass, dịch chuyển bạn đến đảo...' INVALID_WARP: '&c&lLỗi | &7Khu vực không hợp lệ {0}.' INVALID_WORLD: '&c&lLỗi | &7Thế giới không hợp lệ {0}.' INVITE_ANNOUNCEMENT: '&e&lĐảo | &7{0} mời {1} vào đảo.' INVITE_BANNED_PLAYER: '&c&lLỗi | &7Người chơi này bị cấm từ đảo và không thể được mời.' INVITE_TO_FULL_ISLAND: '&c&lLỗi | &7Bạn không thể mời thêm thành viên đến đảo của bạn.' ISLAND_ALREADY_CLOSED: '&c&lLỗi | &7Đảo đã được đóng cửa biên giới.' ISLAND_ALREADY_EXIST: '&c&lLỗi | &7Một hòn đảo với tên đó đã tồn tại.' ISLAND_ALREADY_OPENED: '&c&lLỗi | &7Đảo đã được mở cửa biên giới.' ISLAND_BANK_EMPTY: '&e&lNgân Hàng | &7Đảo ngân hàng trống rỗng.' ISLAND_BANK_SHOW: '&e&lNgân Hàng | &7Đảo bạn có ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lNgân Hàng | &7Đảo của {0} có ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&lNgân Hàng | &7Hòn đảo {0} có ${1}.' ISLAND_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!' ISLAND_CLOSED: '&e&lĐảo | &7Thành công đóng cửa đảo cho công cộng.' ISLAND_CREATE_PROCESS_FAIL: '&c&lLỗi | &7Bạn đã có một nhiệm vụ tạo đảo đang diễn ra.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lĐảo | &7Đang xử lý yêu cầu của bạn...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lBay | &7Bay trong đảo đã tự động &cvô hiệu hóad&7.' ISLAND_FLY_ENABLED: '&e&lBay | &7Bay trong đảo đã tự động &akích hoạt&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lĐảo | &7&oBạn đã ở trong một hòn đảo đã bị giải tán, vì vậy bạn sẽ được dịch chuyển trở lại spawn...' ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lĐảo | &7&oBạn đã ở trong một hòn đảo đã bật pvp, vì vậy bạn đã được dịch chuyển trở lại trung tâm...' ISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Được phát triển bởi Ome_R' ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Danh sách lệnh [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Dùng /is help {0} cho trang tiếp theo.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lĐảo | &7Giới Hạn Ngân Hàng: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&lĐảo | &7Giới Hạn Các Khối: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lĐảo | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lĐảo | &7Giới Hạn Co-op: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&lĐảo | &7Các hiệu ứng đảo: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lĐảo | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&lĐảo | &7Giới hạn các vật thể: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lĐảo | &7 {0}: {1}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lĐảo | &7Cây trồng đa cấp: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lĐảo | &7Drops đa cấp: {0}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&lĐảo | &7Tỉ lệ máy tạo quặng ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lĐảo | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&lĐảo | &7Giới Hạn Vai Trò: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lĐảo | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&lĐảo | &7Kích thước đảo: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lĐảo | &7Hệ số lồng sinh sản: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lĐảo | &7Giới hạn thành viên: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&lĐảo | &7Các Nâng Cấp: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lĐảo | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lĐảo | &7Giới hạn khu vực: {0}' ISLAND_INFO_BANK: '&e&lĐảo | &7Ngân hàng: {0}' ISLAND_INFO_BONUS: '&e&lĐảo | &7Giá trị đi kèm: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&lĐảo | &7Cấp độ đi kèm: {0}' ISLAND_INFO_CREATION_TIME: '&e&lĐảo | &7Thời gian tạo đảo: {0}' ISLAND_INFO_DISCORD: '&e&lĐảo | &7Discord: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&lĐảo | Cập nhật lần cuối: {0} trước' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lĐảo | &7Cập nhật lần cuối: &aHiện đang hoạt động' ISLAND_INFO_LEVEL: '&e&lĐảo | &7Cấp độ: {0}' ISLAND_INFO_LOCATION: '&e&lĐảo | &7Nhà: {0}' ISLAND_INFO_NAME: '&e&lĐảo | &7Tên: {0}' ISLAND_INFO_OWNER: '&e&lĐảo | &7Lãnh đạo: {0}' ISLAND_INFO_PAYPAL: '&e&lĐảo | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&lĐảo | &7 - {0}' ISLAND_INFO_RATE: '&e&lĐảo | &7Đánh giá: {0} &7({1}/5) - tất cả {2} đánh giá.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: ✦ ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lĐảo | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&lĐảo | &7Số lượt khách: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lĐảo | &7Đáng giá: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lĐảo | &7Mở đảo thành công cho công cộng.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lXem Trước | &7Bạn đã đi ra quá xa và thoát chế độ xem trước.' ISLAND_PREVIEW_CANCEL: '&e&lXem Trước | &7Bạn đã hủy chế độ xem trước.' ISLAND_PREVIEW_CONFIRM_TEXT: 'DONG-Y' ISLAND_PREVIEW_CANCEL_TEXT: 'HUY-BO' ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lXem Trước | &7Bạn đã bắt đầu chế độ xem trước schematic {0}. &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. &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. ISLAND_PROTECTED: '&c&lLỗi | &7Hòn đảo này được bảo vệ.' ISLAND_PROTECTED_OPPED: '&7&oBạn có thể bỏ qua hạn chế này bằng cách sử dụng "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lĐảo | &7Thành viên đảo của {0} &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Ngoại tuyến)' ISLAND_TEAM_STATUS_ONLINE: '&a(Trực tuyến)' ISLAND_TEAM_STATUS_ROLES: '&e&lĐảo | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(Ngoại Tuyến)' ISLAND_TOP_STATUS_ONLINE: '&a(Trực Tuyến)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Riêng Tư]' ISLAND_WAS_CLOSED: '&e&lĐảo | &7&oHòn đảo bạn đang ở đã bị đóng cửa và bạn sẽ dịch chuyển trở lại spawn...' ISLAND_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.' ISLAND_WORTH_RESULT: '&e&lĐảo | &7Giá trị đảo của bạn là {0} [Cấp độ {1}]' ISLAND_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...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã gia nhập đảo của bạn.' JOIN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã gia nhập đảo của bạn.' JOIN_FULL_ISLAND: '&c&lLỗi | &7Hòn đảo này đạt số lượng thành viên tối đa được phép.' JOIN_WHILE_IN_ISLAND: '&c&lLỗi | &7Bạn đã ở trong một hòn đảo rồi.' JOINED_ISLAND: '&e&lĐảo | &7Bạn đã tham gia đảo của {0}.' JOINED_ISLAND_NAME: '&e&lĐảo | &7Bạn đã vào đảo {0}.' JOINED_ISLAND_AS_COOP: '&e&lĐảo | &7Bây giờ bạn là thành viên co-op đảo của {0}.' JOINED_ISLAND_AS_COOP_NAME: '&e&lĐảo | &7Bây giờ bạn là thành viên co-op đảo {0}.' KICK_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã bị kick khỏi đảo bởi {1}.' KICK_ISLAND_LEADER: '&c&lLỗi | &7Bạn không thể đá người chủ đảo, thay vào đó sử dụng /is admin disband.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể kick người chơi có vai trò đảo thấp hơn bạn.' LACK_CHANGE_PERMISSION: '&c&Lỗi | &7Bạn phải có quyền này để thay đổi nó thành các vai trò khác.' LAST_ROLE_DEMOTE: '&c&lLỗi | &7Bạn không thể hạ cấp người chơi này nữa.' LAST_ROLE_PROMOTE: '&c&lLỗi | &7Bạn không thể thăng chức cho người chơi này nữa.' LEAVE_ANNOUNCEMENT: '&e&lĐảo | &7{0} vừa rời đảo.' LEAVE_ISLAND_AS_LEADER: |- &c&lLỗi | &7Bạn không thể rời đảo khi sở hữu nó. &c&lLỗi | &7Bạn có thể chuyển quyền sở hữu bằng cách sử dụng /is transfer. LEFT_ISLAND: '&e&lĐảo | &7Bạn đã rời đảo của bạn.' LEFT_ISLAND_COOP: '&e&lĐảo | &7Bạn không còn là thành viên co-op đảo của {0} nữa.' LEFT_ISLAND_COOP_NAME: '&e&lĐảo | &7Bạn không còn là thành viên co-op đảo {0} nữa.' LOCK_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!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lThế giới | &7Thế giới {0} hiện đã bị khóa đối với hòn đảo {1}!' LOCK_WORLD_ANNOUNCEMENT: '&e&lThế giới | &7Thế giới {0} hiện đã bị khóa đối với hòa đảo của {1}!' MATERIAL_NOT_SOLID: '&c&lLỗi | &7Bạn phải cung cấp một vật liệu rắn.' MAXIMUM_LEVEL: '&c&lLỗi | &7Mức tối đa cho việc nâng cấp này là {0}.' MESSAGE_SENT: '&e&lĐảo | &7Gửi thành công {0} tin nhắn!' MISSION_CANNOT_COMPLETE: '&c&lLỗi | &7Bạn chưa thể hoàn thành nhiệm vụ này.' MISSION_NO_AUTO_REWARD: '&e&lNhiệm vụ | &7Bạn đã có tất cả các vật liệu cần thiết để hoàn thành {0} - sử dụng /is missions để hoàn thành!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lLỗi | &7Bạn cần hoàn thành {0} trước khi hoàn thahf nhiệm vụ này.' MISSION_STATUS_COMPLETE: '&e&lNhiệm Vụ | &7Thay đổi trạng thái của nhiệm vụ {0} hoàn thành cho {1}.' MISSION_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}.' MISSION_STATUS_RESET: '&e&lNhiệm Vụ | &7Đặt lại trạng thái của nhiệm vụ {0} cho {1}.' MISSION_STATUS_RESET_ALL: '&e&lNhiệm Vụ | &7Đặt lại tất cả các nhiệm vụ cho {0}.' MODULE_ALREADY_INITIALIZED: '&e&lModule | &7Module đã đước tải sẵn trước đó.' MODULE_INFO: | &e&lModule | &7{0} bởi {1} &e&lModule | &7&m-------------------- &e&lModule | &7{2} MODULE_LOADED_SUCCESS: '&e&lModule | &7Thành công tải module {0}.' MODULE_LOADED_FAILURE: '&e&lModule | &7Không thể tải module {0}. Hãy kiểm tra console để có thêm thông tin.' MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Đã hủy tải thành công module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thay đổi tên đảo của anh/cô ấy thành {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lLỗi | &7Bạn không thể sử dụng tên này.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lLỗi | &7Bạn không thể dùng tên người chơi là tên đảo.' NAME_TOO_LONG: '&c&lLỗi | &7Tên đảo không thể dài hơn {0} kí tự.' NAME_TOO_SHORT: '&c&lLỗi | &7Tên đảo không thể ngắn hơn {0} ký tự.' NO_BAN_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để cấm người chơi.' NO_CLOSE_BYPASS: '&c&lLỗi | &7Hòn đảo này không mở cửa cho công cộng.' NO_CLOSE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để đóng đảo với công cộng.' NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lLỗi | &7Bạn phải là {0} hoặc cao hơn để thêm người chơi với tư cách là thành viên co-op.' NO_DELETE_WARP_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để xóa khu vực.' NO_DEMOTE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để hạ cấp người chơi.' NO_DEPOSIT_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để gửi tiền vào ngân hàng đảo.' NO_DISBAND_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để giải tán hòn đảo của bạn.' NO_EXPEL_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để trục xuất người chơi khỏi hòn đảo của bạn.' NO_INVITE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để mời người chơi.' NO_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.' NO_ISLAND_CHEST_PERMISSION: '&c&lLỗi | &7Bạn phải cần ít nhất quyền {0} để truy cập rương đảo.' NO_ISLANDS_TO_PURGE: '&c&lLỗi | &7Không có đảo để lọc.' NO_KICK_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để để kick người chơi.' NO_MORE_DISBANDS: '&c&lLỗi | &7Bạn không thể giải tán đảo nữa.' NO_MORE_WARPS: '&c&lLỗi | &7Đảo của bạn không thể có thêm khu vực.' NO_NAME_PERMISSION: '&c&lLỗi | &7Bạn không thể thay đổi tên đảo.' NO_OPEN_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để mở đảo thành công cộng.' NO_PERMISSION_CHECK_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để có được thông tin về quyền.' NO_PROMOTE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thăng chức người chơi.' NO_RANKUP_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để nâng cấp rank.' NO_RATINGS_PERMISSION: '&c&lLỗi | &7Bạn cần có ít nhất {0} để kiểm tra đánh giá.' NO_SET_BIOME_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thay đổi biome của đảo.' NO_SET_DISCORD_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thay đổi discord của đảo.' NO_SET_HOME_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thiết lập vị trí dịch chuyển của hòn đảo.' NO_SET_PAYPAL_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thay đổi email paypal của đảo.' NO_SET_ROLE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để thiết lập vai trò cho người chơi.' NO_SET_SETTINGS_PERMISSION: '&c&lLỗi | &7Bạn cần có ít nhất {0} để thay đổi điều chỉnh đảo.' NO_SET_WARP_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để đặt khu vực cho đảo.' NO_TRANSFER_PERMISSION: '&cBạn phải là người lãnh đạo của hòn đảo để chuyển giao quyền lãnh đạo.' NO_UNCOOP_PERMISSION: '&c&lLỗi | &7Bạn cần có ít nhất {0} để loại bỏ người chơi từ thành viên co-op.' NO_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.' NO_WITHDRAW_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để rút tiền từ ngân hàng của đảo.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lLỗi | &7Bạn không có đủ tiền để gửi {0}$ vào ngân hàng đảo của bạn.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lLỗi | &7Bạn không có đủ tiền để nâng cấp.' NOT_ENOUGH_MONEY_TO_WARP: '&c&lLỗi | &7Bạn không có đủ tiền để dùng các khu vực đảo.' OPEN_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?' PANEL_TOGGLE_OFF: |- &e&lBảng điều khiển | &7Chuyển đổi chế độ bảng điều khiển đảo: &cTẮT&7. &e&lBảng điều khiển | &7Xài /is sẽ dịch chuyển bạn về đảo.' PANEL_TOGGLE_ON: |- &e&lBảng điều khiển | &7Chuyển đổi chế độ bảng điều khiển đảo: &aBẬT&7. &e&lBảng điều khiển | &7Dùng /is sẽ mở bảng điều khiển cho bạn. PERMISSION_CHANGED: '&e&lNâng Cấp | &7Thay đổi thành công quyền {0} đảo của {1}.' PERMISSION_CHANGED_NAME: '&e&lQuyền Lợi | &7Thay đổi thành công quyền {0} cho đảo {1}.' PERMISSION_CHANGED_ALL: '&e&lNâng Cấp | &7Thay đổi thành công quyền {0} cho tất cả các đảo.' PERSISTENT_DATA_EMPTY: '&c&lLỗi | &7Không tìm thấy dữ liệu nào cho truy vấn của bạn.' PERSISTENT_DATA_MODIFY: '&e&lDữ liệu | &7Đã đặt thành công dữ liệu cho {0} với {1}: {2}' PERSISTENT_DATA_SHOW: '&e&lDữ liệu | &7Dữ liệu của {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lDữ liệu | &7Đã xóa thành công dữ liệu cho {0} từ đường dẫn {1}.' PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_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!' PERMISSIONS_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!' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Yes' PLAYER_ALREADY_BANNED: '&c&lLỗi | &7Người chơi này đã bị cấm.' PLAYER_ALREADY_COOP: '&c&lLỗi | &7Người chơi này đã hợp tác.' PLAYER_ALREADY_IN_ISLAND: '&c&lLỗi | &7Người chơi này đã có sẵn trong đảo.' PLAYER_ALREADY_IN_ROLE: '&c&lLỗi | &7{0} đã là một {1}.' PLAYER_EXPEL_BYPASS: '&c&lLỗi | &7Người chơi này không thể bị trục xuất khỏi đảo.' PLAYER_JOIN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã vào server.' PLAYER_NOT_BANNED: '&c&lLỗi | &7Người chơi này không bị cấm.' PLAYER_NOT_COOP: '&c&lLỗi | &7Người chơi này không phải thành viên co-op.' PLAYER_NOT_INSIDE_ISLAND: '&c&lLỗi | &7Người chơi này không ở trong hòn đảo của bạn.' PLAYER_NOT_ONLINE: '&c&Lỗi | &7Người chơi này không hoạt động!' PLAYER_QUIT_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thoát server.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lLỗi | &7Bạn chỉ có thể thăng chức người chơi có vai trò đảo thấp hơn bạn.' PROMOTED_MEMBER: '&e&lĐảo | &7Bạn đã thăng chức {0} thành {1} ở đảo của họ.' PURGE_CLEAR: '&e&lĐảo | &7Thành công xóa tất cả các đảo xếp hàng đã lọc.' PURGED_ISLANDS: |- &e&lĐảo | &7{0} các đảo sẽ bị lọc khi máy chủ tải lại. &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. RANKUP_SUCCESS: '&e&lĐảo | &7Cập nhật thành công mức độ nâng cấp {0} cho đảo của {1}.' RANKUP_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.' RANKUP_SUCCESS_NAME: '&e&lĐảo | &7Cập nhật thành công mức độ nâng cấp {0} cho {1}.' RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lĐánh giá | &7{0} đã đánh giá đảo của bạn {1} trên 5!.' RATE_CHANGE_OTHER: '&e&lĐánh giá | &7Bạn đã thay đổi đánh giá của đảo {0} thành {1}.' RATE_OWN_ISLAND: '&c&lLỗi | &7Bạn không thể đánh giả đảo của bạn.' RATE_REMOVE_ALL: '&e&lĐánh giá | &7Thành công xóa bỏ tất cả đánh giá của đảo {0}.' RATE_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.' RATE_SUCCESS: '&e&lĐánh giá | &7Bạn đánh giả đảo này với {0} sao!' REACHED_BLOCK_LIMIT: '&e&lNâng Cấp | &7Bạn đã đạt giới hạn {0} khối của đảo.' REACHED_ENTITY_LIMIT: '&e&lUpgrades | &7You have reached the island''s limit for the entity {0}.' RECALC_ALREADY_RUNNING: '&c&lLỗi | &7Đảo của bạn đang được tính toán lại, vui lòng chờ.' RECALC_ALREADY_RUNNING_OTHER: '&c&lLỗi | &7Hòn đảo này đang được tính toán lại, vui lòng chờ.' RECALC_ALL_ISLANDS: '&e&lĐảo | &7Recalculating all islands...' RECALC_ALL_ISLANDS_DONE: '&e&lĐảo | &7Thành công tính toán lại tất cả các đảo.' RECALC_PROCCESS_REQUEST: '&e&lĐảo | &7Đang xử lý yêu cầu của bạn...' RELOAD_COMPLETED: '&e&lĐảo | &7Tải lại xong!' RELOAD_PROCCESS_REQUEST: '&e&lĐảo | &7Bắt đầu tải lại config...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lĐảo | &7{0} thu hồi lời mời của {1} đến hòn đảo.' RESET_WORLD_SUCCEED: '&e&lĐảo | &7Thành công đặt lại thế giới {0} cho đảo của {1}.' RESET_WORLD_SUCCEED_ALL: '&e&lĐảo | &7Thành công đặt lại thế giới {0} cho tất cả các đảo.' RESET_WORLD_SUCCEED_NAME: '&e&lĐảo | &7Thành công đặt lại thế giới {0} cho đảo {1}.' SAME_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 bạn.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Đã chọn vị trí #2 ({0})' SCHEMATIC_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}".' SCHEMATIC_NOT_READY: '&c&lLỗi | &7Bạn chưa chọn hai vị trí.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Đang xử lý yêu cầu của bạn...' SCHEMATIC_READY_TO_CREATE: | &e&lSchematics | &7Bạn đã chọn hai vị trí. Xài /is admin schematic để tạo schematic mới. &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. SCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Đã chọn vị trí #1 ({0})' SCHEMATIC_SAVED: '&e&lSchematics | &7Lưu thành công schematic!' SELF_ROLE_CHANGE: '&c&lLỗi | &7Bạn không thể thay đổi vai trò của chính mình.' SET_UPGRADE_LEVEL: '&e&lNâng Cấp | &7Nâng cấp thành công cấp độ của {0} cho đảo của {1}.' SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lNâng Cấp | &7Thay đổi thành công cấp độ {0} cho đảo {1}.' SET_WARP: '&e&lĐảo | &7Tạo thành công một khu vực mới tại {0}.' SET_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.' SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho đảo của {1}.' SETTINGS_UPDATED_NAME: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho đảo {1}.' SETTINGS_UPDATED_ALL: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho tất cả các đảo.' SIZE_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.' SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lTrung Tâm | &7Dịch chuyển thành công {0} đến trung tâm.' SPAWN_SET_SUCCESS: '&e&lTrung Tâm | &7Cập nhật thành công vị trí trung tâm thành {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Bí Mật] &e[{0}] {1}&f: &7{2}' SYNC_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}.' SYNC_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.' SYNC_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}.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không ở trong đảo của bạn.' TELEPORT_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.' TELEPORT_WARMUP: '&7&oBạn sẽ được dịch chuyển trong {0}... Đừng di chuyển!' TELEPORT_WARMUP_CANCEL: '&7&oBạn đã di chuyển và do đó dịch chuyển tức thời đã bị hủy.' TITLE_SENT: '&e&lĐảo | &7Thành công gửi người chơi {0} title!' TELEPORTED_FAILED: '&e&lĐảo | &7Có vẻ như hòn đảo này không có vị trí nào an toàn. Xin vui lòng liên lạc với ban quản trị.' TELEPORTED_SUCCESS: '&e&lĐảo | &7Bạn đã được dịch chuyển đến hòn đảo của bạn.' TELEPORTED_TO_WARP: '&e&lĐảo | &7Dịch chuyển thành công đến khu vực của hòn đảo này.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lĐảo | &7Người chơi {0} đã dịch chuyển đến khu vực đảo {1}.' TOGGLED_BYPASS_OFF: '&e&lBypass | &7Chuyển đổi chế độ bypass: &cTẮT&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Chuyển đổi chế độ bypass: &aBẬT&7.' TOGGLED_FLY_OFF: '&e&lBay | &7Chuyển đổi chế độ bay trong đảo: &cTẮT&7.' TOGGLED_FLY_ON: '&e&lBay | &7Chuyển đổi chế độ bay trong đảo: &aBẬT&7.' TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Chuyển đổi chế độ schematic: &cTẮT&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchematics | &7Chuyển đổi chế độ schematic: &aBẬT&7. &e&lSchematics | &7Chọn một khu vực bằng rìu vàng (golden axe). TOGGLED_SPY_OFF: '&e&lBí Mật | &7Chế độ nói chuyện bí mật: &cTẮT&7.' TOGGLED_SPY_ON: '&e&lBí Mật | &7Chế độ nói chuyện bí mật: &aBẬT&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Chuyển đổi chế độ stack khối: &cTẮT&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Chuyển đổi chế độ stack khối: &aBẬT&7.' TOGGLED_TEAM_CHAT_OFF: '&e&lTrò chuyện | &7Chuyển đổi chế độ trò chuyện đôi &cTẮT&7.' TOGGLED_TEAM_CHAT_ON: '&e&lTrò chuyện | &7Chuyển đổi chế độ trò chuyện đội: &aBẬT&7.' TOGGLED_WORLD_BORDER_OFF: '&e&lBiên giới | &7Chuyển đổi chế độ biên giới: &cTẮT&7.' TOGGLED_WORLD_BORDER_ON: '&e&lBiên giới | &7Chuyển đổi chế độ biên giới: &aBẬT&7.' TRANSFER_ADMIN: '&e&lĐảo | &7Bạn đã chuyển vai trò lãnh đạo {0} cho {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&lLỗi | &7{0} đã là người lãnh đạo hòn đảo của họ.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lLỗi | &7Những người chơi này không ở cùng một hòn đảo.' TRANSFER_ADMIN_NOT_LEADER: '&c&lLỗi | &7Người chơi này không phải là một người lãnh đạo của bất kỳ hòn đảo nào.' TRANSFER_ALREADY_LEADER: '&cBạn đã là người lãnh đạo của hòn đảo này.' TRANSFER_BROADCAST: '&e&lĐảo | &7Lãnh đạo của hòn đảo đã được chuyển cho {0}.' UNBAN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã được dỡ bỏ lệnh cấm trong đảo bởi {1}.' UNCOOP_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã huỷ bỏ tư cách thành viên coop của {1}' UNCOOP_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.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thoát khỏi trò chơi và không còn là một thành viên co-op.' UNIGNORED_ISLAND: '&e&lĐảo | &7Đảo của {0} bây giờ không được bỏ qua từ các đảo hàng đầu.' UNIGNORED_ISLAND_NAME: '&e&lĐảo | &7Đảo {0} bây giờ không được bỏ qua từ các đảo hàng đầu.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho tất cả đảo!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho đảo {1}!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho hòn đảo của {1}!' UNSAFE_WARP: '&e&lĐảo | &7&oCó vẻ như khu vực này không an toàn. Vui lòng thử lại với khu vực khác.' UPDATED_PERMISSION: '&e&lĐảo | &7Đã cập nhật quyền cho {0}.' UPDATED_SETTINGS: '&e&lĐảo | &7Thay đổi thành công điều chỉnh của đảo {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lLỗi | &77Bạn có thể nâng cấp lại trong {0}.' VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lLỗi | &7Bạn không thể sử dụng lệnh này trên đảo khác.' WARP_ALREADY_EXIST: '&c&lLỗi | &7Đã có một khu vực đã được đặt với tên này.' WARP_CATEGORY_ICON_NEW_LORE: | &e&lKhu Vực | &7Hãy nhập mô tả mới (Nhập "-cancel" để hủy): &e&lKhu Vực | &7Bạn có thể xuống dòng bằng cách thêm chữ "\n". WARP_CATEGORY_ICON_NEW_NAME: '&e&lKhu Vực | &7Vui lòng nhập tên (Nhập "-cancel" để hủy):' WARP_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):' WARP_CATEGORY_ICON_UPDATED: '&e&lKhu Vực | &7Cập nhật thành công biểu tượng danh mục.' WARP_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.' WARP_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ự.' WARP_CATEGORY_SLOT: '&e&lKhu Vực | &7Vui lòng nhập vị trí mới (Nhập "-cancel" để hủy):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lLỗi | &7Vị trí đã được dùng bởi một danh mục khu vực khác.' WARP_CATEGORY_SLOT_SUCCESS: '&e&lKhu Vực | &7Thành công thay đổi danh mục tới vị trí {0}.' WARP_CATEGORY_RENAME: '&e&lKhu Vực | &7Vui lòng nhập tên (Nhập "-cancel" để hủy):' WARP_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.' WARP_CATEGORY_RENAME_SUCCESS: '&e&lKhu Vực | &7Thành công đổi tên danh mục thành {0}.' WARP_ICON_NEW_LORE: | &e&lKhu Vực | &7Hãy nhập mô tả mới (Nhập "-cancel" để hủy): &e&lKhu Vực | &7Bạn có thể xuống dòng bằng cách thêm chữ "\n". WARP_ICON_NEW_NAME: '&e&lKhu Vực | &7Vui lòng nhập tên (Nhập "-cancel" để hủy):' WARP_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):' WARP_ICON_UPDATED: '&e&lKhu Vực | &7Cập nhật thành công biểu tượng danh mục.' WARP_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.' WARP_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.' WARP_NAME_TOO_LONG: '&c&lLỗi | &7Tên khu vực không thể dài hơn 255 kí tự.' WARP_PUBLIC_UPDATE: '&e&lKhu Vực | &7Thành công mở khu vực cho công chúng.' WARP_PRIVATE_UPDATE: '&e&lKhu Vực | &7Thành công đóng khu vực đối với công chúng.' WARP_RENAME: '&e&lKhu Vực | &7Vui lòng nhập tên (Nhập "-cancel" để hủy):' WARP_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.' WARP_RENAME_SUCCESS: '&e&lKhu Vực | &7Thành công đổi tên danh mục thành {0}.' WITHDRAW_ALL_MONEY: |- &e&lNgân Hàng | &7Đảo ngân hàng chỉ có {0}$ bên trong. &e&lNgân Hàng | &7&oRút toàn bộ tiền..." WITHDRAW_ANNOUNCEMENT: '&e&lNgân Hàng | &7{0} rút {1}$ từ ngân hàng của đảo!' WITHDRAW_ERROR: '&c&lLỗi | &7{0}.' WITHDRAWN_MONEY: '&e&lNgân Hàng | &7Bạn đã rút ${0} từ đảo của {1}!' WITHDRAWN_MONEY_NAME: '&e&lNgân Hàng | &7Bạn đã rút ${0} từ đảo {1}!' WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lThế Giới | &7Thế giới {0} hiện chưa được mở khóa!' ================================================ FILE: src/main/resources/lang/zh-CN.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## 插件作者 Ome_R ## ## ## ###################################################### # 若你需要创建一个新的语言文件, 那么请复制这个. # 请确保你使用了正确的语言命名格式. # https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html # 可以在这里找到如何正确配置消息文本的教程: # https://wiki.bg-software.com/superiorskyblock/messages ADMIN_ADD_PLAYER: '&e&l岛屿 | &7成功将玩家 {0} 添加至了玩家 {1} 的岛屿.' ADMIN_ADD_PLAYER_NAME: '&e&l岛屿 | &7成功将玩家 {0} 添加至了岛屿 {1}.' ADMIN_DEPOSIT_MONEY: '&e&l银行 | &7你将 ${0} 存入了 {1} 的岛屿银行.' ADMIN_DEPOSIT_MONEY_NAME: '&e&l银行 | &7你存入了 ${0} 至岛屿 {1} 的银行.' ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7由 Ome_R 开发' ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7管理员命令列表[{0}/{1}]:' ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7使用 /is admin {0} 来翻到下一页.' ALREADY_IN_ISLAND: '&c&l错误 | &7你已经处于一个岛屿中了.' ALREADY_IN_ISLAND_OTHER: '&c&l错误 | &7此玩家已经是其他的岛屿成员了.' BAN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 已被 {1} 从该岛屿封禁.' BAN_PLAYERS_WITH_LOWER_ROLE: '&c&l错误 | &7你只能封禁等级低于你的玩家.' BANK_DEPOSIT_CUSTOM: '&e&l银行 | &7输入你需要存入的货币数量:' BANK_DEPOSIT_COMPLETED: '存入成功' BANK_LIMIT_EXCEED: '&c&l错误 | &7你已经达到了银行存量上限.' BANK_WITHDRAW_CUSTOM: '&e&l银行 | &7输入你需要取出的货币数量:' BANK_WITHDRAW_COMPLETED: '取出成功' BANNED_FROM_ISLAND: '&c&l错误 | &7你已被该岛屿封禁.' BLOCK_COUNT_CHECK: '&e&l岛屿 | &7该岛屿有 {0} 个 {1}.' BLOCK_COUNTS_CHECK: | &e&l岛屿 | &7该岛屿包含下列方块: &7{0} BLOCK_COUNTS_CHECK_EMPTY: '&e&l岛屿 | &7该岛屿中不包含任何在追踪列表内的方块.' BLOCK_COUNTS_CHECK_MATERIAL: '{1} x{0}' BLOCK_LEVEL: '&e&l等级 | &7方块 {0} 的等级为 {1}.' BLOCK_LEVEL_WORTHLESS: '&e&l等级 | &7方块 {0} 没有价格.' BLOCK_VALUE: '&e&l价值 | &7方块 {0} 的价值为 {1}.' BLOCK_VALUE_WORTHLESS: '&e&l价值 | &7方块 {0} 没有价格.' BONUS_SYNC_ALL: '&e&l岛屿 | &7成功将该岛屿奖励同步至所有岛屿' BONUS_SYNC_NAME: '&e&l岛屿 | &7成功将该岛屿奖励同步为 {0}.' BONUS_SYNC: '&e&l岛屿 | &7成功将该岛屿奖励同步至了玩家 {0} 的岛屿.' BORDER_PLAYER_COLOR_NAME_BLUE: '蓝' BORDER_PLAYER_COLOR_NAME_RED: '红' BORDER_PLAYER_COLOR_NAME_GREEN: '绿' BORDER_PLAYER_COLOR_UPDATED: '&e&l边界 | &7成功将个人的边界颜色设置为了 {0}.' BUILD_OUTSIDE_ISLAND: '&c&l错误 | &7你不能在保护范围外进行建筑行为.' CANNOT_SET_ROLE: '&c&l错误 | &7你不能将玩家的等级设置为 {0}.' CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&l错误 | &7你只能修改等级低于你的玩家的权限.' CHANGED_BANK_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿银行存款上限.' CHANGED_BANK_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的银行存款上限.' CHANGED_BANK_LIMIT_NAME: '&e&l升级 | &7成功更新了 {0} 的岛屿银行上限.' CHANGED_BIOME: '&e&l岛屿 | &7成功将生物群系修改为了 {0}. 你可能需要重新进入服务器才可看见改动.' CHANGED_BIOME_ALL: '&e&l岛屿 | &7成功将所有岛屿的生物群系修改为了 {0}.' CHANGED_BIOME_NAME: '&e&l岛屿 | &7成功将岛屿 {1} 的生物群系修改为了 {0}.' CHANGED_BIOME_OTHER: '&e&l岛屿 | &7成功将玩家 {1} 的岛屿生物群系修改为了 {0}.' CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7成功将 {0} 的方块数量设置为了 {1}.' CHANGED_BLOCK_LIMIT: '&e&l升级 | &7成功更新了岛屿 {1} 的方块 {0} 限制.' CHANGED_BLOCK_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的方块 {0} 限制.' CHANGED_BLOCK_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的方块 {0} 限制.' CHANGED_BONUS_LEVEL: '&e&l岛屿 | &7成功更新了玩家 {0} 的岛屿等级奖励.' CHANGED_BONUS_LEVEL_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的等级奖励.' CHANGED_BONUS_LEVEL_NAME: '&e&l岛屿 | &7成功更新了岛屿 {0} 的等级奖励.' CHANGED_BONUS_WORTH: '&e&l岛屿 | &7成功更新了玩家 {0} 的岛屿价值奖励.' CHANGED_BONUS_WORTH_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的价值奖励.' CHANGED_BONUS_WORTH_NAME: '&e&l岛屿 | &7成功更新了岛屿 {0} 的价值奖励.' CHANGED_CHEST_SIZE: '&e&lChest | &7成功将玩家 {2} 的岛屿仓库 #{0} 的行数更新为了 {1}.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7成功将所有岛屿的岛屿仓库 #{0} 的行数更新为了 {1}.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7成功将岛屿 {2} 的岛屿仓库 #{0} 的行数更新为了 {1}.' CHANGED_COOP_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿成员数量限制.' CHANGED_COOP_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的岛屿成员数量限制.' CHANGED_COOP_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的岛屿成员数量限制.' CHANGED_CROP_GROWTH: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿作物生长速率.' CHANGED_CROP_GROWTH_ALL: '&e&l升级 | &7成功更新了所有岛屿的作物生长速率.' CHANGED_CROP_GROWTH_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的作物生长速率.' CHANGED_DISCORD: '&e&l岛屿 | &7成功将岛屿的 Discord 群组聊天设置为了 {0}.' CHANGED_ENTITY_LIMIT: '&e&l升级 | &7成功将玩家 {1} 的岛屿实体限制修改为了 {0}.' CHANGED_ENTITY_LIMIT_ALL: '&e&l升级 | &7成功将所有岛屿的实体限制修改为了 {0}.' CHANGED_ENTITY_LIMIT_NAME: '&e&l升级 | &7成功将岛屿 {1} 的实体限制修改为了 {0}.' CHANGED_ISLAND_EFFECT_LEVEL: '&e&l升级 | &7成功将玩家 {1} 的岛屿效果等级修改为了 {0}.' CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&l升级 | &7成功将所有岛屿的效果等级修改为了 {0}.' CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&l升级 | &7成功将岛屿 {1} 的效果等级修改为了 {0}.' CHANGED_ISLAND_SIZE: '&e&l升级 | &7成功修改了玩家 {0} 的岛屿边界大小.' CHANGED_ISLAND_SIZE_ALL: '&e&l升级 | &7成功更新了所有岛屿的边界大小.' CHANGED_ISLAND_SIZE_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的边界大小.' CHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&o玩家可以在他们岛屿的外部进行建筑行为, 所以岛屿大小限制功能无效. 可以在配置文本对这些设置进行调整以使其再次有效.' CHANGED_LANGUAGE: '&e&l语言 | &7成功将你的语言修改为了简体中文.' CHANGED_MOB_DROPS: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿掉落物翻倍量.' CHANGED_MOB_DROPS_ALL: '&e&l升级 | &7成功更新了所有岛屿的掉落物翻倍量.' CHANGED_MOB_DROPS_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的掉落物翻倍量.' CHANGED_NAME: '&e&l岛屿 | &7你将岛屿的名称修改为了 {0}&7.' CHANGED_NAME_OTHER: '&e&l岛屿 | &7你将玩家 {0} 的岛屿名称修改为了 {1}&7.' CHANGED_NAME_OTHER_NAME: '&e&l岛屿 | &7你将岛屿 {0}&7 的名称修改为了 {1}&7.' CHANGED_PAYPAL: '&e&l岛屿 | &7成功将岛屿的 Paypal 支付链接修改为了 {0}.' CHANGED_ROLE_LIMIT: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿角色 {0} 的限制.' CHANGED_ROLE_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的角色 {0} 限制.' CHANGED_ROLE_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的角色 {0} 限制.' CHANGED_SPAWNER_RATES: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的刷怪翻倍量.' CHANGED_SPAWNER_RATES_ALL: '&e&l升级 | &7成功更新了所有岛屿的刷怪翻倍量.' CHANGED_SPAWNER_RATES_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的刷怪翻倍量.' CHANGED_TEAM_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的团队限制.' CHANGED_TEAM_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的团队限制.' CHANGED_TEAM_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的团队限制.' CHANGED_TELEPORT_LOCATION: '&e&l岛屿 | &7成功更新了传送点的位置.' CHANGED_WARPS_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的传送点数量限制.' CHANGED_WARPS_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的传送点数量限制.' CHANGED_WARPS_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的传送点数量限制.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: '数量' COMMAND_ARGUMENT_BIOME: '群系' COMMAND_ARGUMENT_BORDER_COLOR: '边界颜色' COMMAND_ARGUMENT_COMMAND: '命令...' COMMAND_ARGUMENT_DIMENSION: '维度' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: '药水效果' COMMAND_ARGUMENT_EMAIL: '邮箱' COMMAND_ARGUMENT_ENTITY: '实体' COMMAND_ARGUMENT_ISLAND_NAME: '岛屿名称' COMMAND_ARGUMENT_ISLAND_ROLE: '岛屿角色' COMMAND_ARGUMENT_LEADER: '领袖' COMMAND_ARGUMENT_LEVEL: '等级' COMMAND_ARGUMENT_LIMIT: '限制' COMMAND_ARGUMENT_MATERIAL: '材料' COMMAND_ARGUMENT_MENU: '菜单名称' COMMAND_ARGUMENT_MESSAGE: '消息...' COMMAND_ARGUMENT_MISSION_CATEGORY: '任务分类' COMMAND_ARGUMENT_MISSION_NAME: '任务名称' COMMAND_ARGUMENT_MODULE_NAME: '模块名称' COMMAND_ARGUMENT_MULTIPLIER: '翻倍卡' COMMAND_ARGUMENT_NAME: '名称' COMMAND_ARGUMENT_NEW_LEADER: '新领袖' COMMAND_ARGUMENT_PAGE: '页码' COMMAND_ARGUMENT_PATH: '路径' COMMAND_ARGUMENT_PERMISSION: '权限' COMMAND_ARGUMENT_PLAYER_NAME: '玩家名称' COMMAND_ARGUMENT_PRIVATE: '私有' COMMAND_ARGUMENT_RATING: '评分' COMMAND_ARGUMENT_ROWS: '行数' COMMAND_ARGUMENT_SCHEMATIC_NAME: '结构名称' COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: '设置' COMMAND_ARGUMENT_SIZE: '大小' COMMAND_ARGUMENT_TIME: '事件' COMMAND_ARGUMENT_TITLE_DURATION: '持续时间' COMMAND_ARGUMENT_TITLE_FADE_IN: '淡入时间' COMMAND_ARGUMENT_TITLE_FADE_OUT: '淡出时间' COMMAND_ARGUMENT_UPGRADE_NAME: '升级名称' COMMAND_ARGUMENT_VALUE: '值' COMMAND_ARGUMENT_WARP_NAME: '传送点名称' COMMAND_ARGUMENT_WARP_CATEGORY: '传送点分类' COMMAND_ARGUMENT_WORLD: '世界' COMMAND_COOLDOWN_FORMAT: '&c&l错误 | &7你只能在 {0} 中使用该命令.' COMMAND_DESCRIPTION_ACCEPT: '接受玩家的邀请.' COMMAND_DESCRIPTION_ADMIN: '使用管理员命令.' COMMAND_DESCRIPTION_ADMIN_ADD: '将玩家添加至岛屿.' COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: '为指定玩家的岛屿增加银行存款上限.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: '为指定玩家的岛屿增加方块数量上限.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: '向指定玩家添加奖励.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: '为指定玩家的岛屿增加合作玩家数量上限.' COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: '为指定玩家的岛屿提升作物生长速度速率.' COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: '为指定岛屿添加岛屿效果.' COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: '为指定岛屿添加实体数量限制.' COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: '为岛屿刷石机增加指定方块生成的百分比.' COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: '为指定玩家的岛屿增加刷怪掉落物倍率.' COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: '提升指定玩家的岛屿大小.' COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: '为指定玩家的岛屿提升刷怪笼刷怪倍率.' COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: '为指定玩家的岛屿增加团队上限.' COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: '为指定玩家的岛屿设置传送点数量上限.' COMMAND_DESCRIPTION_ADMIN_BONUS: '使指定玩家获得奖励.' COMMAND_DESCRIPTION_ADMIN_BYPASS: '切换绕过模式.' COMMAND_DESCRIPTION_ADMIN_CHEST: '打开指定岛屿的仓库.' COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: '为指定岛屿清除生成器几率.' COMMAND_DESCRIPTION_ADMIN_CLOSE: '将指定岛屿设置为私有.' COMMAND_DESCRIPTION_ADMIN_CMD_ALL: '为指定岛屿上的所有成员执行命令.' COMMAND_DESCRIPTION_ADMIN_COUNT: '检查指定岛屿上的所有方块数量.' COMMAND_DESCRIPTION_ADMIN_DATA: '交互指定玩家或岛屿的持久化数据.' COMMAND_DESCRIPTION_ADMIN_DEBUG: '切换调试模式.' COMMAND_DESCRIPTION_ADMIN_DEL_WARP: '删除指定岛屿的传送点.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: '将岛屿中的指定玩家升职.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: '向指定岛屿的银行中存款.' COMMAND_DESCRIPTION_ADMIN_DISBAND: '永久解散指定岛屿.' COMMAND_DESCRIPTION_ADMIN_FLY: '切换指定玩家的岛屿飞行.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: '使指定玩家从其团队中解散.' COMMAND_DESCRIPTION_ADMIN_IGNORE: '将指定岛屿设置为不参与排行榜排名.' COMMAND_DESCRIPTION_ADMIN_JOIN: '强制加入岛屿.' COMMAND_DESCRIPTION_ADMIN_KICK: '将指定玩家从其岛屿中踢出.' COMMAND_DESCRIPTION_ADMIN_MODULES: '管理插件模块.' COMMAND_DESCRIPTION_ADMIN_MISSION: '修改指定玩家的任务状态.' COMMAND_DESCRIPTION_ADMIN_MSG: '向玩家发送不带前缀的消息.' COMMAND_DESCRIPTION_ADMIN_MSG_ALL: '向岛屿上的所有玩家发送不带前缀的消息.' COMMAND_DESCRIPTION_ADMIN_NAME: '修改指定岛屿的名称.' COMMAND_DESCRIPTION_ADMIN_OPEN: '将指定岛屿设置为公开状态.' COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: '为指定玩家打开自定义菜单.' COMMAND_DESCRIPTION_ADMIN_PROMOTE: '将岛屿中的指定玩家升职.' COMMAND_DESCRIPTION_ADMIN_PURGE: '转化岛屿.' COMMAND_DESCRIPTION_ADMIN_RANKUP: '为指定岛屿提升等级.' COMMAND_DESCRIPTION_ADMIN_RECALC: '重新计算指定岛屿的价值.' COMMAND_DESCRIPTION_ADMIN_RELOAD: '重载本插件的所有配置和进程.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: '去除指定岛屿的方块数量限制.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: '去除指定岛屿的实体数量限制.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: '去除指定玩家的所有评分.' COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: '重置指定岛屿的所有权限.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: '重置指定岛屿的所有设置.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: '重置指定岛屿所在的世界.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: '从插件创建结构文件.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: '设置指定玩家的岛屿银行存款上限.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: '设置指定岛屿的生物群系.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: '设置指定位置的方块数量.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: '设置指定岛屿的方块数量限制.' COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: '设置指定岛屿的仓库容量.' COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: '设置指定岛屿的合作玩家数量.' COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: '设置指定岛屿的作物生长倍率.' COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: '设置岛屿解散所需玩家数量.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: '设置指定岛屿的效果等级.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: '设置指定岛屿的实体数量限制.' COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: '设置岛屿的预览位置.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: '将岛屿所有权转移给其他玩家.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: '设置指定岛屿的生物掉落物倍率.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: '设置所有岛屿上的指定权限所需的职位.' COMMAND_DESCRIPTION_ADMIN_SET_RATE: '设置指定玩家的评分.' COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: '设置指定岛屿的角色限制.' COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: '为指定岛屿设置角色限制.' COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: '设置刷石机生成的指定材料几率.' COMMAND_DESCRIPTION_ADMIN_SET_SIZE: '修改指定岛屿的边界大小.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: '设置服务器的出生点区域.' COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: '设置指定岛屿的刷怪笼生成效率.' COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: '设置指定岛屿的成员数量限制.' COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: '设置指定岛屿的指定功能等级.' COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: '设置指定岛屿的传送点数量限制.' COMMAND_DESCRIPTION_ADMIN_SETTINGS: '打开插件的设置编辑器.' COMMAND_DESCRIPTION_ADMIN_SHOW: '获取岛屿有关信息.' COMMAND_DESCRIPTION_ADMIN_SPAWN: '传送至出生点.' COMMAND_DESCRIPTION_ADMIN_SPY: '切换聊天窃听模式' COMMAND_DESCRIPTION_ADMIN_STATS: '显示有关插件的信息.' COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: '同步指定岛屿与指定世界的奖励.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: '同步指定岛屿的升级数值.' COMMAND_DESCRIPTION_ADMIN_TELEPORT: '传送至指定岛屿.' COMMAND_DESCRIPTION_ADMIN_TITLE: '向玩家发送标题消息.' COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: '向指定岛屿的所有成员发送标题消息.' COMMAND_DESCRIPTION_ADMIN_UNIGNORE: '将指定岛屿重新设置为参与排行榜排名.' COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: '解锁指定岛屿的世界.' COMMAND_DESCRIPTION_ADMIN_WITHDRAW: '从指定岛屿的银行中取款.' COMMAND_DESCRIPTION_BALANCE: '检查指定岛屿银行中的存款.' COMMAND_DESCRIPTION_BAN: '将指定玩家从你的岛屿上封禁.' COMMAND_DESCRIPTION_BANK: '打开岛屿银行.' COMMAND_DESCRIPTION_BANS: '打开封禁菜单.' COMMAND_DESCRIPTION_BIOME: '更换岛屿生物群系.' COMMAND_DESCRIPTION_BORDER: '更换岛屿边界颜色.' COMMAND_DESCRIPTION_CHEST: '打开岛屿仓库.' COMMAND_DESCRIPTION_CLOSE: '将岛屿设置为不对外开放.' COMMAND_DESCRIPTION_COOP: '将指定玩家添加为合作伙伴.' COMMAND_DESCRIPTION_COOPS: '打开合作玩家菜单.' COMMAND_DESCRIPTION_COUNTS: '查看岛屿中的方块限制.' COMMAND_DESCRIPTION_CREATE: '创建一个新的岛屿.' COMMAND_DESCRIPTION_DEL_WARP: '删除指定的岛屿传送点.' COMMAND_DESCRIPTION_DEMOTE: '降职岛屿中的指定玩家.' COMMAND_DESCRIPTION_DEPOSIT: '从你的个人钱包中将钱转入岛屿银行.' COMMAND_DESCRIPTION_DISBAND: '永久解散岛屿.' COMMAND_DESCRIPTION_EXPEL: '踢出岛屿上的指定参观者.' COMMAND_DESCRIPTION_FLY: '切换岛屿飞行.' COMMAND_DESCRIPTION_HELP: '列出所有命令.' COMMAND_DESCRIPTION_INVITE: '将指定玩家邀请至你的岛屿.' COMMAND_DESCRIPTION_KICK: '将指定玩家从你的岛屿踢出.' COMMAND_DESCRIPTION_LANG: '修改你所使用的语言.' COMMAND_DESCRIPTION_LEAVE: '离开你的岛屿.' COMMAND_DESCRIPTION_MEMBERS: '打开成员菜单.' COMMAND_DESCRIPTION_MISSION: '完成任务.' COMMAND_DESCRIPTION_MISSIONS: '打开任务菜单.' COMMAND_DESCRIPTION_NAME: '修改岛屿的名称.' COMMAND_DESCRIPTION_OPEN: '将岛屿设置为对外开放.' COMMAND_DESCRIPTION_PANEL: '打开岛屿控制界面.' COMMAND_DESCRIPTION_PARDON: '解除对指定玩家的岛屿封禁.' COMMAND_DESCRIPTION_PERMISSIONS: '获取指定岛屿职位的所有权限.' COMMAND_DESCRIPTION_PROMOTE: '升职岛屿中的指定成员.' COMMAND_DESCRIPTION_RANKUP: '提升指定功能的等级.' COMMAND_DESCRIPTION_RATE: '为指定岛屿评分.' COMMAND_DESCRIPTION_RATINGS: '显示所有岛屿评分.' COMMAND_DESCRIPTION_SETTINGS: '打开设置菜单.' COMMAND_DESCRIPTION_RECALC: '重新计算岛屿价值.' COMMAND_DESCRIPTION_SET_DISCORD: '设置岛屿成员使用的 Discord 聊天群组.' COMMAND_DESCRIPTION_SET_PAYPAL: '设置岛屿成员使用的 Paypal 聊天群组.' COMMAND_DESCRIPTION_SET_ROLE: '更换指定玩家的职位.' COMMAND_DESCRIPTION_SET_TELEPORT: '修改岛屿的传送点位置.' COMMAND_DESCRIPTION_SET_WARP: '创建一个新的岛屿传送点.' COMMAND_DESCRIPTION_SHOW: '获取指定岛屿的信息.' COMMAND_DESCRIPTION_TEAM: '获取指定岛屿的成员信息.' COMMAND_DESCRIPTION_TEAM_CHAT: 'T切换聊天模式.' COMMAND_DESCRIPTION_TELEPORT: '传送至你的岛屿.' COMMAND_DESCRIPTION_TOGGLE: '切换岛屿边界和方块堆叠放置模式.' COMMAND_DESCRIPTION_TOP: '打开岛屿设置界面.' COMMAND_DESCRIPTION_TRANSFER: '转移岛屿拥有权.' COMMAND_DESCRIPTION_UNCOOP: '移除岛屿中指定玩家的成员关系.' COMMAND_DESCRIPTION_UPGRADE: '打开升级界面.' COMMAND_DESCRIPTION_VALUE: '获取指定方块的价值.' COMMAND_DESCRIPTION_VALUES: '打开价值菜单.' COMMAND_DESCRIPTION_VISIT: '传送至岛屿的访客传送点.' COMMAND_DESCRIPTION_VISITORS: '打开岛屿访客菜单.' COMMAND_DESCRIPTION_WARP: '传送至岛屿的指定传送点.' COMMAND_DESCRIPTION_WARPS: '打开岛屿传送点菜单.' COMMAND_DESCRIPTION_WITHDRAW: '从岛屿银行中取出指定数额的硬币至你的钱包.' COMMAND_USAGE: '&c用法: /{0}' COOP_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将玩家 {1} 添加为了合作成员.' COOP_BANNED_PLAYER: '&c&l错误 | &7该玩家已被该岛屿封禁, 不可成为该岛屿的合作成员.' COOP_LIMIT_EXCEED: '&c&l错误 | &7该岛屿已达到了可设置的合作成员的最大数量.' CREATE_ISLAND: '&e&l岛屿 | &7成功在 {0} 位置创建了岛屿, 耗时 {1}ms.' CREATE_ISLAND_FAILURE: '&c&l错误 | &7创建岛屿时遇到未知错误. 请联系服务器管理员以排查该问题.' CREATE_WORLD_FAILURE: '&c&l错误 | &7创建你的世界时遇到位置错误. 请联系服务器管理员以排查该问题.' DEBUG_MODE_DISABLED: '&e&lDebug | &7调试模式已 &c关闭&7.' DEBUG_MODE_ENABLED: '&e&lDebug | &7调试模式 &a开启&7.' DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7调试模式过滤 {0} 已 &a开启&7.' DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7所有调试模式过滤已 &c关闭&7.' DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7调试模式过滤 {0} 已 &c关闭&7.' DELETE_WARP: '&e&l岛屿 | &7你删除了传送点 {0}.' DELETE_WARP_SIGN_BROKE: '&7&o检测到有木牌绑定了该传送点, 将会自动失效...' DEMOTE_LEADER: '&c&l错误 | &7你不能降级岛屿领袖.' DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&l错误 | &7你只能降级角色职位低于你的玩家.' DEMOTED_MEMBER: '&e&l岛屿 | &7你将岛屿中的玩家 {0} 降级为了 {1}.' DEPOSIT_ANNOUNCEMENT: '&e&l银行 | &7{0} 向岛屿银行存入了 ${1} !' DEPOSIT_ERROR: '&c&l错误 | &7{0}.' DESTROY_OUTSIDE_ISLAND: '&c&l错误 | &7你不能在保护范围外破坏.' DISBAND_ANNOUNCEMENT: '&e&l岛屿 | &7你的岛屿已经被玩家 {0} 解散.' DISBAND_GIVE: '&e&l岛屿 | &7你收到了 {0} 个解散.' DISBAND_GIVE_ALL: '&e&l岛屿 | &7你对所有玩家进行了 {0} 个解散.' DISBAND_GIVE_OTHER: '&e&l岛屿 | &7你将 {0} 个解散给予了玩家 {1}.' DISBAND_ISLAND_BALANCE_REFUND: '&7&o你的岛屿已被解散, 根据岛屿银行的存款记录, 你已被退还 ${0}' DISBAND_SET: '&e&l岛屿 | &7你的解散数量已被设置为 {0}.' DISBAND_SET_ALL: '&e&l岛屿 | &7你将所有玩家的解散数量设置为了 {0}.' DISBAND_SET_OTHER: '&e&l岛屿 | &7你将玩家 {0} 的解散数量设置为了 {1}.' DISBANDED_ISLAND: '&e&l岛屿 | &7你解散了你的岛屿.' DISBANDED_ISLAND_OTHER: '&e&l岛屿 | &7你解散了玩家 {0} 的岛屿.' DISBANDED_ISLAND_OTHER_NAME: '&e&l岛屿 | &7你解散了岛屿 {0}.' ENTER_PVP_ISLAND: '&7&o你被传送至了开启了 PVP 的岛屿. 接下来的 10 秒内你将处于无敌状态...' EXPELLED_PLAYER: '&e&l岛屿 | &7{0} 已从该岛屿被开除.' FORMAT_QUAD: 'Q' FORMAT_TRILLION: 'T' FORMAT_BILLION: 'B' FORMAT_MILLION: 'M' FORMAT_THOUSANDS: 'K' FORMAT_SECONDS_NAME: '秒' FORMAT_SECOND_NAME: '秒' FORMAT_MINUTES_NAME: '分' FORMAT_MINUTE_NAME: '分' FORMAT_HOURS_NAME: '时' FORMAT_HOUR_NAME: '时' FORMAT_DAYS_NAME: '天' FORMAT_DAY_NAME: '天' GENERATOR_CLEARED: '&e&l岛屿 | &7成功清除了玩家 {0} 的岛屿上的所有生成器.' GENERATOR_CLEARED_NAME: '&e&l岛屿 | &7成功清除了岛屿 {0} 上的所有生成器.' GENERATOR_CLEARED_ALL: '&e&l岛屿 | &7成功清除了所有岛屿上的所有生成器.' GENERATOR_UPDATED: '&e&l岛屿 | &7成功更新了玩家 {1} 的岛屿上的 {0} 生成器数量 .' GENERATOR_UPDATED_NAME: '&e&l岛屿 | &7成功更新了岛屿 {1} 上的 {0} 生成器数量.' GENERATOR_UPDATED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿上的 {0} 生成器数量.' GLOBAL_COMMAND_EXECUTED: '&e&l岛屿 | &7成功为玩家 {0} 的岛屿成员执行了命令!' GLOBAL_COMMAND_EXECUTED_NAME: '&e&l岛屿 | &7成功为岛屿 {0} 上的所有成员执行了命令!' GLOBAL_MESSAGE_SENT: '&e&l岛屿 | &7成功将消息发送至玩家 {0} 岛屿上的所有成员!' GLOBAL_MESSAGE_SENT_NAME: '&e&l岛屿 | &7成功将消息发送至岛屿 {0} 上的所有成员!' GLOBAL_TITLE_SENT: '&e&l岛屿 | &7成功将标题消息发送至玩家 {0} 岛屿上的所有成员!' GLOBAL_TITLE_SENT_NAME: '&e&l岛屿 | &7成功将标题消息发送至岛屿 {0} 上的所有成员!' GOT_BANNED: '&e&l岛屿 | &7你已被玩家 {0} 的岛屿封禁.' GOT_DEMOTED: '&e&l岛屿 | &7你在你的岛屿中被降职为 {0} 角色.' GOT_EXPELLED: '&e&l岛屿 | &7&o你已被岛屿 {0} 开除.' GOT_INVITE: '&e&l岛屿 | &7{0} 邀请了你至他的岛屿.' GOT_INVITE_TOOLTIP: '&7点击该消息来同意请求.' GOT_KICKED: '&e&l岛屿 | &7你被玩家 {0} 踢出了岛屿.' GOT_PROMOTED: '&e&l岛屿 | &7你在你的岛屿中被升职为 {0} 角色.' GOT_REVOKED: '&e&l岛屿 | &7{0} 撤回了对你的邀请.' GOT_UNBANNED: '&e&l岛屿 | &7你已从岛屿 {0} 被解除封禁.' HIT_ISLAND_MEMBER: '&c&l错误 | &7你不能攻击你的岛屿成员.' HIT_PLAYER_IN_ISLAND: '&c&l错误 | &7你不能攻击岛屿内的成员.' IGNORED_ISLAND: '&e&l岛屿 | &7{0} 的岛屿现在已不参与排行榜计算.' IGNORED_ISLAND_NAME: '&e&l岛屿 | &7岛屿 {0} 现在已不参与岛屿排行榜计算.' INTERACT_OUTSIDE_ISLAND: '&c&l错误 | &7你不能在保护范围外进行交互.' INVALID_AMOUNT: '&c&l错误 | &7无效数量 {0}.' INVALID_BIOME: '&c&l错误 | &7无效生物群系 {0}.' INVALID_BLOCK: '&c&l错误 | &7无效方块位置 {0}.' INVALID_BORDER_COLOR: '&c&l错误 | &7无效边界颜色 {0}.' INVALID_COMMAND: '&c&l错误 | &7无效命令 {0}.' INVALID_EFFECT: '&c&l错误 | &7无效效果 {0}.' INVALID_ENTITY: '&c&l错误 | &7无效实体 {0}.' INVALID_ENVIRONMENT: '&c&l错误 | &7无效维度 {0}.' INVALID_INTERVAL: '&c&l错误 | &7无效间隔 {0}.' INVALID_ISLAND: '&c&l错误 | &7你没有岛屿.' INVALID_ISLAND_LOCATION: '&c&l错误 | &7你当前位置没有岛屿.' INVALID_ISLAND_OTHER: '&c&l错误 | &7{0} 没有岛屿.' INVALID_ISLAND_OTHER_NAME: '&c&l错误 | &7找不到名称为 {0} 的岛屿.' INVALID_ISLAND_PERMISSION: | &c&l错误 | &7找不到岛屿权限 {0}. &c&l错误 | &7岛屿权限: {1} INVALID_LEVEL: '&c&l错误 | &7无效等级 {0}.' INVALID_LIMIT: '&c&l错误 | &7无效限制 {0}.' INVALID_MATERIAL: '&c&l错误 | &7无效材料名 {0}.' INVALID_MATERIAL_DATA: '&c&l错误 | &7无效材料数据 {0}.' INVALID_MENU: '&c&l错误 | &7无效菜单 {0}.' INVALID_MISSION: '&c&l错误 | &7无效任务 {0}.' INVALID_MISSION_CATEGORY: '&c&l错误 | &7无效任务分类 {0}.' INVALID_MODULE: '&c&l错误 | &7无效模块 {0}.' INVALID_MULTIPLIER: '&c&l错误 | &7无效翻倍 {0}.' INVALID_PAGE: '&c&l错误 | &7无效页码 {0}.' INVALID_PERCENTAGE: '&c&l错误 | &7百分比数值必须介于 0 和 100.' INVALID_PLAYER: '&c&l错误 | &7找不到名为 {0} 的玩家' INVALID_RATE: | &c&l错误 | &7找不到名为 {0} 的评分. &c&l错误 | &7岛屿评分: {1} INVALID_ROWS: '&c&l错误 | &7无效行数: {0}' INVALID_ROLE: | &c&l错误 | &7找不到名为 {0} 的角色. &c&l错误 | &7岛屿角色: {1} INVALID_SCHEMATIC: '&c&l错误 | &7找不到名为 {0} 的结构文件.' INVALID_SETTINGS: | &c&l错误 | &7找不到名为 {0} 的岛屿设置. &c&l错误 | &7岛屿设置: {1} INVALID_SIZE: '&c&l错误 | &7无效大小 {0}.' INVALID_SLOT: '&c&l错误 | &7无效位置 {0}.' INVALID_TITLE: '&c&l错误 | &7输入的标题信息无效.' INVALID_TOGGLE_MODE: '&c&l错误 | &7不能切换模式 {0}.' INVALID_UPGRADE: | &c&l错误 | &7找不到名为 {0} 的可升级功能. &c&l错误 | &7可升级功能: {1} INVALID_VISIT_LOCATION: '&c&l错误 | &7该岛屿没有访客传送位置.' INVALID_VISIT_LOCATION_BYPASS: '&7&o你开启了岛屿绕过保护模式, 正在为你传送至该岛屿...' INVALID_WARP: '&c&l错误 | &7无效传送点 {0}.' INVALID_WORLD: '&c&l错误 | &7I无效世界 {0}.' INVITE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将玩家 {1} 邀请至了岛屿.' INVITE_BANNED_PLAYER: '&c&l错误 | &7该玩家已从岛屿被封禁, 不可接受任何邀请.' INVITE_TO_FULL_ISLAND: '&c&l错误 | &7你不能再向岛屿邀请更多成员了.' ISLAND_ALREADY_CLOSED: '&c&l错误 | &7该岛屿已经设置为不对公众开放了.' ISLAND_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的岛屿.' ISLAND_ALREADY_OPENED: '&c&l错误 | &7该岛屿已经设置为对公众开放了.' ISLAND_BANK_EMPTY: '&e&l银行 | &7岛屿银行中没有存款.' ISLAND_BANK_SHOW: '&e&l银行 | &7你的岛屿银行存款为 ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&l银行 | &7玩家 {0} 的岛屿银行存款为 ${1}.' ISLAND_BANK_SHOW_OTHER_NAME: '&e&l银行 | &7岛屿 {0} 的银行存款为 ${1}.' ISLAND_BEING_CALCULATED: '&c&l错误 | &7正在进行计算, 不可以与方块交互!' ISLAND_CLOSED: '&e&l岛屿 | &7成功将岛屿设置为不对公众开放.' ISLAND_CREATE_PROCESS_FAIL: '&c&l错误 | &7你已经有一个正在进行的岛屿创建进程了.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&l岛屿 | &7正在处理你的请求...' ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&l飞行 | &7岛屿飞行已自动 &c关闭&7.' ISLAND_FLY_ENABLED: '&e&l飞行 | &7岛屿飞行已自动 &a打开&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&l岛屿 | &7&o你正处于一个被解散的岛屿, 正在将你传送回主城...' ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&l岛屿 | &7&o你正处于一个开启了 PVP 的岛屿, 正在将你传送回主城...' ISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock&7, 由 Ome_R 开发' ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7命令列表 [{0}/{1}]:' ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' ISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7使用 /is help {0} 来翻到下一页.' ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&l岛屿 | &7银行限制: {0}' ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | &e&l岛屿 | &7方块限制: {0} ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&l岛屿 | &7 {0}: {1}' ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&l岛屿 | &7合作成员数量限制: {0}' ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&l岛屿 | &7作物生长速率: {0}' ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&l岛屿 | &7掉落物翻倍: {0}' ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | &e&l岛屿 | &7岛屿效果: {0} ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&l岛屿 | &7 {0}: {1}' ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | &e&l岛屿 | &7实体限制: {0} ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&l岛屿 | &7 {0}: {1}' ISLAND_INFO_ADMIN_GENERATOR_RATES: | &e&l岛屿 | &7刷怪比率 ({1}): {0} ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&l岛屿 | &7 {0}: {1}% ({2})' ISLAND_INFO_ADMIN_ROLE_LIMITS: | &e&l岛屿 | &7角色限制: {0} ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&l岛屿 | &7 {0}: {1}' ISLAND_INFO_ADMIN_SIZE: '&e&l岛屿 | &7边界大小: {0}' ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&l岛屿 | &7刷怪笼生成倍率: {0}' ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&l岛屿 | &7团队限制: {0}' ISLAND_INFO_ADMIN_UPGRADES: | &e&l岛屿 | &7功能升级: {0} ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&l岛屿 | &7 {0}: {1}' ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&l岛屿 | &7传送点限制: {0}' ISLAND_INFO_BANK: '&e&l岛屿 | &7银行: {0}' ISLAND_INFO_BONUS: '&e&l岛屿 | &7价值奖励: {0}' ISLAND_INFO_BONUS_LEVEL: '&e&l岛屿 | &7等级奖励: {0}' ISLAND_INFO_CREATION_TIME: '&e&l岛屿 | &7创建时间: {0}' ISLAND_INFO_DISCORD: '&e&l岛屿 | &7Discord: {0}' ISLAND_INFO_FOOTER: '' ISLAND_INFO_HEADER: '' ISLAND_INFO_LAST_TIME_UPDATED: '&e&l岛屿 | &7最后更新: {0} 前' ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&l岛屿 | &7最后更新: &a正在活跃' ISLAND_INFO_LEVEL: '&e&l岛屿 | &7等级: {0}' ISLAND_INFO_LOCATION: '&e&l岛屿 | &7家: {0}' ISLAND_INFO_NAME: '&e&l岛屿 | &7名称: {0}' ISLAND_INFO_OWNER: '&e&l岛屿 | &7领袖: {0}' ISLAND_INFO_PAYPAL: '&e&l岛屿 | &7Paypal: {0}' ISLAND_INFO_PLAYER_LINE: '&e&l岛屿 | &7 - {0}' ISLAND_INFO_RATE: '&e&l岛屿 | &7评分: {0} &7({1}/5) - 共 {2} 个评分.' ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' ISLAND_INFO_RATE_SYMBOL: '✦' ISLAND_INFO_RATE_ONE_COLOR: '&4' ISLAND_INFO_RATE_TWO_COLOR: '&6' ISLAND_INFO_RATE_THREE_COLOR: '&e' ISLAND_INFO_RATE_FOUR_COLOR: '&a' ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&l岛屿 | &7{0}s: {1} ISLAND_INFO_VISITORS_COUNT: '&e&l岛屿 | &7访客数量: {0} ({1} 位独立访客)' ISLAND_INFO_WORTH: '&e&l岛屿 | &7价值: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&l岛屿 | &7成功将岛屿设置为对公众开放.' ISLAND_OWNER_NONE: None ISLAND_PREVIEW_BLOCK_COMMAND: '&c&l错误 | &7你不能在预览模式中使用该命令.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&l结构 | &7你离得太远离了, 已自动退出预览模式.' ISLAND_PREVIEW_CANCEL: '&e&l结构 | &7你退出了预览模式.' ISLAND_PREVIEW_CONFIRM_TEXT: '确认' ISLAND_PREVIEW_CANCEL_TEXT: '取消' ISLAND_PREVIEW_SET: '&e&l预览 | &7成功将结构 {0} 的预览位置设置为 {1}.' ISLAND_PREVIEW_START: | &e&l结构 | &7你正在预览结构 {0}. &e&l结构 | &7输入 &a&lCONFIRM &7来创建一个新岛屿, 或 &c&lCANCEL &7取消预览模式. &e&l结构 | &7你不能离开该岛屿的区域, 否则将会自动退出岛屿预览. ISLAND_PROTECTED: '&c&l错误 | &7该岛屿受到保护.' ISLAND_PROTECTED_OPPED: '&7&o你可通过输入命令 "/is admin bypass" 来绕过该限制.' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&l岛屿 | &7成员 {0} 的岛屿 &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(离线)' ISLAND_TEAM_STATUS_ONLINE: '&a(在线)' ISLAND_TEAM_STATUS_ROLES: '&e&l岛屿 | &7 * [{0}] {1} {2} &7({3})' ISLAND_TOP_STATUS_OFFLINE: '&c(离线)' ISLAND_TOP_STATUS_ONLINE: '&a(在线)' ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[私有]' ISLAND_WAS_CLOSED: '&e&l岛屿 | &7&o你所处的岛屿已关闭, 你已被自动传送回主城...' ISLAND_WORTH_ERROR: '&c&l错误 | &7进行岛屿计算时出现错误. 若问题持续出现请尝试联系管理员.' ISLAND_WORTH_RESULT: '&e&l岛屿 | &7你的岛屿价值为 {0} [等级 {1}]' ISLAND_WORTH_TIME_OUT: '&c&l错误 | &7计算超时. 稍后再试...' JOIN_ADMIN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 加入了你的岛屿.' JOIN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 加入了你的岛屿.' JOIN_FULL_ISLAND: '&c&l错误 | &7该岛屿成员数量已达上限.' JOIN_WHILE_IN_ISLAND: '&c&l错误 | &7你已经处于一个岛屿中了.' JOINED_ISLAND: '&e&l岛屿 | &7你加入了 {0} 的岛屿.' JOINED_ISLAND_NAME: '&e&l岛屿 | &7你加入了岛屿 {0}.' JOINED_ISLAND_AS_COOP: '&e&l岛屿 | &7你现在是玩家 {0} 的岛屿合作成员.' JOINED_ISLAND_AS_COOP_NAME: '&e&l岛屿 | &7你现在是岛屿 {0} 的合作成员.' KICK_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 被玩家 {1} 从岛屿中踢出.' KICK_ISLAND_LEADER: '&c&l错误 | &7你不能踢出岛屿的领袖, 若要如此请输入命令 /is admin disband instead.' KICK_PLAYERS_WITH_LOWER_ROLE: '&c&l错误 | &7你只能踢出角色职位低于你的玩家.' LACK_CHANGE_PERMISSION: '&c&l错误 | &7你必须拥有更改其他成员职位的权限.' LAST_ROLE_DEMOTE: '&c&l错误 | &7你不能再对该玩家降职了.' LAST_ROLE_PROMOTE: '&c&l错误 | &7你不能再对该玩家升职了.' LEAVE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 离开了岛屿.' LEAVE_ISLAND_AS_LEADER: |- &c&l错误 | &7你不能离开你拥有的岛屿. &c&l错误 | &7你可以使用命令 /is transfer 转移岛屿拥有权. LEFT_ISLAND: '&e&l岛屿 | &7你离开了你的岛屿.' LEFT_ISLAND_COOP: '&e&l岛屿 | &7你不再是玩家 {0} 的岛屿合作成员.' LEFT_ISLAND_COOP_NAME: '&e&l岛屿 | &7你不再是岛屿 {0} 的合作成员.' LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&l世界 | &7世界 {0} 已对所有岛屿锁定!' LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&l世界 | &7世界 {0} 已对岛屿 {1} 锁定!' LOCK_WORLD_ANNOUNCEMENT: '&e&l世界 | &7世界 {0} 已对玩家 {1} 的岛屿锁定!' MATERIAL_NOT_SOLID: '&c&l错误 | &7你必须提供一个固体方块材料名.' MAXIMUM_LEVEL: '&c&l错误 | &7该功能的最大等级为 {0}.' MESSAGE_SENT: '&e&l岛屿 | &7成功将消息发送给了 {0}!' MISSION_CANNOT_COMPLETE: '&c&l错误 | &7你现在还不能完成该任务.' MISSION_NO_AUTO_REWARD: '&e&l任务 | &7你已拥有了完成任务 {0} 的所有条件 - 使用 /is missions 完成任务并领取奖励!' MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&l错误 | &7你必须在完成该任务之前完成任务 {0}.' MISSION_STATUS_COMPLETE: '&e&l任务 | &7成功修改了玩家 {1} 的任务 {0} 状态为完成.' MISSION_STATUS_COMPLETE_ALL: '&e&l任务 | &7成功修改了玩家 {0} 的所有任务状态为完成.' MISSION_STATUS_RESET: '&e&l任务 | &7成功将玩家 {1} 的任务 {0} 状态重置.' MISSION_STATUS_RESET_ALL: '&e&l任务 | &7成功将玩家 {0} 的所有任务状态重置.' MODULE_ALREADY_INITIALIZED: '&e&l模块 | &7该模块已载入.' MODULE_INFO: | &e&l模块 | &7{0} 作者 {1} &e&l模块 | &7&m-------------------- &e&l模块 | &7{2} MODULE_LOADED_SUCCESS: '&e&l模块 | &7成功载入了模块 {0}.' MODULE_LOADED_FAILURE: '&e&l模块 | &7无法载入模块 {0}. 检查控制台以获得更多信息.' MODULE_UNLOADED_SUCCESS: '&e&l模块 | &7成功卸载了模块.' MODULES_LIST: '&f模块 ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将岛屿名称修改为了 {1}&7.' NAME_ANNOUNCEMENT_OTHER: '&e&l岛屿 | &7{0} 将玩家 {1} 的岛屿名称修改为了 {2}&7.' NAME_ANNOUNCEMENT_OTHER_NAME: '&e&l岛屿 | &7{0} 将岛屿 {1}&7 的名称修改为了 {2}&7.' NAME_BLACKLISTED: '&c&l错误 | &7你不能使用该名称.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&l错误 | &7你不能将玩家名称作为岛屿名称.' NAME_TOO_LONG: '&c&l错误 | &7岛屿名称不能超过 {0} 个字符.' NAME_TOO_SHORT: '&c&l错误 | &7岛屿名称不能短于 {0} 个字符.' NO_BAN_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可封禁玩家.' NO_CLOSE_BYPASS: '&c&l错误 | &7该岛屿不对公众开放.' NO_CLOSE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将岛屿对公众开放.' NO_COMMAND_PERMISSION: '&c&l错误 | &7你没有权限使用该命令. ({0})' NO_COOP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将玩家添加为合作成员.' NO_DELETE_WARP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可删除传送点.' NO_DEMOTE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可降职玩家.' NO_DEPOSIT_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可向岛屿银行存款.' NO_DISBAND_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可解散你的岛屿.' NO_EXPEL_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可从岛屿中开除玩家.' NO_INVITE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可邀请玩家.' NO_ISLAND_CHEST_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可打开岛屿仓库.' NO_ISLAND_INVITE: '&c&l错误 | &7找不到任何该岛屿的请求.' NO_ISLANDS_TO_PURGE: '&c&l错误 | &7没有可清除的岛屿.' NO_KICK_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可踢出玩家.' NO_MORE_DISBANDS: '&c&l错误 | &7你不能再解散更多岛屿了.' NO_MORE_WARPS: '&c&l错误 | &7你的岛屿不能拥有更多传送点了.' NO_NAME_PERMISSION: '&c&l错误 | &7你不能修改岛屿的名称.' NO_OPEN_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将岛屿对公众开放.' NO_PERMISSION_CHECK_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可获取权限的有关信息.' NO_PROMOTE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可升职玩家.' NO_RANKUP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可提升功能等级.' NO_RATINGS_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可浏览评分.' NO_SET_BIOME_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可修改岛屿生物群系.' NO_SET_DISCORD_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可修改岛屿的 Discord.' NO_SET_HOME_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可设置岛屿的传送位置.' NO_SET_PAYPAL_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可修改岛屿的 Paypal 邮箱.' NO_SET_ROLE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可设置玩家的角色.' NO_SET_SETTINGS_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可修改岛屿设置.' NO_SET_WARP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可设置岛屿传送点.' NO_TRANSFER_PERMISSION: '&c&l错误 | &7你必须为岛屿的领袖才可转移拥有权.' NO_UNCOOP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将玩家的合作成员身份去除.' NO_UPGRADE_PERMISSION: '&c&l错误 | &7你缺少升级该功能的权限.' NO_WITHDRAW_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可从岛屿银行中取出存款.' NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&l错误 | &7你没有足够的钱将 ${0} 存入岛屿银行.' NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&l错误 | &7你没有足够的钱.' NOT_ENOUGH_MONEY_TO_WARP: '&c&l错误 | &7你没有足够的钱使用岛屿传送点.' OPEN_MENU_WHILE_SLEEPING: '&7&o你太累了, 不能和菜单交易, 你不这么觉得嘛?' PANEL_TOGGLE_OFF: |- &e&lPanel | &7岛屿控制面板已 &c关闭&7. &e&lPanel | &7输入命令 /is 将会把你传送回岛屿. PANEL_TOGGLE_ON: |- &e&lPanel | &7岛屿控制面板已 &a开启&7. &e&lPanel | &7输入命令 /is 将会打开岛屿控制面板. PERMISSION_CHANGED: '&e&l岛屿 | &7成功更新了玩家 {1} 的岛屿的权限 {0}.' PERMISSION_CHANGED_NAME: '&e&l岛屿 | &7成功更新了岛屿 {1} 的权限 {0}.' PERMISSION_CHANGED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的权限 {0}.' PERSISTENT_DATA_EMPTY: '&c&l错误 | &7请求中未找到你所需要的数据.' PERSISTENT_DATA_MODIFY: '&e&l数据 | &7成功将 {0} 的数据 {1} 值设置为了: {2}' PERSISTENT_DATA_SHOW: '&e&l数据 | &7{0} 的数据值: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&l数据 | &7成功删除了路径 {1} 下的数据 {0}.' PERMISSIONS_RESET: '&e&l岛屿 | &7成功将玩家 {0} 的岛屿所有权限重置为默认值!' PERMISSIONS_RESET_ALL: '&e&l岛屿 | &7成功将所有岛屿的所有权限重置为默认值!' PERMISSIONS_RESET_NAME: '&e&l岛屿 | &7成功将岛屿 {0} 的所有权限重置为默认值!' PERMISSIONS_RESET_PLAYER: '&e&l岛屿 | &7成功将玩家 {0} 的权限重置回默认状态!' PERMISSIONS_RESET_ROLES: '&e&l岛屿 | &7成功将该岛屿上的所有权限重置为默认状态!' PLACEHOLDER_NO: '否' PLACEHOLDER_YES: '是' PLAYER_ALREADY_BANNED: '&c&l错误 | &7该玩家已被封禁.' PLAYER_ALREADY_COOP: '&c&l错误 | &7该玩家已为合作成员.' PLAYER_ALREADY_IN_ISLAND: '&c&l错误 | &7该玩家已经属于一个岛屿.' PLAYER_ALREADY_IN_ROLE: '&c&l错误 | &7{0} 的职位已为 {1}.' PLAYER_EXPEL_BYPASS: '&c&l错误 | &7该玩家不能从岛上被开除.' PLAYER_JOIN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 加入了服务器.' PLAYER_NOT_BANNED: '&c&l错误 | &7该玩家尚未被封禁.' PLAYER_NOT_COOP: '&c&l错误 | &7该玩家不是合作成员.' PLAYER_NOT_INSIDE_ISLAND: '&c&l错误 | &7该玩家不在你的岛屿内.' PLAYER_NOT_ONLINE: '&c&l错误 | &7该玩家不在线!' PLAYER_QUIT_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 离开了服务器.' PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&l错误 | &7你只能升职职位低于你的玩家.' PROMOTED_MEMBER: '&e&l岛屿 | &7你将玩家 {0} 的职位提升到了 {1}.' PURGE_CLEAR: '&e&l岛屿 | &7成功清除了位于队列中的所有岛屿.' PURGED_ISLANDS: |- &e&l岛屿 | &7{0} 在服务器重启后将会被删除. &e&l岛屿 | &7可使用命令 /is admin purge cancel 取消清理过程. RANKUP_SUCCESS: '&e&l岛屿 | &7成功更新了玩家 {1} 的岛屿功能 {0} 等级.' RANKUP_SUCCESS_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的功能 {0} 等级.' RANKUP_SUCCESS_NAME: '&e&l岛屿 | &7成功更新了岛屿 {1} 的功能 {0} 等级.' RATE_ALREADY_GIVEN: '&c&l错误 | &7你已经为该岛屿评过分了.' RATE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 为你的岛屿评分 {1}, 满分为 5!.' RATE_CHANGE_OTHER: '&e&l岛屿 | &7你将 {0} 的评分修改为了 {1}.' RATE_OWN_ISLAND: '&c&l错误 | &7你不能对着自己的岛屿评分.' RATE_REMOVE_ALL: '&e&l岛屿 | &7成功了删除了岛屿 {0} 的所有评价.' RATE_REMOVE_ALL_ISLANDS: '&e&l岛屿 | &7成功删除了所有岛屿的所有评价.' REACHED_ENTITY_LIMIT: '&e&l升级 | &7你已到达了最多 {0} 个的实体限制.' RATE_SUCCESS: '&e&l岛屿 | &7你对该岛屿给出了 {0} 星的评价!' REACHED_BLOCK_LIMIT: '&e&l升级 | &7你已经到达了岛屿 {0} 的放置数量限制.' RECALC_ALREADY_RUNNING: '&c&l错误 | &7你的岛屿正在重新计算.' RECALC_ALREADY_RUNNING_OTHER: '&c&l错误 | &7该岛屿正在重新计算.' RECALC_ALL_ISLANDS: '&e&l岛屿 | &7正在对所有岛屿进行重新计算...' RECALC_ALL_ISLANDS_DONE: '&e&l岛屿 | &7成功完成了对所有岛屿的重新计算.' RECALC_PROCCESS_REQUEST: '&e&l岛屿 | &7正在处理你的请求...' RELOAD_COMPLETED: '&e&l岛屿 | &7重载完毕!' RELOAD_PROCCESS_REQUEST: '&e&l岛屿 | &7正在准备重载...' REVOKE_INVITE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 撤回了对玩家 {1} 的邀请.' RESET_WORLD_SUCCEED: '&e&l岛屿 | &7成功重置了玩家 {1} 的岛屿世界 {0}.' RESET_WORLD_SUCCEED_ALL: '&e&l岛屿 | &7成功为所有岛屿重置了世界 {0}.' RESET_WORLD_SUCCEED_NAME: '&e&l岛屿 | &7成功为岛屿 {1} 重置了世界 {0}.' RESET_SETTINGS: '&e&l岛屿 | &7成功重置了玩家 {0} 的岛屿设置.' RESET_SETTINGS_ALL: '&e&l岛屿 | &7成功重置了所有岛屿的设置.' RESET_SETTINGS_NAME: '&e&l岛屿 | &7成功重置了岛屿 {0} 的设置.' SAME_NAME_CHANGE: '&c&l错误 | &7你必须输入一个不与当前岛屿名称重复的名称.' SCHEMATIC_LEFT_SELECT: '&e&l结构 | &7已选中 #2 位点 ({0})' SCHEMATIC_NOT_ADDED: '&c&l错误 | &7服务器尚未添加 {0} 的结构文件. 请联系管理员解决此问题. {0} 结构文件的格式为 "{1}".' SCHEMATIC_NOT_READY: '&c&l错误 | &7你尚未选中两点.' SCHEMATIC_PROCCESS_REQUEST: '&e&l结构 | &7正在处理你的请求...' SCHEMATIC_READY_TO_CREATE: | &e&l结构 | &7你已选择两个点. 输入命令 /is admin schematic <名称> 可创建一个新的结构. &e&l结构 | &7确保你输入命令时站在了你所需设置的传送点. SCHEMATIC_RIGHT_SELECT: '&e&l结构 | &7已选中 #1 位点 ({0})' SCHEMATIC_SAVED: '&e&l结构 | &7结构文件成功保存!' SELF_ROLE_CHANGE: '&c&l错误 | &7你不能修改自己的职位.' SET_UPGRADE_LEVEL: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿等级 {0}.' SET_UPGRADE_LEVEL_ALL: '&e&l升级 | &7成功更新了所有岛屿的等级 {0}.' SET_UPGRADE_LEVEL_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的等级 {0}.' SET_WARP: '&e&l岛屿 | &7成功在 {0} 处设置了传送点.' SET_WARP_OUTSIDE: '&c&l错误 | &7你不能在岛屿外设置传送点.' SETTINGS_RESET: '&e&l岛屿 | &7成功将玩家 {0} 的岛屿的所有设置重置为默认值!' SETTINGS_RESET_ALL: '&e&l岛屿 | &7成功将所有岛屿的所有设置重置为默认值!' SETTINGS_RESET_NAME: '&e&l岛屿 | &7成功将岛屿 {0} 的所有设置重置为默认值!' SETTINGS_RESET_SELF: '&e&l岛屿 | &7成功将该岛屿的所有设置重置为默认值!' SETTINGS_UPDATED: '&e&l岛屿 | &7成功修改了玩家 {1} 的岛屿设置 {0}.' SETTINGS_UPDATED_NAME: '&e&l岛屿 | &7成功修改了岛屿 {1} 的设置 {0}.' SETTINGS_UPDATED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的 {0} 设置.' SIZE_BIGGER_MAX: '&c&l错误 | &7你不能将大小设置为超出岛屿最大大小的数值.' SPAWN_PROTECTED: '&c&l错误 | &7出生点受到保护.' SPAWN_PROTECTED_OPPED: '&7&o你可通过输入命令 "/is admin bypass" 来绕过该限制.' SPAWN_TELEPORT_SUCCESS: '&e&l主城 | &7成功将玩家 {0} 传送至主城.' SPAWN_SET_SUCCESS: '&e&l主城 | &7成功将出生点位置设置为了 {0}.' SPY_TEAM_CHAT_FORMAT: '&7[窃听] &e[{0}] {1}&f: &7{2}' SYNC_UPGRADES: '&e&l升级 | &7成功同步了玩家 {0} 岛屿上所有功能的升级数值.' SYNC_UPGRADES_ALL: '&e&l升级 | &7成功同步了岛屿上所有功能的升级数值.' SYNC_UPGRADES_NAME: '&e&l升级 | &7成功同步了功能 {0} 的所有数值.' TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&l错误 | &7你未处于你的岛屿中.' TELEPORT_OUTSIDE_ISLAND: '&c&l错误 | &7你不能在保护区域外进行传送.' TELEPORT_WARMUP: '&7&o你将会在 {0} 秒内传送... 请勿移动!' TELEPORT_WARMUP_CANCEL: '&7&o待处理的传送请求已取消.' TITLE_SENT: '&e&l岛屿 | &7成功向玩家 {0} 发送了标题信息!' TELEPORTED_FAILED: '&e&l岛屿 | &7该岛屿似乎不存在安全的落脚点. 请联系管理员.' TELEPORTED_SUCCESS: '&e&l岛屿 | &7你已被传送至你的岛屿.' TELEPORTED_TO_WARP: '&e&l岛屿 | &7成功传送至了该传送点.' TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&l岛屿 | &7玩家 {0} 传送至了岛屿传送点 {1}.' TOGGLED_BYPASS_OFF: '&e&l绕过 | &7绕过模式已 &c关闭&7.' TOGGLED_BYPASS_ON: '&e&l绕过 | &7绕过模式已 &a开启&7.' TOGGLED_FLY_OFF: '&e&l飞行 | &7岛屿飞行已 &c关闭&7.' TOGGLED_FLY_ON: '&e&l飞行 | &7岛屿飞行已 &a开启&7.' TOGGLED_FLY_OFF_OTHER: '&e&l飞行 | &7已为 {0} &c关闭&7岛屿飞行.' TOGGLED_FLY_ON_OTHER: '&e&l飞行 | &7已为 {0} &a开启&7岛屿飞行.' TOGGLED_SCHEMATIC_OFF: '&e&l结构 | &7结构模式已 &c关闭&7.' TOGGLED_SCHEMATIC_ON: |- &e&l结构 | &7结构模式已 &a开启&7. &e&l结构 | &7使用金斧圈定选区. TOGGLED_SPY_OFF: '&e&l窃听 | &7聊天窃听已 &c关闭&7.' TOGGLED_SPY_ON: '&e&l窃听 | &7聊天窃听已 &a开启&7.' TOGGLED_STACKED_BLOCKS_OFF: '&e&l堆叠 | &7方块堆叠已 &c关闭&7.' TOGGLED_STACKED_BLOCKS_ON: '&e&l堆叠 | &7方块堆叠已 &a开启&7.' TOGGLED_TEAM_CHAT_OFF: '&e&l聊天 | &7团队聊天已 &c关闭&7.' TOGGLED_TEAM_CHAT_ON: '&e&l聊天 | &7团队聊天已 &a开启&7.' TOGGLED_WORLD_BORDER_OFF: '&e&l边界 | &7世界边界已 &c关闭&7.' TOGGLED_WORLD_BORDER_ON: '&e&l边界 | &7世界边界已 &a开启&7.' TRANSFER_ADMIN: '&e&l岛屿 | &7你将岛屿 {0} 的拥有权转移给了玩家 {1}.' TRANSFER_ADMIN_ALREADY_LEADER: '&c&l错误 | &7{0} 已经是该岛屿的领袖了.' TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&l错误 | &7这些玩家不在同一岛屿中.' TRANSFER_ADMIN_NOT_LEADER: '&c&l错误 | &7这些玩家不是任何岛屿的领袖.' TRANSFER_ALREADY_LEADER: '&c&l错误 | &7你已经是该岛屿的领袖了.' TRANSFER_BROADCAST: '&e&l岛屿 | &7该岛屿的拥有权已转移给了玩家 {0}.' UNBAN_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 已被玩家 {1} 从该岛屿解除封禁.' UNCOOP_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 解除了玩家 {1} 的合作成员关系.' UNCOOP_AUTO_ANNOUNCEMENT: '&e&l岛屿 | &7没有岛屿成员在线, 你已被自动解除合作关系.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 离开了游戏, 自动取消其成员关系.' UNIGNORED_ISLAND: '&e&l岛屿 | &7{0} 的岛屿现在已重新参与岛屿排行榜计算.' UNIGNORED_ISLAND_NAME: '&e&l岛屿 | &7岛屿 {0} 现在已重新参与岛屿排行榜计算.' UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&l世界 | &7世界 {0} 已对所有岛屿解锁!' UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&l世界 | &7世界 {0} 已对岛屿 {1} 解锁!' UNLOCK_WORLD_ANNOUNCEMENT: '&e&l世界 | &7世界 {0} 已对玩家 {1} 的岛屿解锁!' UNSAFE_WARP: '&e&l岛屿 | &7&o看起来该传送点不安全. 请尝试使用其他传送点.' UPDATED_PERMISSION: '&e&l岛屿 | &7更新了 {0} 的权限.' UPDATED_SETTINGS: '&e&l岛屿 | &7更新了岛屿设置 {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&l错误 | &7你只能在 {0} 之后才可继续进行升级操作.' VAULT_NOT_INSTALLED: '&c&l错误 | &7服务器未安装 Vault 插件, 交易功能已禁用.' VISITOR_BLOCK_COMMAND: '&c&l错误 | &7你不能对其他岛屿使用该命令.' WARP_ALREADY_EXIST: '&c&l错误 | &7已存在同名传送点.' WARP_CATEGORY_ICON_NEW_LORE: | &e&l传送 | &7输入一行新的描述 (输入 "-cancel" 取消本次操作): &e&l传送 | &7可使用符号 "\n" 进行换行. WARP_CATEGORY_ICON_NEW_NAME: '&e&l传送 | &7输入新的分类图标名称 (输入 "-cancel" 取消本次操作):' WARP_CATEGORY_ICON_NEW_TYPE: '&e&l传送 | &7输入新的材料名称 (输入 "-cancel" 取消本次操作):' WARP_CATEGORY_ICON_UPDATED: '&e&l传送 | &7成功更新了分类图标的样式.' WARP_CATEGORY_ILLEGAL_NAME: '&c&l错误 | &7传送点分类名称不能为空.' WARP_CATEGORY_NAME_TOO_LONG: '&c&l错误 | &7传送点分类名称长度不能大于 255 个字符.' WARP_CATEGORY_SLOT: '&e&l传送 | &7输入一个新的格子位置 (输入 "-cancel" 取消本次操作):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&l错误 | &7该槽位已有其他分类图标占用.' WARP_CATEGORY_SLOT_SUCCESS: '&e&l传送 | &7成功将该分类的位置转移至 {0}.' WARP_CATEGORY_RENAME: '&e&l传送 | &7输入新的名称 (输入 "-cancel" 取消本次操作):' WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的分类名称.' WARP_CATEGORY_RENAME_SUCCESS: '&e&l传送 | &7成功将分类重命名为 {0}.' WARP_ICON_NEW_LORE: | &e&l传送 | &7输入一行新的描述 (输入 "-cancel" 取消本次操作): &e&l传送 | &7可使用符号 "\n" 进行换行. WARP_ICON_NEW_NAME: '&e&l传送 | &7输入新的名称 (输入 "-cancel" 取消本次操作):' WARP_ICON_NEW_TYPE: '&e&l传送 | &7输入新的材料名称 (输入 "-cancel" 取消本次操作):' WARP_ICON_UPDATED: '&e&l传送 | &7成功更新了传送点的图标样式.' WARP_ILLEGAL_NAME: '&c&l错误 | &7传送点名称不能为空.' WARP_LOCATION_UPDATE: '&e&l传送 | &7成功将传送点的位置转移至你当前的位置.' WARP_NAME_TOO_LONG: '&c&l错误 | &7传送点名称长度不能大于 255 个字符.' WARP_PUBLIC_UPDATE: '&e&l传送 | &7成功将传送点设置为对公众开放.' WARP_PRIVATE_UPDATE: '&e&l传送 | &7成功将传送点设置为不对公众开放.' WARP_RENAME: '&e&l传送 | &7输入传送点的新名称 (输入 "-cancel" 取消本次操作):' WARP_RENAME_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的其他传送点.' WARP_RENAME_SUCCESS: '&e&l传送 | &7成功将传送点重命名为 {0}.' WITHDRAW_ALL_MONEY: |- &e&l银行 | &7岛屿银行余额为 ${0}. &e&l银行 | &7&o正在取出所有钱... WITHDRAW_ANNOUNCEMENT: '&e&l银行 | &7玩家 {0} 从岛屿银行中取出了 ${1}!' WITHDRAW_ERROR: '&c&l错误 | &7{0}.' WITHDRAWN_MONEY: '&e&l银行 | &7你从玩家 {1} 的岛屿银行中取出 ${0}!' WITHDRAWN_MONEY_NAME: '&e&l银行 | &7你从岛屿 {1} 的银行中取出 ${0}!' WORLD_NOT_ENABLED: '&e&l世界 | &7世界 {0} 未在服务器上启用.' WORLD_NOT_UNLOCKED: '&e&l世界 | &7世界 {0} 尚未解锁!' ================================================ FILE: src/main/resources/menus/bank-logs.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lTransaction Logs &r{0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ ! $ - $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' time-sort: '!' money-sort: '-' items: '@': type: PAPER name: '&eTransaction #{0}' lore: - '&7Player: {1}' - '&7Status: {2}' - '&7Time: {3}' - '&7Amount: ${4}' - '' - '&7Click to filter transactions by this player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '!': type: WATCH name: '&6Sort by creation time' '-': type: EMERALD name: '&6Sort by money' sounds: '@': type: CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/bank-logs1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lTransaction Logs &r{0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ ! $ - $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' time-sort: '!' money-sort: '-' items: '@': type: PAPER name: '&eTransaction #{0}' lore: - '&7Player: {1}' - '&7Status: {2}' - '&7Time: {3}' - '&7Amount: ${4}' - '' - '&7Click to filter transactions by this player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '!': type: WATCH name: '&6Sort by creation time' '-': type: EMERALD name: '&6Sort by money' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/bank-logs1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lTransaction Logs &r{0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ ! $ - $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' time-sort: '!' money-sort: '-' items: '@': type: PAPER name: '&eTransaction #{0}' lore: - '&7Player: {1}' - '&7Status: {2}' - '&7Time: {3}' - '&7Amount: ${4}' - '' - '&7Click to filter transactions by this player.' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' '!': type: CLOCK name: '&6Sort by creation time' '-': type: EMERALD name: '&6Sort by money' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/banned-players.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Banned Players ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&7Click to unban the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/banned-players1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Banned Players ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&7Click to unban the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/banned-players1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Banned Players ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: PLAYER_HEAD name: '&e{0}' lore: - '&7Click to unban the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/biomes.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lSelect a biome' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '# ! # % # & # ~ #' - '# # @ # ^ # * # #' - '$ $ $ $ $ $ $ $ $' # Should the current biome be glowing? current-biome-glow: false items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '!': biome: PLAINS access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&ePlains Biome &a(Available)' lore: - '&7Change your island biome to plains.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&ePlains Biome &c(Unavailable)' lore: - '&7Change your island biome to plains.' '@': biome: JUNGLE access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=' name: '&eJungle Biome &a(Available)' lore: - '&7Change your island biome to jungle.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=' name: '&eJungle Biome &c(Unavailable)' lore: - '&7Change your island biome to jungle.' '%': biome: TAIGA access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ==' name: '&eTaiga Biome &a(Available)' lore: - '&7Change your island biome to taiga.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ==' name: '&eTaiga Biome &c(Unavailable)' lore: - '&7Change your island biome to taiga.' '^': biome: DESERT access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0=' name: '&eDesert Biome &a(Available)' lore: - '&7Change your island biome to desert.' - '&cWarning ice and snow must go!' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0=' name: '&eDesert Biome &c(Unavailable)' lore: - '&7Change your island biome to desert.' - '&cWarning ice and snow must go!' '&': biome: HELL access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19' name: '&eNether Biome &a(Available)' lore: - '&7Change your island biome to nether.' - '&cWarning ice, snow and water must go!' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19' name: '&eNether Biome &c(Unavailable)' lore: - '&7Change your island biome to nether.' - '&cWarning ice snow, and water must go!' '*': biome: SWAMPLAND access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0=' name: '&eSwamp Biome &a(Available)' lore: - '&7Change your island biome to swamp.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0=' name: '&eSwamp Biome &c(Unavailable)' lore: - '&7Change your island biome to swamp.' '~': biome: MESA access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19' name: '&eMesa Biome &a(Available)' lore: - '&7Change your island biome to Mesa.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19' name: '&eMesa Biome &c(Unavailable)' lore: - '&7Change your island biome to Mesa.' sounds: '!': access: type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '@': access: type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '%': access: type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '^': access: type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '&': access: type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '*': access: type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '~': access: type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/biomes1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lSelect a biome' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '# ! # % # & # ~ #' - '# # @ # ^ # * # #' - '$ $ $ $ $ $ $ $ $' # Should the current biome be glowing? current-biome-glow: false items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '!': biome: PLAINS access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&ePlains Biome &a(Available)' lore: - '&7Change your island biome to plains.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&ePlains Biome &c(Unavailable)' lore: - '&7Change your island biome to plains.' '@': biome: JUNGLE access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=' name: '&eJungle Biome &a(Available)' lore: - '&7Change your island biome to jungle.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=' name: '&eJungle Biome &c(Unavailable)' lore: - '&7Change your island biome to jungle.' '%': biome: TAIGA access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ==' name: '&eTaiga Biome &a(Available)' lore: - '&7Change your island biome to taiga.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ==' name: '&eTaiga Biome &c(Unavailable)' lore: - '&7Change your island biome to taiga.' '^': biome: DESERT access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0=' name: '&eDesert Biome &a(Available)' lore: - '&7Change your island biome to desert.' - '&cWarning ice and snow must go!' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0=' name: '&eDesert Biome &c(Unavailable)' lore: - '&7Change your island biome to desert.' - '&cWarning ice and snow must go!' '&': biome: HELL access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19' name: '&eNether Biome &a(Available)' lore: - '&7Change your island biome to nether.' - '&cWarning ice, snow and water must go!' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19' name: '&eNether Biome &c(Unavailable)' lore: - '&7Change your island biome to nether.' - '&cWarning ice snow, and water must go!' '*': biome: SWAMPLAND access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0=' name: '&eSwamp Biome &a(Available)' lore: - '&7Change your island biome to swamp.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0=' name: '&eSwamp Biome &c(Unavailable)' lore: - '&7Change your island biome to swamp.' '~': biome: MESA access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19' name: '&eMesa Biome &a(Available)' lore: - '&7Change your island biome to Mesa.' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19' name: '&eMesa Biome &c(Unavailable)' lore: - '&7Change your island biome to Mesa.' sounds: '!': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '@': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '%': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '^': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '&': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '*': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '~': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/biomes1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lSelect a biome' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '# ! # % # & # ~ #' - '# # @ # ^ # * # #' - '$ $ $ $ $ $ $ $ $' # Should the current biome be glowing? current-biome-glow: false items: '$': type: BLACK_STAINED_GLASS_PANE name: '&f' '!': biome: PLAINS access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&ePlains Biome &a(Available)' lore: - '&7Change your island biome to plains.' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&ePlains Biome &c(Unavailable)' lore: - '&7Change your island biome to plains.' '@': biome: JUNGLE access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=' name: '&eJungle Biome &a(Available)' lore: - '&7Change your island biome to jungle.' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=' name: '&eJungle Biome &c(Unavailable)' lore: - '&7Change your island biome to jungle.' '%': biome: TAIGA access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ==' name: '&eTaiga Biome &a(Available)' lore: - '&7Change your island biome to taiga.' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ==' name: '&eTaiga Biome &c(Unavailable)' lore: - '&7Change your island biome to taiga.' '^': biome: DESERT access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0=' name: '&eDesert Biome &a(Available)' lore: - '&7Change your island biome to desert.' - '&cWarning ice and snow must go!' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0=' name: '&eDesert Biome &c(Unavailable)' lore: - '&7Change your island biome to desert.' - '&cWarning ice and snow must go!' '&': biome: NETHER_WASTES access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19' name: '&eNether Biome &a(Available)' lore: - '&7Change your island biome to nether.' - '&cWarning ice, snow and water must go!' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19' name: '&eNether Biome &c(Unavailable)' lore: - '&7Change your island biome to nether.' - '&cWarning ice snow, and water must go!' '*': biome: SWAMP access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0=' name: '&eSwamp Biome &a(Available)' lore: - '&7Change your island biome to swamp.' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0=' name: '&eSwamp Biome &c(Unavailable)' lore: - '&7Change your island biome to swamp.' '~': biome: BADLANDS access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19' name: '&eBadlands Biome &a(Available)' lore: - '&7Change your island biome to Badlands.' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19' name: '&eBadlands Biome &c(Unavailable)' lore: - '&7Change your island biome to Badlands.' sounds: '!': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '@': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '%': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '^': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '&': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '*': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '~': access: type: ENTITY_ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/border-color.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Border Color' previous-menu: true type: HOPPER pattern: - '~ # @ ^ $' green-color: '@' red-color: '^' blue-color: '$' items: '~': enable-border: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=' name: '&aEnable Border' disable-border: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=' name: '&cDisable Border' '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aGreen Color' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&cRed Color' '$': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0=' name: '&bBlue Color' sounds: '~': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '$': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/border-color1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Border Color' previous-menu: true type: HOPPER pattern: - '~ # @ ^ $' green-color: '@' red-color: '^' blue-color: '$' items: '~': enable-border: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=' name: '&aEnable Border' disable-border: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=' name: '&cDisable Border' '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aGreen Color' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&cRed Color' '$': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0=' name: '&bBlue Color' sounds: '~': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '$': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/border-color1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Border Color' previous-menu: true type: HOPPER pattern: - '~ # @ ^ $' green-color: '@' red-color: '^' blue-color: '$' items: '~': enable-border: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=' name: '&aEnable Border' disable-border: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=' name: '&cDisable Border' '#': type: BLACK_STAINED_GLASS_PANE name: '&f' '@': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aGreen Color' '^': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&cRed Color' '$': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0=' name: '&bBlue Color' sounds: '~': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '$': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-ban.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Ban' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to ban that player?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-ban1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Ban' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to ban that player?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-ban1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Ban' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: BLACK_STAINED_GLASS_PANE name: '&f' '@': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to ban that player?' '^': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-disband.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Disband' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to delete your island?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-disband1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Disband' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to delete your island?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-disband1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Disband' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: BLACK_STAINED_GLASS_PANE name: '&f' '@': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to delete your island?' '^': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-kick.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Kick' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to kick that player?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-kick1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Kick' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to kick that player?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-kick1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Kick' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: BLACK_STAINED_GLASS_PANE name: '&f' '@': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to kick that player?' '^': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-leave.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Leave' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to leave your island?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-leave1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Leave' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to leave your island?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-leave1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Leave' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: BLACK_STAINED_GLASS_PANE name: '&f' '@': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to leave your island?' '^': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-transfer.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Transfer' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to transfer your island?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-transfer1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Transfer' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to transfer your island?' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/confirm-transfer1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l Confirm Transfer' previous-menu: true type: HOPPER pattern: - '# @ # ^ #' confirm: '@' cancel: '^' items: '#': type: BLACK_STAINED_GLASS_PANE name: '&f' '@': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' name: '&aConfirm' lore: - '&7Are you sure you want to transfer your island?' '^': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' name: '&4Cancel' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/control-panel.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Panel' previous-menu: true pattern: - '2 2 2 2 2 2 2 2 2' - '# ! # @ # $ # % #' - '_ # ^ # & # * # 1' - '# ~ # = # - # + #' - '2 2 2 2 2 2 2 2 2' members: '+' settings: '@' visitors: '-' items: '!': type: SIGN name: '&eTeleport' lore: - '&7Teleport back to your island.' '@': type: DIODE name: '&eIsland Settings' lore: - '&7Manage settings regarding your island.' '$': type: ENDER_PEARL name: '&eIsland Permissions' lore: - '&7Manage permissions in your island.' '%': type: GRASS name: '&eIsland Biomes' lore: - '&7Change the biome of your island.' '_': type: EMERALD name: '&eIsland Bank' lore: - '&7Open the bank of your island.' '^': type: GOLD_INGOT name: '&eIsland Upgrades' lore: - '&7Upgrade your island statistics!' '&': type: BEACON name: '&eTop Islands' lore: - '&7Check which island is the best on the server!' '*': type: PAPER name: '&eIsland Missions' lore: - '&7Complete missions and get rewarded!' '1': type: SMOOTH_BRICK name: '&eIsland Counts' lore: - '&7See all the blocks on your island!' '~': type: BARRIER name: '&eIsland Disband' lore: - '&7Disband your island.' - '&cThis action cannot be restored!' '=': type: CHEST name: '&eIsland Chest' lore: - '&7Open the community chest of the island.' '-': type: SKULL_ITEM name: '&eIsland Visitors' lore: - '&7Check all the visitors of the island.' '+': type: SKULL_ITEM data: 3 name: '&eIsland Members' lore: - '&7Manage the members of the island.' '2': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '!': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '$': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '_': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '1': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '~': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '-': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '=': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '+': type: ORB_PICKUP volume: 0.2 pitch: 0.2 commands: '!': - '[player] is tp' '$': - '[player] is permissions' '%': - '[player] is biome' '_': - '[player] is bank' '^': - '[player] is upgrade' '&': - '[player] is top' '*': - '[player] is missions' '1': - '[player] is counts' '~': - '[player] is disband' '=': - '[player] is chest' ================================================ FILE: src/main/resources/menus/control-panel1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Panel' previous-menu: true pattern: - '2 2 2 2 2 2 2 2 2' - '# ! # @ # $ # % #' - '_ # ^ # & # * # 1' - '# ~ # = # - # + #' - '2 2 2 2 2 2 2 2 2' members: '+' settings: '@' visitors: '-' items: '!': type: SIGN name: '&eTeleport' lore: - '&7Teleport back to your island.' '@': type: DIODE name: '&eIsland Settings' lore: - '&7Manage settings regarding your island.' '$': type: ENDER_PEARL name: '&eIsland Permissions' lore: - '&7Manage permissions in your island.' '%': type: GRASS name: '&eIsland Biomes' lore: - '&7Change the biome of your island.' '_': type: EMERALD name: '&eIsland Bank' lore: - '&7Open the bank of your island.' '^': type: GOLD_INGOT name: '&eIsland Upgrades' lore: - '&7Upgrade your island statistics!' '&': type: BEACON name: '&eTop Islands' lore: - '&7Check which island is the best on the server!' '*': type: PAPER name: '&eIsland Missions' lore: - '&7Complete missions and get rewarded!' '1': type: SMOOTH_BRICK name: '&eIsland Counts' lore: - '&7See all the blocks on your island!' '~': type: BARRIER name: '&eIsland Disband' lore: - '&7Disband your island.' - '&cThis action cannot be restored!' '=': type: CHEST name: '&eIsland Chest' lore: - '&7Open the community chest of the island.' '-': type: SKULL_ITEM name: '&eIsland Visitors' lore: - '&7Check all the visitors of the island.' '+': type: SKULL_ITEM data: 3 name: '&eIsland Members' lore: - '&7Manage the members of the island.' '2': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '!': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '$': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '_': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '1': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '~': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '-': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '=': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '+': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 commands: '!': - '[player] is tp' '$': - '[player] is permissions' '%': - '[player] is biome' '_': - '[player] is bank' '^': - '[player] is upgrade' '&': - '[player] is top' '*': - '[player] is missions' '1': - '[player] is counts' '~': - '[player] is disband' '=': - '[player] is chest' ================================================ FILE: src/main/resources/menus/control-panel1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Panel' previous-menu: true pattern: - '2 2 2 2 2 2 2 2 2' - '# ! # @ # $ # % #' - '_ # ^ # & # * # 1' - '# ~ # = # - # + #' - '2 2 2 2 2 2 2 2 2' members: '+' settings: '@' visitors: '-' items: '!': type: OAK_SIGN name: '&eTeleport' lore: - '&7Teleport back to your island.' '@': type: REPEATER name: '&eIsland Settings' lore: - '&7Manage settings regarding your island.' '$': type: ENDER_PEARL name: '&eIsland Permissions' lore: - '&7Manage permissions in your island.' '%': type: GRASS_BLOCK name: '&eIsland Biomes' lore: - '&7Change the biome of your island.' '_': type: EMERALD name: '&eIsland Bank' lore: - '&7Open the bank of your island.' '^': type: GOLD_INGOT name: '&eIsland Upgrades' lore: - '&7Upgrade your island statistics!' '&': type: BEACON name: '&eTop Islands' lore: - '&7Check which island is the best on the server!' '*': type: PAPER name: '&eIsland Missions' lore: - '&7Complete missions and get rewarded!' '1': type: STONE_BRICKS name: '&eIsland Counts' lore: - '&7See all the blocks on your island!' '~': type: BARRIER name: '&eIsland Disband' lore: - '&7Disband your island.' - '&cThis action cannot be restored!' '=': type: CHEST name: '&eIsland Chest' lore: - '&7Open the community chest of the island.' '-': type: SKELETON_SKULL name: '&eIsland Visitors' lore: - '&7Check all the visitors of the island.' '+': type: PLAYER_HEAD name: '&eIsland Members' lore: - '&7Manage the members of the island.' '2': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '!': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '$': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '_': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '1': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '~': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '-': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '=': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '+': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 commands: '!': - '[player] is tp' '$': - '[player] is permissions' '%': - '[player] is biome' '_': - '[player] is bank' '^': - '[player] is upgrade' '&': - '[player] is top' '*': - '[player] is missions' '1': - '[player] is counts' '~': - '[player] is disband' '=': - '[player] is chest' ================================================ FILE: src/main/resources/menus/coops.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Coop Players ({0}/{1})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&7Click to uncoop the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/coops1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Coop Players ({0}/{1})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&7Click to uncoop the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/coops1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Coop Players ({0}/{1})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: PLAYER_HEAD name: '&e{0}' lore: - '&7Click to uncoop the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/counts.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Block Counts' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: STONE name: '&e{0}' lore: - '&6&l* &e&lQuantity &fx{1}' - '&6&l* &e&lWorth: &f${2}' - '&6&l* &e&lLevel: &f${3}' flags: - HIDE_ATTRIBUTES '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' ================================================ FILE: src/main/resources/menus/counts1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Block Counts' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: STONE name: '&e{0}' lore: - '&6&l* &e&lQuantity &fx{1}' - '&6&l* &e&lWorth: &f${2}' - '&6&l* &e&lLevel: &f${3}' flags: - HIDE_ATTRIBUTES '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' ================================================ FILE: src/main/resources/menus/counts1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Block Counts' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: STONE name: '&e{0}' lore: - '&6&l* &e&lQuantity &fx{1}' - '&6&l* &e&lWorth: &f${2}' - '&6&l* &e&lLevel: &f${3}' flags: - HIDE_ATTRIBUTES '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' ================================================ FILE: src/main/resources/menus/counts1_20.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Block Counts' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: STONE name: '&e{0}' lore: - '&6&l* &e&lQuantity &fx{1}' - '&6&l* &e&lWorth: &f${2}' - '&6&l* &e&lLevel: &f${3}' flags: - HIDE_ADDITIONAL_TOOLTIP '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' ================================================ FILE: src/main/resources/menus/global-warps.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Warps' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' warps: '@' previous-page: '%' current-page: '*' next-page: '^' # When enabled, instead of showing warps, the visitor warp locations will be shown. # To show the description, use the {1} placeholder. visitor-warps: false items: '@': type: SKULL_ITEM data: 3 name: '&e{0}''s Island' lore: - '&7Click to see all warps of this island.' - '&8>> &7This island has {2} warps.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/global-warps1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Warps' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' warps: '@' previous-page: '%' current-page: '*' next-page: '^' # When enabled, instead of showing warps, the visitor warp locations will be shown. # To show the description, use the {1} placeholder. visitor-warps: false items: '@': type: SKULL_ITEM data: 3 name: '&e{0}''s Island' lore: - '&7Click to see all warps of this island.' - '&8>> &7This island has {2} warps.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/global-warps1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Warps' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' warps: '@' previous-page: '%' current-page: '*' next-page: '^' # When enabled, instead of showing warps, the visitor warp locations will be shown. # To show the description, use the {1} placeholder. visitor-warps: false items: '@': type: PLAYER_HEAD name: '&e{0}''s Island' lore: - '&7Click to see all warps of this island.' - '&8>> &7This island has {2} warps.' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-bank.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Bank' previous-menu: true pattern: - '= - @ @ @ @ @ - =' - '- @ ! @ @ @ % @ -' - '@ # @ @ * @ @ ^ @' - '- @ $ @ @ @ & @ -' - '= - @ @ ~ @ @ - =' balance: '*' logs: '~' items: '!': type: STAINED_GLASS_PANE data: 5 name: '&aDeposit Half Money' lore: - '&7Deposit half of your money into the bank.' bank-action: deposit: 50.0 '#': type: STAINED_GLASS_PANE data: 5 name: '&aDeposit Money' lore: - '&7Deposit money into the bank.' bank-action: deposit: 0.0 '$': type: STAINED_GLASS_PANE data: 5 name: '&aDeposit All Money' lore: - '&7Deposit all of your money into the bank.' bank-action: deposit: 100.0 '%': type: STAINED_GLASS_PANE data: 14 name: '&aWithdraw Half Money' lore: - '&7Withdraw half of the money from the bank.' bank-action: withdraw: 50.0 '^': type: STAINED_GLASS_PANE data: 14 name: '&aWithdraw Money' lore: - '&7Withdraw money from the bank.' bank-action: withdraw: 0.0 '&': type: STAINED_GLASS_PANE data: 14 name: '&aWithdraw All Money' lore: - '&7Withdraw all of the money from the bank.' bank-action: withdraw: 100.0 '*': type: PAPER name: '&6Balance' lore: - '&7Your bank currently has ${2}' - '&7Next interest on {7}' '=': type: EMERALD_BLOCK name: '&f ' '-': type: EMERALD name: '&f ' '~': type: EXP_BOTTLE name: '&6Transaction Logs' sounds: '!': success-sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '#': success-sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '$': success-sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '%': success-sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '^': success-sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '&': success-sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '~': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-bank1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Bank' previous-menu: true pattern: - '= - @ @ @ @ @ - =' - '- @ ! @ @ @ % @ -' - '@ # @ @ * @ @ ^ @' - '- @ $ @ @ @ & @ -' - '= - @ @ ~ @ @ - =' balance: '*' logs: '~' items: '!': type: STAINED_GLASS_PANE data: 5 name: '&aDeposit Half Money' lore: - '&7Deposit half of your money into the bank.' bank-action: deposit: 50.0 '#': type: STAINED_GLASS_PANE data: 5 name: '&aDeposit Money' lore: - '&7Deposit money into the bank.' bank-action: deposit: 0.0 '$': type: STAINED_GLASS_PANE data: 5 name: '&aDeposit All Money' lore: - '&7Deposit all of your money into the bank.' bank-action: deposit: 100.0 '%': type: STAINED_GLASS_PANE data: 14 name: '&aWithdraw Half Money' lore: - '&7Withdraw half of the money from the bank.' bank-action: withdraw: 50.0 '^': type: STAINED_GLASS_PANE data: 14 name: '&aWithdraw Money' lore: - '&7Withdraw money from the bank.' bank-action: withdraw: 0.0 '&': type: STAINED_GLASS_PANE data: 14 name: '&aWithdraw All Money' lore: - '&7Withdraw all of the money from the bank.' bank-action: withdraw: 100.0 '*': type: PAPER name: '&6Balance' lore: - '&7Your bank currently has ${2}' - '&7Next interest on {7}' '=': type: EMERALD_BLOCK name: '&f ' '-': type: EMERALD name: '&f ' '~': type: EXP_BOTTLE name: '&6Transaction Logs' sounds: '!': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '#': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '$': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '%': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '^': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '&': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '~': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-bank1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Bank' previous-menu: true pattern: - '= - @ @ @ @ @ - =' - '- @ ! @ @ @ % @ -' - '@ # @ @ * @ @ ^ @' - '- @ $ @ @ @ & @ -' - '= - @ @ ~ @ @ - =' balance: '*' logs: '~' items: '!': type: LIME_STAINED_GLASS_PANE name: '&aDeposit Half Money' lore: - '&7Deposit half of your money into the bank.' bank-action: deposit: 50.0 '#': type: LIME_STAINED_GLASS_PANE name: '&aDeposit Money' lore: - '&7Deposit money into the bank.' bank-action: deposit: 0.0 '$': type: LIME_STAINED_GLASS_PANE name: '&aDeposit All Money' lore: - '&7Deposit all of your money into the bank.' bank-action: deposit: 100.0 '%': type: RED_STAINED_GLASS_PANE name: '&aWithdraw Half Money' lore: - '&7Withdraw half of the money from the bank.' bank-action: withdraw: 50.0 '^': type: RED_STAINED_GLASS_PANE name: '&aWithdraw Money' lore: - '&7Withdraw money from the bank.' bank-action: withdraw: 0.0 '&': type: RED_STAINED_GLASS_PANE name: '&aWithdraw All Money' lore: - '&7Withdraw all of the money from the bank.' bank-action: withdraw: 100.0 '*': type: PAPER name: '&6Balance' lore: - '&7Your bank currently has ${2}' - '&7Next interest on {7}' '=': type: EMERALD_BLOCK name: '&f ' '-': type: EMERALD name: '&f ' '~': type: EXPERIENCE_BOTTLE name: '&6Transaction Logs' sounds: '!': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '#': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '$': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '%': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '^': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '&': success-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '~': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-chest.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Chest' previous-menu: true pattern: - '# # # # # # # # #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': valid-page: type: STORAGE_MINECART name: '&ePage #{0}' lore: - '&eSize: &7{1}' invalid-page: type: MINECART name: '&f ' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '#': type: RAILS name: '&f ' sounds: '@': type: CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/island-chest1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Chest' previous-menu: true pattern: - '# # # # # # # # #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': valid-page: type: STORAGE_MINECART name: '&ePage #{0}' lore: - '&eSize: &7{1}' invalid-page: type: MINECART name: '&f ' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '#': type: RAILS name: '&f ' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/island-chest1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Chest' previous-menu: true pattern: - '# # # # # # # # #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# $ @ @ @ @ @ $ #' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': valid-page: type: CHEST_MINECART name: '&ePage #{0}' lore: - '&eSize: &7{1}' invalid-page: type: MINECART name: '&f ' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '#': type: RAIL name: '&f ' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/island-creation.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lCreate a new island...' previous-menu: true pattern: - '~ ~ ~ ~ ~ ~ ~ ~ ~' - '# @ # # ^ # # $ #' - '~ ~ ~ ~ ~ ~ ~ ~ ~' items: '@': schematic: 'normal' biome: PLAINS spawn-offset: '0, 0, 0' access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&eNormal Island &a(Available)' lore: - '&7Simple island with trees and a mining area!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&eNormal Island &c(Unavailable)' lore: - '&7Simple island with trees and a mining area!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '^': schematic: 'mycel' biome: MUSHROOM_ISLAND spawn-offset: '0, 0, 0' access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19' name: '&eMycelium Island &a(Available)' lore: - '&7Customized island with lots of mycelium!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19' name: '&eMycelium Island &c(Unavailable)' lore: - '&7Customized island with lots of mycelium!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '$': schematic: 'desert' biome: DESERT spawn-offset: '0, 0, 0' access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0=' name: '&eDesert Island &a(Available)' lore: - '&7Customized island with lots of sand!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0=' name: '&eDesert Island &c(Unavailable)' lore: - '&7Customized island with lots of sand!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '~': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': access: type: PORTAL_TRIGGER volume: 1 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '^': access: type: PORTAL_TRIGGER volume: 1 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '$': access: type: PORTAL_TRIGGER volume: 1 pitch: 0.2 no-access: type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-creation1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lCreate a new island...' previous-menu: true pattern: - '~ ~ ~ ~ ~ ~ ~ ~ ~' - '# @ # # ^ # # $ #' - '~ ~ ~ ~ ~ ~ ~ ~ ~' items: '@': schematic: 'normal' biome: PLAINS spawn-offset: '0, 0, 0' access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&eNormal Island &a(Available)' lore: - '&7Simple island with trees and a mining area!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&eNormal Island &c(Unavailable)' lore: - '&7Simple island with trees and a mining area!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '^': schematic: 'mycel' biome: MUSHROOM_ISLAND spawn-offset: '0, 0, 0' access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19' name: '&eMycelium Island &a(Available)' lore: - '&7Customized island with lots of mycelium!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19' name: '&eMycelium Island &c(Unavailable)' lore: - '&7Customized island with lots of mycelium!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '$': schematic: 'desert' biome: DESERT spawn-offset: '0, 0, 0' access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0=' name: '&eDesert Island &a(Available)' lore: - '&7Customized island with lots of sand!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0=' name: '&eDesert Island &c(Unavailable)' lore: - '&7Customized island with lots of sand!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '~': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': access: type: BLOCK_PORTAL_AMBIENT volume: 1 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '^': access: type: BLOCK_PORTAL_AMBIENT volume: 1 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '$': access: type: BLOCK_PORTAL_AMBIENT volume: 1 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-creation1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lCreate a new island...' previous-menu: true pattern: - '~ ~ ~ ~ ~ ~ ~ ~ ~' - '# @ # # ^ # # $ #' - '~ ~ ~ ~ ~ ~ ~ ~ ~' items: '@': schematic: 'normal' biome: PLAINS spawn-offset: '0, 0, 0' access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&eNormal Island &a(Available)' lore: - '&7Simple island with trees and a mining area!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' name: '&eNormal Island &c(Unavailable)' lore: - '&7Simple island with trees and a mining area!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '^': schematic: 'mycel' biome: MUSHROOM_FIELDS spawn-offset: '0, 0, 0' access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19' name: '&eMycelium Island &a(Available)' lore: - '&7Customized island with lots of mycelium!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19' name: '&eMycelium Island &c(Unavailable)' lore: - '&7Customized island with lots of mycelium!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '$': schematic: 'desert' biome: DESERT spawn-offset: '0, 0, 0' access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0=' name: '&eDesert Island &a(Available)' lore: - '&7Customized island with lots of sand!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' no-access: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0=' name: '&eDesert Island &c(Unavailable)' lore: - '&7Customized island with lots of sand!' - '&7 ' - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' '~': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': access: type: BLOCK_PORTAL_AMBIENT volume: 1 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '^': access: type: BLOCK_PORTAL_AMBIENT volume: 1 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '$': access: type: BLOCK_PORTAL_AMBIENT volume: 1 pitch: 0.2 no-access: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-rate.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lRate Island' previous-menu: true pattern: - '# ~ @ % # * ^ & #' zero-stars: '~' one-star: '@' two-stars: '%' three-stars: '*' four-stars: '^' five-stars: '&' items: '~': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODViZDFlNjEzZmYzMmI1MjNjY2Y5ZTU3NGNjMzExYjc5OGMyYjNhNjgyOGYwZjcxYTI1NGM5OTVlNmRiOGU1In19fQ==' name: '&4Horrible (0/5)' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNmYWZmYThjNmM3ZjYyNjIxNjgyZmU1NjcxMWRjM2I4OTQ0NjVmZGY3YTYyZjQzYjMxYTBkMzQwM2YzNGU3In19fQ==' name: '&6Ugly (1/5)' '%': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNThjY2ExZTBmYjVkOWJmNzdmNTI3MzU2ZThiZjRlNTNjYjRhNGM1NmYxMWU3NzlhYmFkYWU1NDFiYmVkYzYifX19' name: '&eNice (2/5)' '*': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQyMjZmMmViNjRhYmM4NmIzOGI2MWQxNDk3NzY0Y2JhMDNkMTc4YWZjMzNiN2I4MDIzY2Y0OGI0OTMxMSJ9fX0=' name: '&aGood (3/5)' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI1MjdiMjRiNWQyYmNkYzc1NmY5OTVkMzRlYWU1NzlkNzQxNGIwYTVmMjZjNGZmYTRhNTU4ZWNhZjZiNyJ9fX0=' name: '&2Beautiful (4/5)' '&': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDkzNTdjYjQ2NjQ0MjZhOWFlMGY5Yzc3MjVlYTQzNTFkYzY5ZjE1YTgwNjJjMDM1OTFlMjZhYzExYmJjNWEifX19' name: '&5Fabulous (5/5)' sounds: '~': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-rate1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lRate Island' previous-menu: true pattern: - '# ~ @ % # * ^ & #' zero-stars: '~' one-star: '@' two-stars: '%' three-stars: '*' four-stars: '^' five-stars: '&' items: '~': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODViZDFlNjEzZmYzMmI1MjNjY2Y5ZTU3NGNjMzExYjc5OGMyYjNhNjgyOGYwZjcxYTI1NGM5OTVlNmRiOGU1In19fQ==' name: '&4Horrible (0/5)' '@': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNmYWZmYThjNmM3ZjYyNjIxNjgyZmU1NjcxMWRjM2I4OTQ0NjVmZGY3YTYyZjQzYjMxYTBkMzQwM2YzNGU3In19fQ==' name: '&6Ugly (1/5)' '%': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNThjY2ExZTBmYjVkOWJmNzdmNTI3MzU2ZThiZjRlNTNjYjRhNGM1NmYxMWU3NzlhYmFkYWU1NDFiYmVkYzYifX19' name: '&eNice (2/5)' '*': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQyMjZmMmViNjRhYmM4NmIzOGI2MWQxNDk3NzY0Y2JhMDNkMTc4YWZjMzNiN2I4MDIzY2Y0OGI0OTMxMSJ9fX0=' name: '&aGood (3/5)' '^': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI1MjdiMjRiNWQyYmNkYzc1NmY5OTVkMzRlYWU1NzlkNzQxNGIwYTVmMjZjNGZmYTRhNTU4ZWNhZjZiNyJ9fX0=' name: '&2Beautiful (4/5)' '&': type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDkzNTdjYjQ2NjQ0MjZhOWFlMGY5Yzc3MjVlYTQzNTFkYzY5ZjE1YTgwNjJjMDM1OTFlMjZhYzExYmJjNWEifX19' name: '&5Fabulous (5/5)' sounds: '~': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-rate1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lRate Island' previous-menu: true pattern: - '# ~ @ % # * ^ & #' zero-stars: '~' one-star: '@' two-stars: '%' three-stars: '*' four-stars: '^' five-stars: '&' items: '~': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODViZDFlNjEzZmYzMmI1MjNjY2Y5ZTU3NGNjMzExYjc5OGMyYjNhNjgyOGYwZjcxYTI1NGM5OTVlNmRiOGU1In19fQ==' name: '&4Horrible (0/5)' '@': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNmYWZmYThjNmM3ZjYyNjIxNjgyZmU1NjcxMWRjM2I4OTQ0NjVmZGY3YTYyZjQzYjMxYTBkMzQwM2YzNGU3In19fQ==' name: '&6Ugly (1/5)' '%': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNThjY2ExZTBmYjVkOWJmNzdmNTI3MzU2ZThiZjRlNTNjYjRhNGM1NmYxMWU3NzlhYmFkYWU1NDFiYmVkYzYifX19' name: '&eNice (2/5)' '*': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQyMjZmMmViNjRhYmM4NmIzOGI2MWQxNDk3NzY0Y2JhMDNkMTc4YWZjMzNiN2I4MDIzY2Y0OGI0OTMxMSJ9fX0=' name: '&aGood (3/5)' '^': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI1MjdiMjRiNWQyYmNkYzc1NmY5OTVkMzRlYWU1NzlkNzQxNGIwYTVmMjZjNGZmYTRhNTU4ZWNhZjZiNyJ9fX0=' name: '&2Beautiful (4/5)' '&': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDkzNTdjYjQ2NjQ0MjZhOWFlMGY5Yzc3MjVlYTQzNTFkYzY5ZjE1YTgwNjJjMDM1OTFlMjZhYzExYmJjNWEifX19' name: '&5Fabulous (5/5)' sounds: '~': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/island-ratings.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Ratings ({0}/5)' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '{1}' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' ================================================ FILE: src/main/resources/menus/island-ratings1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Ratings ({0}/5)' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: PLAYER_HEAD name: '&e{0}' lore: - '{1}' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' ================================================ FILE: src/main/resources/menus/member-manage.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&8&l{}' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ # # # # # # # $' - '$ # @ # % # ^ # $' - '$ # # # # # # # $' - '$ $ $ $ $ $ $ $ $' roles: '@' ban: '%' kick: '^' items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: DIAMOND_CHESTPLATE name: '&ePlayer Role' lore: - '&7Click to edit player''s role.' flags: - HIDE_ATTRIBUTES '%': type: BARRIER name: '&eBan Player' lore: - '&7Click to ban the player from the island.' '^': type: SKULL_ITEM name: '&eKick Player' lore: - '&7Click to kick the player from the island.' sounds: '@': type: CHEST_OPEN volume: 0.8 pitch: 1 '%': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/member-manage1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&8&l{}' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ # # # # # # # $' - '$ # @ # % # ^ # $' - '$ # # # # # # # $' - '$ $ $ $ $ $ $ $ $' roles: '@' ban: '%' kick: '^' items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': type: DIAMOND_CHESTPLATE name: '&ePlayer Role' lore: - '&7Click to edit player''s role.' flags: - HIDE_ATTRIBUTES '%': type: BARRIER name: '&eBan Player' lore: - '&7Click to ban the player from the island.' '^': type: SKULL_ITEM name: '&eKick Player' lore: - '&7Click to kick the player from the island.' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/member-manage1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&8&l{}' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ # # # # # # # $' - '$ # @ # % # ^ # $' - '$ # # # # # # # $' - '$ $ $ $ $ $ $ $ $' roles: '@' ban: '%' kick: '^' items: '$': type: BLACK_STAINED_GLASS_PANE name: '&f' '@': type: DIAMOND_CHESTPLATE name: '&ePlayer Role' lore: - '&7Click to edit player''s role.' flags: - HIDE_ATTRIBUTES '%': type: BARRIER name: '&eBan Player' lore: - '&7Click to ban the player from the island.' '^': type: SKELETON_SKULL name: '&eKick Player' lore: - '&7Click to kick the player from the island.' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/member-role.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&8&l{}' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ # # # # # # # $' - '$ @ # % # & # * $' - '$ # # # # # # # $' - '$ $ $ $ $ $ $ $ $' items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': role: Member type: LEATHER_CHESTPLATE name: '&eMember' lore: - '&7Click to set player''s role to member.' flags: - HIDE_ATTRIBUTES '%': role: Moderator type: GOLD_CHESTPLATE name: '&eModerator' lore: - '&7Click to set player''s role to moderator.' flags: - HIDE_ATTRIBUTES '&': role: Admin type: IRON_CHESTPLATE name: '&eAdmin' lore: - '&7Click to set player''s role to admin.' flags: - HIDE_ATTRIBUTES '*': role: Leader type: DIAMOND_CHESTPLATE name: '&eLeader' lore: - '&7Click to transfer leadership to player.' flags: - HIDE_ATTRIBUTES sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/member-role1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&8&l{}' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ # # # # # # # $' - '$ @ # % # & # * $' - '$ # # # # # # # $' - '$ $ $ $ $ $ $ $ $' items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '@': role: Member type: LEATHER_CHESTPLATE name: '&eMember' lore: - '&7Click to set player''s role to member.' flags: - HIDE_ATTRIBUTES '%': role: Moderator type: GOLD_CHESTPLATE name: '&eModerator' lore: - '&7Click to set player''s role to moderator.' flags: - HIDE_ATTRIBUTES '&': role: Admin type: IRON_CHESTPLATE name: '&eAdmin' lore: - '&7Click to set player''s role to admin.' flags: - HIDE_ATTRIBUTES '*': role: Leader type: DIAMOND_CHESTPLATE name: '&eLeader' lore: - '&7Click to transfer leadership to player.' flags: - HIDE_ATTRIBUTES sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/member-role1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&8&l{}' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ # # # # # # # $' - '$ @ # % # & # * $' - '$ # # # # # # # $' - '$ $ $ $ $ $ $ $ $' items: '$': type: BLACK_STAINED_GLASS_PANE name: '&f' '@': role: Member type: LEATHER_CHESTPLATE name: '&eMember' lore: - '&7Click to set player''s role to member.' flags: - HIDE_ATTRIBUTES '%': role: Moderator type: GOLDEN_CHESTPLATE name: '&eModerator' lore: - '&7Click to set player''s role to moderator.' flags: - HIDE_ATTRIBUTES '&': role: Admin type: IRON_CHESTPLATE name: '&eAdmin' lore: - '&7Click to set player''s role to admin.' flags: - HIDE_ATTRIBUTES '*': role: Leader type: DIAMOND_CHESTPLATE name: '&eLeader' lore: - '&7Click to transfer leadership to player.' flags: - HIDE_ATTRIBUTES sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '&': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '*': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/members.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Members ({0}/{1})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&eRole: &7{1}' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/members1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Members ({0}/{1})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&eRole: &7{1}' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/members1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Members ({0}/{1})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: PLAYER_HEAD name: '&e{0}' lore: - '&eRole: &7{1}' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/missions-category.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l{0} Missions' previous-menu: true pattern: - '# # # # # # # # #' - '# # @ @ @ @ @ # #' - '# # # # # # # # #' slots: '@' previous-page: '*' current-page: '*' next-page: '*' # Should missions be sorted by their completion status? # Not completed -> Can complete -> Completed sort-by-completion: false # Should completed missions not be displayed in the menu? remove-completed: false items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': locked: type: ANVIL_LAND volume: 0.2 pitch: 0.2 completed: type: ANVIL_LAND volume: 0.2 pitch: 0.2 not-completed: type: ANVIL_LAND volume: 0.2 pitch: 0.2 can-complete: type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/missions-category1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l{0} Missions' previous-menu: true pattern: - '# # # # # # # # #' - '# # @ @ @ @ @ # #' - '# # # # # # # # #' slots: '@' previous-page: '*' current-page: '*' next-page: '*' # Should missions be sorted by their completion status? # Not completed -> Can complete -> Completed sort-by-completion: false # Should completed missions not be displayed in the menu? remove-completed: false items: '#': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': locked: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 completed: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 not-completed: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 can-complete: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/missions-category1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&l{0} Missions' previous-menu: true pattern: - '# # # # # # # # #' - '# # @ @ @ @ @ # #' - '# # # # # # # # #' slots: '@' previous-page: '*' current-page: '*' next-page: '*' # Should missions be sorted by their completion status? # Not completed -> Can complete -> Completed sort-by-completion: false # Should completed missions not be displayed in the menu? remove-completed: false items: '#': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': locked: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 completed: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 not-completed: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 can-complete: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/missions.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lMissions' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ * * * * * * * $' - '$ * # @ % ^ & * $' - '$ * * * * * * * $' - '$ $ $ $ $ $ $ $ $' items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '#': type: DIAMOND_PICKAXE name: '&eMiner Missions' lore: - '&7Click to start your adventure as a Miner.' flags: - HIDE_ATTRIBUTES '@': type: SKULL_ITEM data: 2 name: '&eSlayer Missions' lore: - '&7Click to start your adventure as a Slayer.' '%': type: WHEAT name: '&eFarmer Missions' lore: - '&7Click to start your adventure as a Farmer.' '^': type: FISHING_ROD name: '&eFisherman Missions' lore: - '&7Click to start your adventure as a Fisherman.' '&': type: MAP name: '&eExplorer Missions' lore: - '&7Click to start your adventure as an Explorer.' sounds: '#': type: CHEST_OPEN volume: 0.8 pitch: 1 '@': type: CHEST_OPEN volume: 0.8 pitch: 1 '%': type: CHEST_OPEN volume: 0.8 pitch: 1 '^': type: CHEST_OPEN volume: 0.8 pitch: 1 '&': type: CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/missions1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lMissions' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ * * * * * * * $' - '$ * # @ % ^ & * $' - '$ * * * * * * * $' - '$ $ $ $ $ $ $ $ $' items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' '#': type: DIAMOND_PICKAXE name: '&eMiner Missions' lore: - '&7Click to start your adventure as a Miner.' flags: - HIDE_ATTRIBUTES '@': type: SKULL_ITEM data: 2 name: '&eSlayer Missions' lore: - '&7Click to start your adventure as a Slayer.' '%': type: WHEAT name: '&eFarmer Missions' lore: - '&7Click to start your adventure as a Farmer.' '^': type: FISHING_ROD name: '&eFisherman Missions' lore: - '&7Click to start your adventure as a Fisherman.' '&': type: MAP name: '&eExplorer Missions' lore: - '&7Click to start your adventure as an Explorer.' sounds: '#': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '%': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '^': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '&': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/missions1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lMissions' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ * * * * * * * $' - '$ * # @ % ^ & * $' - '$ * * * * * * * $' - '$ $ $ $ $ $ $ $ $' items: '$': type: BLACK_STAINED_GLASS_PANE name: '&f' '#': type: DIAMOND_PICKAXE name: '&eMiner Missions' lore: - '&7Click to start your adventure as a Miner.' flags: - HIDE_ATTRIBUTES '@': type: ZOMBIE_HEAD name: '&eSlayer Missions' lore: - '&7Click to start your adventure as a Slayer.' '%': type: WHEAT name: '&eFarmer Missions' lore: - '&7Click to start your adventure as a Farmer.' '^': type: FISHING_ROD name: '&eFisherman Missions' lore: - '&7Click to start your adventure as a Fisherman.' '&': type: MAP name: '&eExplorer Missions' lore: - '&7Click to start your adventure as an Explorer.' sounds: '#': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '@': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '%': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '^': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 '&': type: BLOCK_CHEST_OPEN volume: 0.8 pitch: 1 ================================================ FILE: src/main/resources/menus/permissions.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lPermissions Controller' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' messages: no-role-permission: '&8 - &c{}' exact-role-permission: '&8 - &2{}' higher-role-permission: '&8 - &a{}' items: '$': type: STAINED_GLASS_PANE data: 3 name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' permissions: all: display-menu: true permission-enabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 animal_breed: display-menu: true permission-enabled: type: WHEAT name: '&6Animal Breed' lore: - '&7Access to breed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 animal_damage: display-menu: true permission-enabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 animal_shear: display-menu: true permission-enabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 animal_spawn: display-menu: true permission-enabled: type: MONSTER_EGG data: 93 name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG data: 93 name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG data: 93 name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 ban_member: display-menu: true permission-enabled: type: SKULL_ITEM name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 break: display-menu: true permission-enabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 build: display-menu: true permission-enabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 change_name: display-menu: true permission-enabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 chest_access: display-menu: true permission-enabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 close_bypass: display-menu: true permission-enabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &aENABLED&7.' permission-disabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &cDISABLED&7.' role-permission: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 close_island: display-menu: true permission-enabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &aENABLED&7.' permission-disabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &cDISABLED&7.' role-permission: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 coop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 delete_warp: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 demote_members: display-menu: true permission-enabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 deposit_money: display-menu: true permission-enabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 disband_island: display-menu: true permission-enabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 discord_show: display-menu: true permission-enabled: type: STAINED_CLAY data: 3 name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &aENABLED&7.' permission-disabled: type: STAINED_CLAY data: 3 name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &cDISABLED&7.' role-permission: type: STAINED_CLAY data: 3 name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 drop_items: display-menu: true permission-enabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 dye_sheep: display-menu: true permission-enabled: type: MONSTER_EGG entity: SHEEP name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG entity: SHEEP name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG entity: SHEEP name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 ender_pearl: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 entity_ride: display-menu: true permission-enabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 expel_bypass: display-menu: true permission-enabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 expel_players: display-menu: true permission-enabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 farm_tramping: display-menu: true permission-enabled: type: SOIL name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SOIL name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SOIL name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 fertilize: display-menu: true permission-enabled: type: INK_SACK data: 15 name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: INK_SACK data: 15 name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: INK_SACK data: 15 name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 fish: display-menu: true permission-enabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 fly: display-menu: true permission-enabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 horse_interact: display-menu: true permission-enabled: type: MONSTER_EGG entity: HORSE name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG entity: HORSE name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG entity: HORSE name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 ignite_creeper: display-menu: true permission-enabled: type: MONSTER_EGG entity: CREEPER name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG entity: CREEPER name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG entity: CREEPER name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 interact: display-menu: true permission-enabled: type: PISTON_BASE name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PISTON_BASE name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PISTON_BASE name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 invite_member: display-menu: true permission-enabled: type: SKULL_ITEM data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 island_chest: display-menu: true permission-enabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 item_frame: display-menu: true permission-enabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 kick_member: display-menu: true permission-enabled: type: SKULL_ITEM name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 leash: display-menu: true permission-enabled: type: LEASH name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEASH name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LEASH name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 minecart_damage: display-menu: true permission-enabled: type: EXPLOSIVE_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: EXPLOSIVE_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: EXPLOSIVE_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 minecart_enter: display-menu: true permission-enabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 minecart_open: display-menu: true permission-enabled: type: STORAGE_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STORAGE_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STORAGE_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 minecart_place: display-menu: true permission-enabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 monster_damage: display-menu: true permission-enabled: type: SKULL_ITEM data: 2 name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM data: 2 name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM data: 2 name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 monster_spawn: display-menu: true permission-enabled: type: MONSTER_EGG data: 59 name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG data: 59 name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG data: 59 name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 name_entity: display-menu: true permission-enabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 open_island: display-menu: true permission-enabled: type: REDSTONE_TORCH_ON name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &aENABLED&7.' permission-disabled: type: REDSTONE_TORCH_ON name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &cDISABLED&7.' role-permission: type: REDSTONE_TORCH_ON name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 painting: display-menu: true permission-enabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 paypal_show: display-menu: true permission-enabled: type: WOOL data: 11 name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &aENABLED&7.' permission-disabled: type: WOOL data: 11 name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &cDISABLED&7.' role-permission: type: WOOL data: 11 name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 pickup_drops: display-menu: true permission-enabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 promote_members: display-menu: true permission-enabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 rankup: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 ratings_show: display-menu: true permission-enabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 saddle_entity: display-menu: true permission-enabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 set_biome: display-menu: true permission-enabled: type: GRASS name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: type: GRASS name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: type: GRASS name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 set_discord: display-menu: true permission-enabled: type: STAINED_CLAY data: 3 name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STAINED_CLAY data: 3 name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STAINED_CLAY data: 3 name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 set_home: display-menu: true permission-enabled: type: BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 set_paypal: display-menu: true permission-enabled: type: WOOL data: 11 name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: WOOL data: 11 name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: WOOL data: 11 name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 set_permission: display-menu: true permission-enabled: type: DIODE name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIODE name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &cDISABLED&7.' role-permission: type: DIODE name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 set_role: display-menu: true permission-enabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 set_settings: display-menu: true permission-enabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &cDISABLED&7.' role-permission: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 set_warp: display-menu: true permission-enabled: type: EYE_OF_ENDER name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: EYE_OF_ENDER name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &cDISABLED&7.' role-permission: type: EYE_OF_ENDER name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 sign_interact: display-menu: true permission-enabled: type: SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 spawner_break: display-menu: true permission-enabled: type: MOB_SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MOB_SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MOB_SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 tamed_animal_damage: display-menu: true permission-enabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 uncoop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 use: display-menu: true permission-enabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 valuable_break: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 villager_trading: display-menu: true permission-enabled: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 withdraw_money: display-menu: true permission-enabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/permissions1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lPermissions Controller' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' messages: no-role-permission: '&8 - &c{}' exact-role-permission: '&8 - &2{}' higher-role-permission: '&8 - &a{}' items: '$': type: STAINED_GLASS_PANE data: 3 name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' permissions: all: display-menu: true permission-enabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_breed: display-menu: true permission-enabled: type: WHEAT name: '&6Animal Breed' lore: - '&7Access to breed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_damage: display-menu: true permission-enabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_shear: display-menu: true permission-enabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_spawn: display-menu: true permission-enabled: type: MONSTER_EGG data: 93 name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG data: 93 name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG data: 93 name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ban_member: display-menu: true permission-enabled: type: SKULL_ITEM name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 break: display-menu: true permission-enabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 build: display-menu: true permission-enabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 change_name: display-menu: true permission-enabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chest_access: display-menu: true permission-enabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chorus_fruit: display-menu: true permission-enabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_bypass: display-menu: true permission-enabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &aENABLED&7.' permission-disabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &cDISABLED&7.' role-permission: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_island: display-menu: true permission-enabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &aENABLED&7.' permission-disabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &cDISABLED&7.' role-permission: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 coop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 delete_warp: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 demote_members: display-menu: true permission-enabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 deposit_money: display-menu: true permission-enabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 disband_island: display-menu: true permission-enabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 discord_show: display-menu: true permission-enabled: type: STAINED_CLAY data: 3 name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &aENABLED&7.' permission-disabled: type: STAINED_CLAY data: 3 name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &cDISABLED&7.' role-permission: type: STAINED_CLAY data: 3 name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 drop_items: display-menu: true permission-enabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 dye_sheep: display-menu: true permission-enabled: type: MONSTER_EGG entity: SHEEP name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG entity: SHEEP name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG entity: SHEEP name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ender_pearl: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 entity_ride: display-menu: true permission-enabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_bypass: display-menu: true permission-enabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_players: display-menu: true permission-enabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 farm_tramping: display-menu: true permission-enabled: type: SOIL name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SOIL name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SOIL name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fertilize: display-menu: true permission-enabled: type: INK_SACK data: 15 name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: INK_SACK data: 15 name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: INK_SACK data: 15 name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fish: display-menu: true permission-enabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fly: display-menu: true permission-enabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 horse_interact: display-menu: true permission-enabled: type: MONSTER_EGG entity: HORSE name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG entity: HORSE name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG entity: HORSE name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ignite_creeper: display-menu: true permission-enabled: type: MONSTER_EGG entity: CREEPER name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG entity: CREEPER name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG entity: CREEPER name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 interact: display-menu: true permission-enabled: type: PISTON_BASE name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PISTON_BASE name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PISTON_BASE name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 invite_member: display-menu: true permission-enabled: type: SKULL_ITEM data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 island_chest: display-menu: true permission-enabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 item_frame: display-menu: true permission-enabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 kick_member: display-menu: true permission-enabled: type: SKULL_ITEM name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 leash: display-menu: true permission-enabled: type: LEASH name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEASH name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LEASH name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_damage: display-menu: true permission-enabled: type: EXPLOSIVE_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: EXPLOSIVE_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: EXPLOSIVE_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_enter: display-menu: true permission-enabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_open: display-menu: true permission-enabled: type: STORAGE_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STORAGE_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STORAGE_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_place: display-menu: true permission-enabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_damage: display-menu: true permission-enabled: type: SKULL_ITEM data: 2 name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM data: 2 name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM data: 2 name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_spawn: display-menu: true permission-enabled: type: MONSTER_EGG data: 59 name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MONSTER_EGG data: 59 name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MONSTER_EGG data: 59 name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 name_entity: display-menu: true permission-enabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 open_island: display-menu: true permission-enabled: type: REDSTONE_TORCH_ON name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &aENABLED&7.' permission-disabled: type: REDSTONE_TORCH_ON name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &cDISABLED&7.' role-permission: type: REDSTONE_TORCH_ON name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 painting: display-menu: true permission-enabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 paypal_show: display-menu: true permission-enabled: type: WOOL data: 11 name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &aENABLED&7.' permission-disabled: type: WOOL data: 11 name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &cDISABLED&7.' role-permission: type: WOOL data: 11 name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_drops: display-menu: true permission-enabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 promote_members: display-menu: true permission-enabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 rankup: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ratings_show: display-menu: true permission-enabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 saddle_entity: display-menu: true permission-enabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_biome: display-menu: true permission-enabled: type: GRASS name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: type: GRASS name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: type: GRASS name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_discord: display-menu: true permission-enabled: type: STAINED_CLAY data: 3 name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STAINED_CLAY data: 3 name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STAINED_CLAY data: 3 name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_home: display-menu: true permission-enabled: type: BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_paypal: display-menu: true permission-enabled: type: WOOL data: 11 name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: WOOL data: 11 name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: WOOL data: 11 name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_permission: display-menu: true permission-enabled: type: DIODE name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIODE name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &cDISABLED&7.' role-permission: type: DIODE name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_role: display-menu: true permission-enabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_settings: display-menu: true permission-enabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &cDISABLED&7.' role-permission: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_warp: display-menu: true permission-enabled: type: EYE_OF_ENDER name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: EYE_OF_ENDER name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &cDISABLED&7.' role-permission: type: EYE_OF_ENDER name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sign_interact: display-menu: true permission-enabled: type: SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner_break: display-menu: true permission-enabled: type: MOB_SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MOB_SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MOB_SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 tamed_animal_damage: display-menu: true permission-enabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 uncoop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 use: display-menu: true permission-enabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 valuable_break: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 villager_trading: display-menu: true permission-enabled: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 withdraw_money: display-menu: true permission-enabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/permissions1_16.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lPermissions Controller' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' messages: no-role-permission: '&8 - &c{}' exact-role-permission: '&8 - &2{}' higher-role-permission: '&8 - &a{}' items: '$': type: CYAN_STAINED_GLASS_PANE name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' permissions: all: display-menu: true permission-enabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_breed: display-menu: true permission-enabled: type: WHEAT name: '&6Animal Breed' lore: - '&7Access to breed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_damage: display-menu: true permission-enabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_shear: display-menu: true permission-enabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_spawn: display-menu: true permission-enabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ban_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 break: display-menu: true permission-enabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 build: display-menu: true permission-enabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 change_name: display-menu: true permission-enabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chest_access: display-menu: true permission-enabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chorus_fruit: display-menu: true permission-enabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_bypass: display-menu: true permission-enabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &aENABLED&7.' permission-disabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &cDISABLED&7.' role-permission: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_island: display-menu: true permission-enabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &aENABLED&7.' permission-disabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &cDISABLED&7.' role-permission: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 coop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 delete_warp: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 demote_members: display-menu: true permission-enabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 deposit_money: display-menu: true permission-enabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 disband_island: display-menu: true permission-enabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 discord_show: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 drop_items: display-menu: true permission-enabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 dye_sheep: display-menu: true permission-enabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ender_pearl: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 entity_ride: display-menu: true permission-enabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_bypass: display-menu: true permission-enabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_players: display-menu: true permission-enabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 farm_tramping: display-menu: true permission-enabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fertilize: display-menu: true permission-enabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fish: display-menu: true permission-enabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fly: display-menu: true permission-enabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 horse_interact: display-menu: true permission-enabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ignite_creeper: display-menu: true permission-enabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 interact: display-menu: true permission-enabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 invite_member: display-menu: true permission-enabled: type: PLAYER_HEAD data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 island_chest: display-menu: true permission-enabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 item_frame: display-menu: true permission-enabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 kick_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 leash: display-menu: true permission-enabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_damage: display-menu: true permission-enabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_enter: display-menu: true permission-enabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_open: display-menu: true permission-enabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_place: display-menu: true permission-enabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_damage: display-menu: true permission-enabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_spawn: display-menu: true permission-enabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 name_entity: display-menu: true permission-enabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 open_island: display-menu: true permission-enabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &aENABLED&7.' permission-disabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &cDISABLED&7.' role-permission: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 painting: display-menu: true permission-enabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 paypal_show: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_drops: display-menu: true permission-enabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_fish: display-menu: true permission-enabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_lectern_book: display-menu: true permission-enabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 promote_members: display-menu: true permission-enabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 rankup: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ratings_show: display-menu: true permission-enabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 saddle_entity: display-menu: true permission-enabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_biome: display-menu: true permission-enabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_discord: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_home: display-menu: true permission-enabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_paypal: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_permission: display-menu: true permission-enabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &aENABLED&7.' permission-disabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &cDISABLED&7.' role-permission: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_role: display-menu: true permission-enabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_settings: display-menu: true permission-enabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &cDISABLED&7.' role-permission: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_warp: display-menu: true permission-enabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sign_interact: display-menu: true permission-enabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner_break: display-menu: true permission-enabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 turtle_egg_tramping: display-menu: true permission-enabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 tamed_animal_damage: display-menu: true permission-enabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 uncoop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 use: display-menu: true permission-enabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 valuable_break: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 villager_trading: display-menu: true permission-enabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 withdraw_money: display-menu: true permission-enabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/permissions1_17.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lPermissions Controller' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' messages: no-role-permission: '&8 - &c{}' exact-role-permission: '&8 - &2{}' higher-role-permission: '&8 - &a{}' items: '$': type: CYAN_STAINED_GLASS_PANE name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' permissions: all: display-menu: true permission-enabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_breed: display-menu: true permission-enabled: type: WHEAT name: '&6Animal Breed' lore: - '&7Access to breed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_damage: display-menu: true permission-enabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_shear: display-menu: true permission-enabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_spawn: display-menu: true permission-enabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ban_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 break: display-menu: true permission-enabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 build: display-menu: true permission-enabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 change_name: display-menu: true permission-enabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chest_access: display-menu: true permission-enabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chorus_fruit: display-menu: true permission-enabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_bypass: display-menu: true permission-enabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &aENABLED&7.' permission-disabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &cDISABLED&7.' role-permission: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_island: display-menu: true permission-enabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &aENABLED&7.' permission-disabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &cDISABLED&7.' role-permission: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 coop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 delete_warp: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 demote_members: display-menu: true permission-enabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 deposit_money: display-menu: true permission-enabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 disband_island: display-menu: true permission-enabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 discord_show: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 drop_items: display-menu: true permission-enabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 dye_sheep: display-menu: true permission-enabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ender_pearl: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 entity_ride: display-menu: true permission-enabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_bypass: display-menu: true permission-enabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_players: display-menu: true permission-enabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 farm_tramping: display-menu: true permission-enabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fertilize: display-menu: true permission-enabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fish: display-menu: true permission-enabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fly: display-menu: true permission-enabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 horse_interact: display-menu: true permission-enabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ignite_creeper: display-menu: true permission-enabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 interact: display-menu: true permission-enabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 invite_member: display-menu: true permission-enabled: type: PLAYER_HEAD data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 island_chest: display-menu: true permission-enabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 item_frame: display-menu: true permission-enabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 kick_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 leash: display-menu: true permission-enabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_damage: display-menu: true permission-enabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_enter: display-menu: true permission-enabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_open: display-menu: true permission-enabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_place: display-menu: true permission-enabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_damage: display-menu: true permission-enabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_spawn: display-menu: true permission-enabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 name_entity: display-menu: true permission-enabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 open_island: display-menu: true permission-enabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &aENABLED&7.' permission-disabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &cDISABLED&7.' role-permission: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 painting: display-menu: true permission-enabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 paypal_show: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_axolotl: display-menu: true permission-enabled: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_drops: display-menu: true permission-enabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_fish: display-menu: true permission-enabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_lectern_book: display-menu: true permission-enabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 promote_members: display-menu: true permission-enabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 rankup: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ratings_show: display-menu: true permission-enabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 saddle_entity: display-menu: true permission-enabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sculk_sensor: display-menu: true permission-enabled: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_biome: display-menu: true permission-enabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_discord: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_home: display-menu: true permission-enabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_paypal: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_permission: display-menu: true permission-enabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &aENABLED&7.' permission-disabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &cDISABLED&7.' role-permission: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_role: display-menu: true permission-enabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_settings: display-menu: true permission-enabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &cDISABLED&7.' role-permission: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_warp: display-menu: true permission-enabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sign_interact: display-menu: true permission-enabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner_break: display-menu: true permission-enabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 turtle_egg_tramping: display-menu: true permission-enabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 tamed_animal_damage: display-menu: true permission-enabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 uncoop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 use: display-menu: true permission-enabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 valuable_break: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 villager_trading: display-menu: true permission-enabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 withdraw_money: display-menu: true permission-enabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/permissions1_19.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lPermissions Controller' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' messages: no-role-permission: '&8 - &c{}' exact-role-permission: '&8 - &2{}' higher-role-permission: '&8 - &a{}' items: '$': type: CYAN_STAINED_GLASS_PANE name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' permissions: all: display-menu: true permission-enabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 allay_interact: display-menu: true permission-enabled: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_breed: display-menu: true permission-enabled: type: WHEAT name: '&6Animal Breed' lore: - '&7Access to breed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_damage: display-menu: true permission-enabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_shear: display-menu: true permission-enabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_spawn: display-menu: true permission-enabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ban_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 break: display-menu: true permission-enabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 brush: display-menu: true permission-enabled: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 build: display-menu: true permission-enabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 change_name: display-menu: true permission-enabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chest_access: display-menu: true permission-enabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chorus_fruit: display-menu: true permission-enabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_bypass: display-menu: true permission-enabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &aENABLED&7.' permission-disabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &cDISABLED&7.' role-permission: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_island: display-menu: true permission-enabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &aENABLED&7.' permission-disabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &cDISABLED&7.' role-permission: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 coop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 delete_warp: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 demote_members: display-menu: true permission-enabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 deposit_money: display-menu: true permission-enabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 disband_island: display-menu: true permission-enabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 discord_show: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 drop_items: display-menu: true permission-enabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 dye_sheep: display-menu: true permission-enabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ender_pearl: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 entity_ride: display-menu: true permission-enabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_bypass: display-menu: true permission-enabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_players: display-menu: true permission-enabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 farm_tramping: display-menu: true permission-enabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fertilize: display-menu: true permission-enabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fish: display-menu: true permission-enabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fly: display-menu: true permission-enabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 horse_interact: display-menu: true permission-enabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ignite_creeper: display-menu: true permission-enabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 interact: display-menu: true permission-enabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 invite_member: display-menu: true permission-enabled: type: PLAYER_HEAD data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 island_chest: display-menu: true permission-enabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 item_frame: display-menu: true permission-enabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 kick_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 leash: display-menu: true permission-enabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_damage: display-menu: true permission-enabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_enter: display-menu: true permission-enabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_open: display-menu: true permission-enabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_place: display-menu: true permission-enabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_damage: display-menu: true permission-enabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_spawn: display-menu: true permission-enabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 name_entity: display-menu: true permission-enabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 open_island: display-menu: true permission-enabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &aENABLED&7.' permission-disabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &cDISABLED&7.' role-permission: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 painting: display-menu: true permission-enabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 paypal_show: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_axolotl: display-menu: true permission-enabled: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_drops: display-menu: true permission-enabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_fish: display-menu: true permission-enabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_lectern_book: display-menu: true permission-enabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 promote_members: display-menu: true permission-enabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 rankup: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ratings_show: display-menu: true permission-enabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 saddle_entity: display-menu: true permission-enabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sculk_sensor: display-menu: true permission-enabled: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_biome: display-menu: true permission-enabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_discord: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_home: display-menu: true permission-enabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_paypal: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_permission: display-menu: true permission-enabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &aENABLED&7.' permission-disabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &cDISABLED&7.' role-permission: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_role: display-menu: true permission-enabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_settings: display-menu: true permission-enabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &cDISABLED&7.' role-permission: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_warp: display-menu: true permission-enabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sign_interact: display-menu: true permission-enabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner_break: display-menu: true permission-enabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP permission-disabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP role-permission: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ADDITIONAL_TOOLTIP has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 turtle_egg_tramping: display-menu: true permission-enabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 tamed_animal_damage: display-menu: true permission-enabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 uncoop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 use: display-menu: true permission-enabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 valuable_break: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 villager_trading: display-menu: true permission-enabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 withdraw_money: display-menu: true permission-enabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/permissions1_20.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lPermissions Controller' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' messages: no-role-permission: '&8 - &c{}' exact-role-permission: '&8 - &2{}' higher-role-permission: '&8 - &a{}' items: '$': type: CYAN_STAINED_GLASS_PANE name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' permissions: all: display-menu: true permission-enabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 allay_interact: display-menu: true permission-enabled: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_breed: display-menu: true permission-enabled: type: WHEAT name: '&6Animal Breed' lore: - '&7Access to breed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_damage: display-menu: true permission-enabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_shear: display-menu: true permission-enabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_spawn: display-menu: true permission-enabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ban_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 break: display-menu: true permission-enabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 brush: display-menu: true permission-enabled: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 build: display-menu: true permission-enabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 change_name: display-menu: true permission-enabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chest_access: display-menu: true permission-enabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chorus_fruit: display-menu: true permission-enabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_bypass: display-menu: true permission-enabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &aENABLED&7.' permission-disabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &cDISABLED&7.' role-permission: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_island: display-menu: true permission-enabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &aENABLED&7.' permission-disabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &cDISABLED&7.' role-permission: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 coop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 delete_warp: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 demote_members: display-menu: true permission-enabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 deposit_money: display-menu: true permission-enabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 disband_island: display-menu: true permission-enabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 discord_show: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 drop_items: display-menu: true permission-enabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 dye_sheep: display-menu: true permission-enabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ender_pearl: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 entity_ride: display-menu: true permission-enabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_bypass: display-menu: true permission-enabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_players: display-menu: true permission-enabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 farm_tramping: display-menu: true permission-enabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fertilize: display-menu: true permission-enabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fish: display-menu: true permission-enabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fly: display-menu: true permission-enabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 horse_interact: display-menu: true permission-enabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ignite_creeper: display-menu: true permission-enabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 interact: display-menu: true permission-enabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 invite_member: display-menu: true permission-enabled: type: PLAYER_HEAD data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 island_chest: display-menu: true permission-enabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 item_frame: display-menu: true permission-enabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 kick_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 leash: display-menu: true permission-enabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_damage: display-menu: true permission-enabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_enter: display-menu: true permission-enabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_open: display-menu: true permission-enabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_place: display-menu: true permission-enabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_damage: display-menu: true permission-enabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_spawn: display-menu: true permission-enabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 name_entity: display-menu: true permission-enabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 open_island: display-menu: true permission-enabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &aENABLED&7.' permission-disabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &cDISABLED&7.' role-permission: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 painting: display-menu: true permission-enabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 paypal_show: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_axolotl: display-menu: true permission-enabled: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_drops: display-menu: true permission-enabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_fish: display-menu: true permission-enabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_lectern_book: display-menu: true permission-enabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 promote_members: display-menu: true permission-enabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 rankup: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ratings_show: display-menu: true permission-enabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 saddle_entity: display-menu: true permission-enabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sculk_sensor: display-menu: true permission-enabled: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_biome: display-menu: true permission-enabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_discord: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_home: display-menu: true permission-enabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_paypal: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_permission: display-menu: true permission-enabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &aENABLED&7.' permission-disabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &cDISABLED&7.' role-permission: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_role: display-menu: true permission-enabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_settings: display-menu: true permission-enabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &cDISABLED&7.' role-permission: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_warp: display-menu: true permission-enabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sign_interact: display-menu: true permission-enabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner_break: display-menu: true permission-enabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP permission-disabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP role-permission: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ADDITIONAL_TOOLTIP has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 turtle_egg_tramping: display-menu: true permission-enabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 tamed_animal_damage: display-menu: true permission-enabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 uncoop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 use: display-menu: true permission-enabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 valuable_break: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 villager_trading: display-menu: true permission-enabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 withdraw_money: display-menu: true permission-enabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/permissions1_21.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lPermissions Controller' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' messages: no-role-permission: '&8 - &c{}' exact-role-permission: '&8 - &2{}' higher-role-permission: '&8 - &a{}' items: '$': type: CYAN_STAINED_GLASS_PANE name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' permissions: all: display-menu: true permission-enabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BEDROCK name: '&6All' lore: - '&7Access to all the abilities of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 allay_interact: display-menu: true permission-enabled: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ALLAY_SPAWN_EGG name: '&6Allay Interact' lore: - '&7Access to interact with allays inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_breed: display-menu: true permission-enabled: type: WHEAT name: '&6Animal Breed' lore: - '&7Access to breed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: name: '&6Animal Breed' type: WHEAT lore: - '&7Access to breed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_damage: display-menu: true permission-enabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_shear: display-menu: true permission-enabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEARS name: '&6Animal Shear' lore: - '&7Access to shear animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 animal_spawn: display-menu: true permission-enabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHICKEN_SPAWN_EGG name: '&6Animal Spawn' lore: - '&7Access to spawn animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ban_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Ban Member' lore: - '&7Access to ban members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 break: display-menu: true permission-enabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 brush: display-menu: true permission-enabled: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BRUSH name: '&6Brush' lore: - '&7Access to brush suspicious blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 build: display-menu: true permission-enabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COBBLESTONE name: '&6Build' lore: - '&7Access to place blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 change_name: display-menu: true permission-enabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Change Name' lore: - '&7Access to change the island''s name.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chest_access: display-menu: true permission-enabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST name: '&6Chest Access' lore: - '&7Access to open chests inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 chorus_fruit: display-menu: true permission-enabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHORUS_FRUIT name: '&6Chorus Fruit' lore: - '&7Access to consume chorus fruits inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_bypass: display-menu: true permission-enabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &aENABLED&7.' permission-disabled: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Currently &cDISABLED&7.' role-permission: type: TRIPWIRE_HOOK name: '&6Locked Bypass' lore: - '&7Access to bypass the island''s lock.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 close_island: display-menu: true permission-enabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &aENABLED&7.' permission-disabled: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Currently &cDISABLED&7.' role-permission: type: BARRIER name: '&6Lock Island' lore: - '&7Access to lock the island from public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 coop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Coop Member' lore: - '&7Access to add a player as a co-op member.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 copper_golem_interact: display-menu: true permission-enabled: type: COPPER_GOLEM_STATUE name: '&6Copper Golem Interact' lore: - '&7Access to take items from copper golems.' - '&7Currently &aENABLED&7.' permission-disabled: type: COPPER_GOLEM_STATUE name: '&6Copper Golem Interact' lore: - '&7Access to take items from copper golems.' - '&7Currently &cDISABLED&7.' role-permission: type: COPPER_GOLEM_STATUE name: '&6Copper Golem Interact' lore: - '&7Access to take items from copper golems.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 delete_warp: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Delete Warp' lore: - '&7Access to delete island warps.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 demote_members: display-menu: true permission-enabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: IRON_INGOT name: '&6Demote Members' lore: - '&7Access to demote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 deposit_money: display-menu: true permission-enabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: MAP name: '&6Deposit Money' lore: - '&7Access to deposit money into the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 disband_island: display-menu: true permission-enabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT name: '&6Disband Island' lore: - '&7Access to disband the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 discord_show: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Discord Show' lore: - '&7Access to check the island''s linked discord.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 drop_items: display-menu: true permission-enabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ARROW name: '&6Drop Items' lore: - '&7Access to drop items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 dye_sheep: display-menu: true permission-enabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SHEEP_SPAWN_EGG name: '&6Dye Sheep' lore: - '&7Access to dye sheep inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ender_pearl: display-menu: true permission-enabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_PEARL name: '&6Ender Pearl' lore: - '&7Access to use ender pearls inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 entity_ride: display-menu: true permission-enabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Entity Ride' lore: - '&7Access to ride entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_bypass: display-menu: true permission-enabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Expel Bypass' lore: - '&7Access to bypass from being expelled.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 expel_players: display-menu: true permission-enabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DISPENSER name: '&6Expel Players' lore: - '&7Access to expel players from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 farm_tramping: display-menu: true permission-enabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FARMLAND name: '&6Farm Tramping' lore: - '&7Access to tramp farmlands inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fertilize: display-menu: true permission-enabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE_MEAL name: '&6Fertilize' lore: - '&7Access to fertilize blocks around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fish: display-menu: true permission-enabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FISHING_ROD name: '&6Fish' lore: - '&7Access fishing around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 fly: display-menu: true permission-enabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Currently &cDISABLED&7.' role-permission: type: FEATHER name: '&6Fly' lore: - '&7Access fly around the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 horse_interact: display-menu: true permission-enabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HORSE_SPAWN_EGG name: '&6Horse Interact' lore: - '&7Access to interact with horses inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ignite_creeper: display-menu: true permission-enabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CREEPER_SPAWN_EGG name: '&6Ignite Creepers' lore: - '&7Access to ignite creepers with flint and steel inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 interact: display-menu: true permission-enabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PISTON name: '&6Interact' lore: - '&7Access to interact with blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 invite_member: display-menu: true permission-enabled: type: PLAYER_HEAD data: 3 name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD name: '&6Invite Member' lore: - '&7Access to invite new members to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 island_chest: display-menu: true permission-enabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_CHEST name: '&6Community Chest' lore: - '&7Access to the community chest of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 item_frame: display-menu: true permission-enabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ITEM_FRAME name: '&6Item Frame' lore: - '&7Access to interact with item frames inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 kick_member: display-menu: true permission-enabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SKELETON_SKULL name: '&6Kick Member' lore: - '&7Access to kick members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 leash: display-menu: true permission-enabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LEAD name: '&6Leash Mobs' lore: - '&7Access to leash mobs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_damage: display-menu: true permission-enabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TNT_MINECART name: '&6Minecart Damage' lore: - '&7Access to damage minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_enter: display-menu: true permission-enabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER_MINECART name: '&6Minecart Enter' lore: - '&7Access to enter minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_open: display-menu: true permission-enabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CHEST_MINECART name: '&6Minecart Open' lore: - '&7Access to open minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecart_place: display-menu: true permission-enabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: MINECART name: '&6Minecart Place' lore: - '&7Access to place minecarts inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_damage: display-menu: true permission-enabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ZOMBIE_HEAD name: '&6Monster Damage' lore: - '&7Access to damage monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 monster_spawn: display-menu: true permission-enabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: CAVE_SPIDER_SPAWN_EGG name: '&6Monster Spawn' lore: - '&7Access to spawn monsters inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 nautilus_interact: display-menu: true permission-enabled: type: NAUTILUS_SHELL name: '&6Nautilus Interact' lore: - '&7Access to interact with nautiluses inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAUTILUS_SHELL name: '&6Nautilus Interact' lore: - '&7Access to interact with nautiluses inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: NAUTILUS_SHELL name: '&6Nautilus Interact' lore: - '&7Access to interact with nautiluses inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 name_entity: display-menu: true permission-enabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: NAME_TAG name: '&6Name Entity' lore: - '&7Access to name-tag entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 open_island: display-menu: true permission-enabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &aENABLED&7.' permission-disabled: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Currently &cDISABLED&7.' role-permission: type: REDSTONE_TORCH name: '&6Open Island' lore: - '&7Access to open the island to the public.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 painting: display-menu: true permission-enabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PAINTING name: '&6Painting' lore: - '&7Access to interact with paintings inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 paypal_show: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Paypal Show' lore: - '&7Access to check the island''s linked paypal.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_axolotl: display-menu: true permission-enabled: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: AXOLOTL_SPAWN_EGG name: '&6Pickup Axolotls' lore: - '&7Access to pickup axolotls using a water bucket inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_drops: display-menu: true permission-enabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: HOPPER name: '&6Pickup Drops' lore: - '&7Access to pickup items inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_fish: display-menu: true permission-enabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: COD name: '&6Pickup Fish' lore: - '&7Access to pickup fish using buckets inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 pickup_lectern_book: display-menu: true permission-enabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LECTERN name: '&6Pickup Lectern Book' lore: - '&7Access to pickup books out of lecterns inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 promote_members: display-menu: true permission-enabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: DIAMOND name: '&6Promote Members' lore: - '&7Access to promote members inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 rankup: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Upgrades Rankup' lore: - '&7Access to rankup island''s upgrades.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ratings_show: display-menu: true permission-enabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: type: NETHER_STAR name: '&6Ratings Show' lore: - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 saddle_entity: display-menu: true permission-enabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SADDLE name: '&6Saddle Entity' lore: - '&7Access to add saddle to entities inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sculk_sensor: display-menu: true permission-enabled: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: SCULK_SENSOR name: '&6Sculk Sensor' lore: - '&7Access to trigger sculk sensors inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_biome: display-menu: true permission-enabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_discord: display-menu: true permission-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: LIGHT_BLUE_TERRACOTTA name: '&6Set Discord' lore: - '&7Access to change the discord linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_home: display-menu: true permission-enabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Currently &cDISABLED&7.' role-permission: type: RED_BED name: '&6Set Home' lore: - '&7Access to change the home location of the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_paypal: display-menu: true permission-enabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BLUE_WOOL name: '&6Set Paypal' lore: - '&7Access to change the paypal linked to the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_permission: display-menu: true permission-enabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &aENABLED&7.' permission-disabled: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Currently &cDISABLED&7.' role-permission: type: REPEATER name: '&6Set Permission' lore: - '&7Access to change permissions for island members.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_role: display-menu: true permission-enabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_settings: display-menu: true permission-enabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &aENABLED&7.' permission-disabled: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Currently &cDISABLED&7.' role-permission: type: LEVER name: '&6Set Settings' lore: - '&7Access to change settings for islands.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 set_warp: display-menu: true permission-enabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Currently &cDISABLED&7.' role-permission: type: ENDER_EYE name: '&6Set Warp' lore: - '&7Access to set new warps for the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 sign_interact: display-menu: true permission-enabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: OAK_SIGN name: '&6Sign Interact' lore: - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner_break: display-menu: true permission-enabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP permission-disabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP role-permission: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' flags: - HIDE_ADDITIONAL_TOOLTIP has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 turtle_egg_tramping: display-menu: true permission-enabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: TURTLE_EGG name: '&6Turtle Eggs Tramping' lore: - '&7Access to tramp turtle eggs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 tamed_animal_damage: display-menu: true permission-enabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: BONE name: '&6Tamed Animal Damage' lore: - '&7Access to damage tamed animals inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 uncoop_member: display-menu: true permission-enabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLDEN_APPLE name: '&6Uncoop Member' lore: - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 use: display-menu: true permission-enabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: STONE_BUTTON name: '&6Use' lore: - '&7Access to use different blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 valuable_break: display-menu: true permission-enabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: GOLD_INGOT name: '&6Valuable Blocks Break' lore: - '&7Access to break valuable blocks inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 villager_trading: display-menu: true permission-enabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' name: '&6Villagers Trading' lore: - '&7Access to trade with villagers inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 wind_charge: display-menu: true permission-enabled: type: WIND_CHARGE name: '&6Wind Charge' lore: - '&7Access to use wind charges inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: type: WIND_CHARGE name: '&6Wind Charge' lore: - '&7Access to use wind charges inside the island.' - '&7Currently &cDISABLED&7.' role-permission: type: WIND_CHARGE name: '&6Wind Charge' lore: - '&7Access to use wind charges inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 withdraw_money: display-menu: true permission-enabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &aENABLED&7.' permission-disabled: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Currently &cDISABLED&7.' role-permission: type: EMERALD name: '&6Withdraw Money' lore: - '&7Access to withdraw money from the island''s bank.' - '&7Role: &e{}&7.' - '' - '{0}' has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/player-language.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lSelect Language...' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ # % * + ^ ~ 1 @' - '@ @ - = ! 2 3 @ @' - '@ @ @ @ @ @ @ @ @' items: '#': language: 'en-US' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNhYzk3NzRkYTEyMTcyNDg1MzJjZTE0N2Y3ODMxZjY3YTEyZmRjY2ExY2YwY2I0YjM4NDhkZTZiYzk0YjQifX19' name: '&eEnglish' lore: - '&7Change language to English.' '%': language: 'iw-IL' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWJhMDg2YTJjYzcyNzJjZjViYTQ5YzgwMjQ4NTQ2YzIyZTVlZjFiYWI1NDEyMGU4YThlNWQ5ZTc1YjZhIn19fQ==' name: '&eHebrew' lore: - '&7Change language to Hebrew.' '*': language: 'vi-VN' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE1N2I5ZDdkZDA0MTY5NDc4Y2ZkYjhkMGI2ZmQwYjhjODJiNjU2NmJiMjgzNzFlZTlhN2M3YzE2NzFhZDBiYiJ9fX0=' name: '&eVietnamese' lore: - '&7Change language to Vietnamese.' '+': language: 'pl-PL' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxYjJhZjhkMjMyMjI4MmZjZTRhMWFhNGYyNTdhNTJiNjhlMjdlYjMzNGY0YTE4MWZkOTc2YmFlNmQ4ZWIifX19' name: '&ePolish' lore: - '&7Change language to Polish.' '2': language: 'pt-BR' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0=' name: '&eBrazilian Portuguese' lore: - '&7Change language to Brazilian Portuguese.' '^': language: 'it-IT' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODVjZTg5MjIzZmE0MmZlMDZhZDY1ZDhkNDRjYTQxMmFlODk5YzgzMTMwOWQ2ODkyNGRmZTBkMTQyZmRiZWVhNCJ9fX0=' name: '&eItalian' lore: - '&7Change language to Italian.' '~': language: 'zh-CN' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2Y5YmMwMzVjZGM4MGYxYWI1ZTExOThmMjlmM2FkM2ZkZDJiNDJkOWE2OWFlYjY0ZGU5OTA2ODE4MDBiOThkYyJ9fX0=' name: '&eSimplified Chinese' lore: - '&7Change language to Simplified Chinese.' '1': language: 'ru-RU' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZlYWZlZjk4MGQ2MTE3ZGFiZTg5ODJhYzRiNDUwOTg4N2UyYzQ2MjFmNmE4ZmU1YzliNzM1YTgzZDc3NWFkIn19fQ==' name: '&eRussian' lore: - '&7Change language to Russian.' '-': language: 'fr-FR' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTEyNjlhMDY3ZWUzN2U2MzYzNWNhMWU3MjNiNjc2ZjEzOWRjMmRiZGRmZjk2YmJmZWY5OWQ4YjM1Yzk5NmJjIn19fQ==' name: '&eFrench' lore: - '&7Change language to French.' '=': language: 'es-ES' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJiZDQ1MjE5ODMzMDllMGFkNzZjMWVlMjk4NzQyODc5NTdlYzNkOTZmOGQ4ODkzMjRkYThjODg3ZTQ4NWVhOCJ9fX0=' name: '&eSpanish' lore: - '&7Change language to Spanish.' '!': language: 'de-DE' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWU3ODk5YjQ4MDY4NTg2OTdlMjgzZjA4NGQ5MTczZmU0ODc4ODY0NTM3NzQ2MjZiMjRiZDhjZmVjYzc3YjNmIn19fQ==' name: '&eGerman' lore: - '&7Change language to German.' '3': language: 'tr-TR' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ==' name: '&eTurkish' lore: - '&7Change language to Turkish.' sounds: '#': type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/player-language1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lSelect Language...' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ # % * + ^ ~ 1 @' - '@ @ - = ! 2 3 @ @' - '@ @ @ @ @ @ @ @ @' items: '#': language: 'en-US' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNhYzk3NzRkYTEyMTcyNDg1MzJjZTE0N2Y3ODMxZjY3YTEyZmRjY2ExY2YwY2I0YjM4NDhkZTZiYzk0YjQifX19' name: '&eEnglish' lore: - '&7Change language to English.' '%': language: 'iw-IL' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWJhMDg2YTJjYzcyNzJjZjViYTQ5YzgwMjQ4NTQ2YzIyZTVlZjFiYWI1NDEyMGU4YThlNWQ5ZTc1YjZhIn19fQ==' name: '&eHebrew' lore: - '&7Change language to Hebrew.' '*': language: 'vi-VN' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE1N2I5ZDdkZDA0MTY5NDc4Y2ZkYjhkMGI2ZmQwYjhjODJiNjU2NmJiMjgzNzFlZTlhN2M3YzE2NzFhZDBiYiJ9fX0=' name: '&eVietnamese' lore: - '&7Change language to Vietnamese.' '+': language: 'pl-PL' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxYjJhZjhkMjMyMjI4MmZjZTRhMWFhNGYyNTdhNTJiNjhlMjdlYjMzNGY0YTE4MWZkOTc2YmFlNmQ4ZWIifX19' name: '&ePolish' lore: - '&7Change language to Polish.' '2': language: 'pt-BR' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0=' name: '&eBrazilian Portuguese' lore: - '&7Change language to Brazilian Portuguese.' '^': language: 'it-IT' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODVjZTg5MjIzZmE0MmZlMDZhZDY1ZDhkNDRjYTQxMmFlODk5YzgzMTMwOWQ2ODkyNGRmZTBkMTQyZmRiZWVhNCJ9fX0=' name: '&eItalian' lore: - '&7Change language to Italian.' '~': language: 'zh-CN' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2Y5YmMwMzVjZGM4MGYxYWI1ZTExOThmMjlmM2FkM2ZkZDJiNDJkOWE2OWFlYjY0ZGU5OTA2ODE4MDBiOThkYyJ9fX0=' name: '&eSimplified Chinese' lore: - '&7Change language to Simplified Chinese.' '1': language: 'ru-RU' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZlYWZlZjk4MGQ2MTE3ZGFiZTg5ODJhYzRiNDUwOTg4N2UyYzQ2MjFmNmE4ZmU1YzliNzM1YTgzZDc3NWFkIn19fQ==' name: '&eRussian' lore: - '&7Change language to Russian.' '-': language: 'fr-FR' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTEyNjlhMDY3ZWUzN2U2MzYzNWNhMWU3MjNiNjc2ZjEzOWRjMmRiZGRmZjk2YmJmZWY5OWQ4YjM1Yzk5NmJjIn19fQ==' name: '&eFrench' lore: - '&7Change language to French.' '=': language: 'es-ES' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJiZDQ1MjE5ODMzMDllMGFkNzZjMWVlMjk4NzQyODc5NTdlYzNkOTZmOGQ4ODkzMjRkYThjODg3ZTQ4NWVhOCJ9fX0=' name: '&eSpanish' lore: - '&7Change language to Spanish.' '!': language: 'de-DE' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWU3ODk5YjQ4MDY4NTg2OTdlMjgzZjA4NGQ5MTczZmU0ODc4ODY0NTM3NzQ2MjZiMjRiZDhjZmVjYzc3YjNmIn19fQ==' name: '&eGerman' lore: - '&7Change language to German.' '3': language: 'tr-TR' type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ==' name: '&eTurkish' lore: - '&7Change language to Turkish.' sounds: '#': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/player-language1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lSelect Language...' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ # % * + ^ ~ 1 @' - '@ @ - = ! 2 3 @ @' - '@ @ @ @ @ @ @ @ @' items: '#': language: 'en-US' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNhYzk3NzRkYTEyMTcyNDg1MzJjZTE0N2Y3ODMxZjY3YTEyZmRjY2ExY2YwY2I0YjM4NDhkZTZiYzk0YjQifX19' name: '&eEnglish' lore: - '&7Change language to English.' '%': language: 'iw-IL' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWJhMDg2YTJjYzcyNzJjZjViYTQ5YzgwMjQ4NTQ2YzIyZTVlZjFiYWI1NDEyMGU4YThlNWQ5ZTc1YjZhIn19fQ==' name: '&eHebrew' lore: - '&7Change language to Hebrew.' '*': language: 'vi-VN' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE1N2I5ZDdkZDA0MTY5NDc4Y2ZkYjhkMGI2ZmQwYjhjODJiNjU2NmJiMjgzNzFlZTlhN2M3YzE2NzFhZDBiYiJ9fX0=' name: '&eVietnamese' lore: - '&7Change language to Vietnamese.' '+': language: 'pl-PL' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxYjJhZjhkMjMyMjI4MmZjZTRhMWFhNGYyNTdhNTJiNjhlMjdlYjMzNGY0YTE4MWZkOTc2YmFlNmQ4ZWIifX19' name: '&ePolish' lore: - '&7Change language to Polish.' '2': language: 'pt-BR' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0=' name: '&eBrazilian Portuguese' lore: - '&7Change language to Brazilian Portuguese.' '^': language: 'it-IT' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODVjZTg5MjIzZmE0MmZlMDZhZDY1ZDhkNDRjYTQxMmFlODk5YzgzMTMwOWQ2ODkyNGRmZTBkMTQyZmRiZWVhNCJ9fX0=' name: '&eItalian' lore: - '&7Change language to Italian.' '~': language: 'zh-CN' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2Y5YmMwMzVjZGM4MGYxYWI1ZTExOThmMjlmM2FkM2ZkZDJiNDJkOWE2OWFlYjY0ZGU5OTA2ODE4MDBiOThkYyJ9fX0=' name: '&eSimplified Chinese' lore: - '&7Change language to Simplified Chinese.' '1': language: 'ru-RU' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZlYWZlZjk4MGQ2MTE3ZGFiZTg5ODJhYzRiNDUwOTg4N2UyYzQ2MjFmNmE4ZmU1YzliNzM1YTgzZDc3NWFkIn19fQ==' name: '&eRussian' lore: - '&7Change language to Russian.' '-': language: 'fr-FR' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTEyNjlhMDY3ZWUzN2U2MzYzNWNhMWU3MjNiNjc2ZjEzOWRjMmRiZGRmZjk2YmJmZWY5OWQ4YjM1Yzk5NmJjIn19fQ==' name: '&eFrench' lore: - '&7Change language to French.' '=': language: 'es-ES' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJiZDQ1MjE5ODMzMDllMGFkNzZjMWVlMjk4NzQyODc5NTdlYzNkOTZmOGQ4ODkzMjRkYThjODg3ZTQ4NWVhOCJ9fX0=' name: '&eSpanish' lore: - '&7Change language to Spanish.' '!': language: 'de-DE' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWU3ODk5YjQ4MDY4NTg2OTdlMjgzZjA4NGQ5MTczZmU0ODc4ODY0NTM3NzQ2MjZiMjRiZDhjZmVjYzc3YjNmIn19fQ==' name: '&eGerman' lore: - '&7Change language to German.' '3': language: 'tr-TR' type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ==' name: '&eTurkish' lore: - '&7Change language to Turkish.' sounds: '#': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 '^': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/settings.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Settings' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '$': type: STAINED_GLASS_PANE data: 3 name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' settings: always_day: display-menu: true settings-enabled: type: STAINED_CLAY data: 4 name: '&6Always Day' lore: - '&7Set a day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: STAINED_CLAY data: 4 name: '&6Always Day' lore: - '&7Set a day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 always_middle_day: display-menu: true settings-enabled: type: STAINED_CLAY data: 1 name: '&6Always Middle Day' lore: - '&7Set a middle day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: STAINED_CLAY data: 1 name: '&6Always Middle Day' lore: - '&7Set a middle day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 always_night: display-menu: true settings-enabled: type: STAINED_CLAY data: 3 name: '&6Always Night' lore: - '&7Set a night time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: STAINED_CLAY data: 3 name: '&6Always Night' lore: - '&7Set a night time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 always_middle_night: display-menu: true settings-enabled: type: STAINED_CLAY data: 11 name: '&6Always Middle Night' lore: - '&7Set a middle night day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: STAINED_CLAY data: 11 name: '&6Always Middle Night' lore: - '&7Set a middle night day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 always_rain: display-menu: true settings-enabled: type: WATER_LILY name: '&6Always Rain' lore: - '&7Set a rainy weather on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WATER_LILY name: '&6Always Rain' lore: - '&7Set a rainy weather on your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 always_shiny: display-menu: true settings-enabled: type: DEAD_BUSH name: '&6Always Shiny' lore: - '&7Set a shiny weather on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: DEAD_BUSH name: '&6Always Shiny' lore: - '&7Set a shiny weather on your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 creeper_explosion: display-menu: true settings-enabled: type: SKULL_ITEM data: 4 name: '&6Creeper Explosion' lore: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SKULL_ITEM data: 4 name: '&6Creeper Explosion' lore: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 crops_growth: display-menu: true settings-enabled: type: SEEDS name: '&6Crops Growth' lore: - '&7Allow growth of crops inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SEEDS name: '&6Crops Growth' lore: - '&7Allow growth of crops inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 egg_lay: display-menu: true settings-enabled: type: EGG name: '&6Egg Lay' lore: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: EGG name: '&6Egg Lay' lore: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 enderman_grief: display-menu: true settings-enabled: type: ENDER_PEARL name: '&6Enderman Grief' lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: ENDER_PEARL name: '&6Enderman Grief' lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 fire_spread: display-menu: true settings-enabled: type: FLINT_AND_STEEL name: '&6Fire Spread' lore: - '&7Allow fire to spread inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: FLINT_AND_STEEL name: '&6Fire Spread' lore: - '&7Allow fire to spread inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 ghast_fireball: display-menu: true settings-enabled: type: FIREBALL name: '&6Ghast Fireball' lore: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: FIREBALL name: '&6Ghast Fireball' lore: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 lava_flow: display-menu: true settings-enabled: type: LAVA_BUCKET name: '&6Lava Flow' lore: - '&7Allow lava to flow inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: LAVA_BUCKET name: '&6Lava Flow' lore: - '&7Allow lava to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 natural_animals_spawn: display-menu: true settings-enabled: type: MONSTER_EGG data: 90 name: '&6Natural Animals Spawn' lore: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: MONSTER_EGG data: 90 name: '&6Natural Animals Spawn' lore: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 natural_monster_spawn: display-menu: true settings-enabled: type: MONSTER_EGG data: 54 name: '&6Natural Monster Spawn' lore: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: MONSTER_EGG data: 54 name: '&6Natural Monster Spawn' lore: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 pvp: display-menu: true settings-enabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES settings-disabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_animals_spawn: display-menu: true settings-enabled: type: MOB_SPAWNER name: '&6Spawner Animals Spawn' lore: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: MOB_SPAWNER name: '&6Spawner Animals Spawn' lore: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_monster_spawn: display-menu: true settings-enabled: type: MOB_SPAWNER name: '&6Spawner Monster Spawn' lore: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: MOB_SPAWNER name: '&6Spawner Monster Spawn' lore: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 tnt_explosion: display-menu: true settings-enabled: type: TNT name: '&6TNT Explosion' lore: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: TNT name: '&6TNT Explosion' lore: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 tree_growth: display-menu: true settings-enabled: type: SAPLING name: '&6Tree Growth' lore: - '&7Allow growth of trees inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SAPLING name: '&6Tree Growth' lore: - '&7Allow growth of trees inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 water_flow: display-menu: true settings-enabled: type: WATER_BUCKET name: '&6Water Flow' lore: - '&7Allow water to flow inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WATER_BUCKET name: '&6Water Flow' lore: - '&7Allow water to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 wither_explosion: display-menu: true settings-enabled: type: SKULL_ITEM data: 1 name: '&6Wither Explosion' lore: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SKULL_ITEM data: 1 name: '&6Wither Explosion' lore: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/settings1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Settings' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '$': type: STAINED_GLASS_PANE data: 3 name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' settings: always_day: display-menu: true settings-enabled: type: STAINED_CLAY data: 4 name: '&6Always Day' lore: - '&7Set a day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: STAINED_CLAY data: 4 name: '&6Always Day' lore: - '&7Set a day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_middle_day: display-menu: true settings-enabled: type: STAINED_CLAY data: 1 name: '&6Always Middle Day' lore: - '&7Set a middle day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: STAINED_CLAY data: 1 name: '&6Always Middle Day' lore: - '&7Set a middle day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_night: display-menu: true settings-enabled: type: STAINED_CLAY data: 3 name: '&6Always Night' lore: - '&7Set a night time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: STAINED_CLAY data: 3 name: '&6Always Night' lore: - '&7Set a night time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_middle_night: display-menu: true settings-enabled: type: STAINED_CLAY data: 11 name: '&6Always Middle Night' lore: - '&7Set a middle night day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: STAINED_CLAY data: 11 name: '&6Always Middle Night' lore: - '&7Set a middle night day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_rain: display-menu: true settings-enabled: type: WATER_LILY name: '&6Always Rain' lore: - '&7Set a rainy weather on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WATER_LILY name: '&6Always Rain' lore: - '&7Set a rainy weather on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_shiny: display-menu: true settings-enabled: type: DEAD_BUSH name: '&6Always Shiny' lore: - '&7Set a shiny weather on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: DEAD_BUSH name: '&6Always Shiny' lore: - '&7Set a shiny weather on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 creeper_explosion: display-menu: true settings-enabled: type: SKULL_ITEM data: 4 name: '&6Creeper Explosion' lore: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SKULL_ITEM data: 4 name: '&6Creeper Explosion' lore: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 crops_growth: display-menu: true settings-enabled: type: SEEDS name: '&6Crops Growth' lore: - '&7Allow growth of crops inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SEEDS name: '&6Crops Growth' lore: - '&7Allow growth of crops inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 egg_lay: display-menu: true settings-enabled: type: EGG name: '&6Egg Lay' lore: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: EGG name: '&6Egg Lay' lore: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 enderman_grief: display-menu: true settings-enabled: type: ENDER_PEARL name: '&6Enderman Grief' lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: ENDER_PEARL name: '&6Enderman Grief' lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fire_spread: display-menu: true settings-enabled: type: FLINT_AND_STEEL name: '&6Fire Spread' lore: - '&7Allow fire to spread inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: FLINT_AND_STEEL name: '&6Fire Spread' lore: - '&7Allow fire to spread inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ghast_fireball: display-menu: true settings-enabled: type: FIREBALL name: '&6Ghast Fireball' lore: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: FIREBALL name: '&6Ghast Fireball' lore: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 lava_flow: display-menu: true settings-enabled: type: LAVA_BUCKET name: '&6Lava Flow' lore: - '&7Allow lava to flow inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: LAVA_BUCKET name: '&6Lava Flow' lore: - '&7Allow lava to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 natural_animals_spawn: display-menu: true settings-enabled: type: MONSTER_EGG data: 90 name: '&6Natural Animals Spawn' lore: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: MONSTER_EGG data: 90 name: '&6Natural Animals Spawn' lore: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 natural_monster_spawn: display-menu: true settings-enabled: type: MONSTER_EGG data: 54 name: '&6Natural Monster Spawn' lore: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: MONSTER_EGG data: 54 name: '&6Natural Monster Spawn' lore: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 pvp: display-menu: true settings-enabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES settings-disabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_animals_spawn: display-menu: true settings-enabled: type: MOB_SPAWNER name: '&6Spawner Animals Spawn' lore: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: MOB_SPAWNER name: '&6Spawner Animals Spawn' lore: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_monster_spawn: display-menu: true settings-enabled: type: MOB_SPAWNER name: '&6Spawner Monster Spawn' lore: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: MOB_SPAWNER name: '&6Spawner Monster Spawn' lore: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 tnt_explosion: display-menu: true settings-enabled: type: TNT name: '&6TNT Explosion' lore: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: TNT name: '&6TNT Explosion' lore: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 tree_growth: display-menu: true settings-enabled: type: SAPLING name: '&6Tree Growth' lore: - '&7Allow growth of trees inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SAPLING name: '&6Tree Growth' lore: - '&7Allow growth of trees inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 water_flow: display-menu: true settings-enabled: type: WATER_BUCKET name: '&6Water Flow' lore: - '&7Allow water to flow inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WATER_BUCKET name: '&6Water Flow' lore: - '&7Allow water to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 wither_explosion: display-menu: true settings-enabled: type: SKULL_ITEM data: 1 name: '&6Wither Explosion' lore: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SKULL_ITEM data: 1 name: '&6Wither Explosion' lore: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/settings1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Settings' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '$': type: CYAN_STAINED_GLASS_PANE name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' settings: always_day: display-menu: true settings-enabled: type: YELLOW_TERRACOTTA name: '&6Always Day' lore: - '&7Set a day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: YELLOW_TERRACOTTA name: '&6Always Day' lore: - '&7Set a day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_middle_day: display-menu: true settings-enabled: type: ORANGE_TERRACOTTA name: '&6Always Middle Day' lore: - '&7Set a middle day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: ORANGE_TERRACOTTA name: '&6Always Middle Day' lore: - '&7Set a middle day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_night: display-menu: true settings-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Always Night' lore: - '&7Set a night time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Always Night' lore: - '&7Set a night time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_middle_night: display-menu: true settings-enabled: type: BLUE_TERRACOTTA name: '&6Always Middle Night' lore: - '&7Set a middle night day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: BLUE_TERRACOTTA name: '&6Always Middle Night' lore: - '&7Set a middle night day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_rain: display-menu: true settings-enabled: type: LILY_PAD name: '&6Always Rain' lore: - '&7Set a rainy weather on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: LILY_PAD name: '&6Always Rain' lore: - '&7Set a rainy weather on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_shiny: display-menu: true settings-enabled: type: DEAD_BUSH name: '&6Always Shiny' lore: - '&7Set a shiny weather on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: DEAD_BUSH name: '&6Always Shiny' lore: - '&7Set a shiny weather on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 creeper_explosion: display-menu: true settings-enabled: type: CREEPER_HEAD name: '&6Creeper Explosion' lore: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: CREEPER_HEAD name: '&6Creeper Explosion' lore: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 crops_growth: display-menu: true settings-enabled: type: WHEAT_SEEDS name: '&6Crops Growth' lore: - '&7Allow growth of crops inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WHEAT_SEEDS name: '&6Crops Growth' lore: - '&7Allow growth of crops inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 egg_lay: display-menu: true settings-enabled: type: EGG name: '&6Egg Lay' lore: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: EGG name: '&6Egg Lay' lore: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 enderman_grief: display-menu: true settings-enabled: type: ENDER_PEARL name: '&6Enderman Grief' lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: ENDER_PEARL name: '&6Enderman Grief' lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fire_spread: display-menu: true settings-enabled: type: FLINT_AND_STEEL name: '&6Fire Spread' lore: - '&7Allow fire to spread inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: FLINT_AND_STEEL name: '&6Fire Spread' lore: - '&7Allow fire to spread inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ghast_fireball: display-menu: true settings-enabled: type: FIRE_CHARGE name: '&6Ghast Fireball' lore: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: FIRE_CHARGE name: '&6Ghast Fireball' lore: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 lava_flow: display-menu: true settings-enabled: type: LAVA_BUCKET name: '&6Lava Flow' lore: - '&7Allow lava to flow inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: LAVA_BUCKET name: '&6Lava Flow' lore: - '&7Allow lava to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 natural_animals_spawn: display-menu: true settings-enabled: type: PIG_SPAWN_EGG name: '&6Natural Animals Spawn' lore: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: PIG_SPAWN_EGG name: '&6Natural Animals Spawn' lore: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 natural_monster_spawn: display-menu: true settings-enabled: type: ZOMBIE_SPAWN_EGG name: '&6Natural Monster Spawn' lore: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: ZOMBIE_SPAWN_EGG name: '&6Natural Monster Spawn' lore: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 pvp: display-menu: true settings-enabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES settings-disabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_animals_spawn: display-menu: true settings-enabled: type: SPAWNER name: '&6Spawner Animals Spawn' lore: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SPAWNER name: '&6Spawner Animals Spawn' lore: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_monster_spawn: display-menu: true settings-enabled: type: SPAWNER name: '&6Spawner Monster Spawn' lore: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: SPAWNER name: '&6Spawner Monster Spawn' lore: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 tnt_explosion: display-menu: true settings-enabled: type: TNT name: '&6TNT Explosion' lore: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: TNT name: '&6TNT Explosion' lore: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 tree_growth: display-menu: true settings-enabled: type: OAK_SAPLING name: '&6Tree Growth' lore: - '&7Allow growth of trees inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: OAK_SAPLING name: '&6Tree Growth' lore: - '&7Allow growth of trees inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 water_flow: display-menu: true settings-enabled: type: WATER_BUCKET name: '&6Water Flow' lore: - '&7Allow water to flow inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WATER_BUCKET name: '&6Water Flow' lore: - '&7Allow water to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 wither_explosion: display-menu: true settings-enabled: type: WITHER_SKELETON_SKULL name: '&6Wither Explosion' lore: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WITHER_SKELETON_SKULL name: '&6Wither Explosion' lore: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/settings1_20.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Settings' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ @ @ @ @ @ @ @ $' - '$ $ % $ * $ ^ $ $' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '$': type: CYAN_STAINED_GLASS_PANE name: '&f' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' settings: always_day: display-menu: true settings-enabled: type: YELLOW_TERRACOTTA name: '&6Always Day' lore: - '&7Set a day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: YELLOW_TERRACOTTA name: '&6Always Day' lore: - '&7Set a day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_middle_day: display-menu: true settings-enabled: type: ORANGE_TERRACOTTA name: '&6Always Middle Day' lore: - '&7Set a middle day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: ORANGE_TERRACOTTA name: '&6Always Middle Day' lore: - '&7Set a middle day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_night: display-menu: true settings-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Always Night' lore: - '&7Set a night time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Always Night' lore: - '&7Set a night time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_middle_night: display-menu: true settings-enabled: type: BLUE_TERRACOTTA name: '&6Always Middle Night' lore: - '&7Set a middle night day time on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: BLUE_TERRACOTTA name: '&6Always Middle Night' lore: - '&7Set a middle night day time on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_rain: display-menu: true settings-enabled: type: LILY_PAD name: '&6Always Rain' lore: - '&7Set a rainy weather on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: LILY_PAD name: '&6Always Rain' lore: - '&7Set a rainy weather on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 always_shiny: display-menu: true settings-enabled: type: DEAD_BUSH name: '&6Always Shiny' lore: - '&7Set a shiny weather on your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: DEAD_BUSH name: '&6Always Shiny' lore: - '&7Set a shiny weather on your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 creeper_explosion: display-menu: true settings-enabled: type: CREEPER_HEAD name: '&6Creeper Explosion' lore: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: CREEPER_HEAD name: '&6Creeper Explosion' lore: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 crops_growth: display-menu: true settings-enabled: type: WHEAT_SEEDS name: '&6Crops Growth' lore: - '&7Allow growth of crops inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WHEAT_SEEDS name: '&6Crops Growth' lore: - '&7Allow growth of crops inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 egg_lay: display-menu: true settings-enabled: type: EGG name: '&6Egg Lay' lore: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: EGG name: '&6Egg Lay' lore: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 enderman_grief: display-menu: true settings-enabled: type: ENDER_PEARL name: '&6Enderman Grief' lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: ENDER_PEARL name: '&6Enderman Grief' lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 fire_spread: display-menu: true settings-enabled: type: FLINT_AND_STEEL name: '&6Fire Spread' lore: - '&7Allow fire to spread inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: FLINT_AND_STEEL name: '&6Fire Spread' lore: - '&7Allow fire to spread inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ghast_fireball: display-menu: true settings-enabled: type: FIRE_CHARGE name: '&6Ghast Fireball' lore: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: FIRE_CHARGE name: '&6Ghast Fireball' lore: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 lava_flow: display-menu: true settings-enabled: type: LAVA_BUCKET name: '&6Lava Flow' lore: - '&7Allow lava to flow inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: LAVA_BUCKET name: '&6Lava Flow' lore: - '&7Allow lava to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 natural_animals_spawn: display-menu: true settings-enabled: type: PIG_SPAWN_EGG name: '&6Natural Animals Spawn' lore: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: PIG_SPAWN_EGG name: '&6Natural Animals Spawn' lore: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 natural_monster_spawn: display-menu: true settings-enabled: type: ZOMBIE_SPAWN_EGG name: '&6Natural Monster Spawn' lore: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &aENABLED&7.' settings-disabled: type: ZOMBIE_SPAWN_EGG name: '&6Natural Monster Spawn' lore: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 pvp: display-menu: true settings-enabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ATTRIBUTES settings-disabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_animals_spawn: display-menu: true settings-enabled: type: SPAWNER name: '&6Spawner Animals Spawn' lore: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP settings-disabled: type: SPAWNER name: '&6Spawner Animals Spawn' lore: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_monster_spawn: display-menu: true settings-enabled: type: SPAWNER name: '&6Spawner Monster Spawn' lore: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &aENABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP settings-disabled: type: SPAWNER name: '&6Spawner Monster Spawn' lore: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 tnt_explosion: display-menu: true settings-enabled: type: TNT name: '&6TNT Explosion' lore: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: TNT name: '&6TNT Explosion' lore: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 tree_growth: display-menu: true settings-enabled: type: OAK_SAPLING name: '&6Tree Growth' lore: - '&7Allow growth of trees inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: OAK_SAPLING name: '&6Tree Growth' lore: - '&7Allow growth of trees inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 water_flow: display-menu: true settings-enabled: type: WATER_BUCKET name: '&6Water Flow' lore: - '&7Allow water to flow inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WATER_BUCKET name: '&6Water Flow' lore: - '&7Allow water to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 wither_explosion: display-menu: true settings-enabled: type: WITHER_SKELETON_SKULL name: '&6Wither Explosion' lore: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &aENABLED&7.' settings-disabled: type: WITHER_SKELETON_SKULL name: '&6Wither Explosion' lore: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/top-islands.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lTop Islands' previous-menu: true pattern: - '~ ~ ~ ~ ~ ~ ~ ~ ~' - '@ % @ @ @ # @ @ @' - '@ * @ @ # # # @ @' - '@ ^ @ # # # # # @' - '@ & @ @ @ $ @ @ @' - '~ ~ ! ~ - ~ + ~ ~' slots: '#' previous-page: '!' current-page: '-' next-page: '+' player-island: '$' sort-glow-when-selected: true items: '#': island: type: SKULL_ITEM data: 3 name: '&e&l[!] Island: &6&n{0}&7 (#{1})' lore: - '&7' - '&6&l* &e&lIsland Level &7{2}' - '&7' - '&6&l* &e&lPlace &7#{1}' - '&6&l* &e&lWorth &7${3}' - '&6&l* &e&lRating {8} &7({9})' - '&6&l* &e&lPlayers &7{10}' - '&7' - '&6&l* &e&lMembers:' - '{4}:&f - &7{}' - '&7' - '&7&o(( &f&oLeft-Click &7&oto view their items. ))' - '&7&o(( &f&oRight-Click &7&oto teleport to island warp. ))' no-island: type: SKULL_ITEM data: 3 name: '&cInvalid Island' '%': type: DIAMOND sorting-type: 'WORTH' name: '&6Sort by Worth' '*': type: GOLD_INGOT sorting-type: 'LEVEL' name: '&6Sort by Level' '^': type: EMERALD sorting-type: 'RATING' name: '&6Sort by Rating' '&': type: SKULL_ITEM data: 3 sorting-type: 'PLAYERS' name: '&6Sort by Players' '!': type: PAPER name: '{0}Previous Page' '-': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '+': type: PAPER name: '{0}Next Page' '~': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/top-islands1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lTop Islands' previous-menu: true pattern: - '~ ~ ~ ~ ~ ~ ~ ~ ~' - '@ % @ @ @ # @ @ @' - '@ * @ @ # # # @ @' - '@ ^ @ # # # # # @' - '@ & @ @ @ $ @ @ @' - '~ ~ ! ~ - ~ + ~ ~' slots: '#' previous-page: '!' current-page: '-' next-page: '+' player-island: '$' sort-glow-when-selected: true items: '#': island: type: SKULL_ITEM data: 3 name: '&e&l[!] Island: &6&n{0}&7 (#{1})' lore: - '&7' - '&6&l* &e&lIsland Level &7{2}' - '&7' - '&6&l* &e&lPlace &7#{1}' - '&6&l* &e&lWorth &7${3}' - '&6&l* &e&lRating {8} &7({9})' - '&6&l* &e&lPlayers &7{10}' - '&7' - '&6&l* &e&lMembers:' - '{4}:&f - &7{}' - '&7' - '&7&o(( &f&oLeft-Click &7&oto view their items. ))' - '&7&o(( &f&oRight-Click &7&oto teleport to island warp. ))' no-island: type: SKULL_ITEM data: 3 name: '&cInvalid Island' '%': type: DIAMOND sorting-type: 'WORTH' name: '&6Sort by Worth' '*': type: GOLD_INGOT sorting-type: 'LEVEL' name: '&6Sort by Level' '^': type: EMERALD sorting-type: 'RATING' name: '&6Sort by Rating' '&': type: SKULL_ITEM data: 3 sorting-type: 'PLAYERS' name: '&6Sort by Players' '!': type: PAPER name: '{0}Previous Page' '-': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '+': type: PAPER name: '{0}Next Page' '~': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/top-islands1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lTop Islands' previous-menu: true pattern: - '~ ~ ~ ~ ~ ~ ~ ~ ~' - '@ % @ @ @ # @ @ @' - '@ * @ @ # # # @ @' - '@ ^ @ # # # # # @' - '@ & @ @ @ $ @ @ @' - '~ ~ ! ~ - ~ + ~ ~' slots: '#' previous-page: '!' current-page: '-' next-page: '+' player-island: '$' sort-glow-when-selected: true items: '#': island: type: PLAYER_HEAD name: '&e&l[!] Island: &6&n{0}&7 (#{1})' lore: - '&7' - '&6&l* &e&lIsland Level &7{2}' - '&7' - '&6&l* &e&lPlace &7#{1}' - '&6&l* &e&lWorth &7${3}' - '&6&l* &e&lRating {8} &7({9})' - '&6&l* &e&lPlayers &7{10}' - '&7' - '&6&l* &e&lMembers:' - '{4}:&f - &7{}' - '&7' - '&7&o(( &f&oLeft-Click &7&oto view their items. ))' - '&7&o(( &f&oRight-Click &7&oto teleport to island warp. ))' no-island: type: PLAYER_HEAD name: '&cInvalid Island' '%': type: DIAMOND sorting-type: 'WORTH' name: '&6Sort by Worth' '*': type: GOLD_INGOT sorting-type: 'LEVEL' name: '&6Sort by Level' '^': type: EMERALD sorting-type: 'RATING' name: '&6Sort by Rating' '&': type: PLAYER_HEAD sorting-type: 'PLAYERS' name: '&6Sort by Players' '!': type: PAPER name: '{0}Previous Page' '-': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '+': type: PAPER name: '{0}Next Page' '~': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/unique-visitors.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Unique Visitors ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&7Island Owner: {1}' - '&7Last Time Joined: {3}' - '' - '&7Left-Click to expel the player.' - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/unique-visitors1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Unique Visitors ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&7Island Owner: {1}' - '&7Last Time Joined: {3}' - '' - '&7Left-Click to expel the player.' - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/unique-visitors1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Unique Visitors ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' items: '@': type: PLAYER_HEAD name: '&e{0}' lore: - '&7Island Owner: {1}' - '&7Last Time Joined: {3}' - '' - '&7Left-Click to expel the player.' - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/upgrades.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Upgrades' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '# # @ # % # ^ # #' - '# # # ! # + # # #' - '# # * # ~ # & # #' - '$ $ $ $ $ $ $ $ $' items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' upgrades: hoppers-limit: item: '@' '1': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '2': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '3': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '4': has-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the hoppers limit!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the hoppers limit!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 crop-growth: item: '%' '1': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 2' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 2' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '2': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 3' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 3' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '3': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 4' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 4' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '4': has-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the crop growth!' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the crop growth!' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 spawner-rates: item: '^' '1': has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e2' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e2' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '2': has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e3' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e3' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '3': has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e4' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e4' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '4': has-next-level: type: MOB_SPAWNER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the spawner rates!' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 no-next-level: type: MOB_SPAWNER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the spawner rates!' flags: - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 mob-drops: item: '*' '1': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e2' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e2' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '2': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e3' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e3' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '3': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e4' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e4' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '4': has-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the mob drops!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the mob drops!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 members-limit: item: '~' '1': has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e2' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e2' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '2': has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e3' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e3' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '3': has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e4' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e4' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '4': has-next-level: type: SKULL_ITEM data: 3 name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the members limit!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 no-next-level: type: SKULL_ITEM data: 3 name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the members limit!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 border-size: item: '!' '1': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e2' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e2' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '2': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e3' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e3' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '3': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e4' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e4' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '4': has-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the border size!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the border size!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 generator-rates: item: '+' '1': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e2' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f92% Stone' - ' &7 - &f5% Coal Ore' - ' &7 - &f3% Redstone Ore' - '&7' - '&3Price: &f$25,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e2' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f92% Stone' - ' &7 - &f5% Coal Ore' - ' &7 - &f3% Redstone Ore' - '&7' - '&3Price: &f$25,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '2': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e3' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f80% Stone' - ' &7 - &f8% Coal Ore' - ' &7 - &f6% Redstone Ore' - ' &7 - &f4% Lapis Ore' - ' &7 - &f2% Iron Ore' - '&7' - '&3Price: &f$75,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e3' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f80% Stone' - ' &7 - &f8% Coal Ore' - ' &7 - &f6% Redstone Ore' - ' &7 - &f4% Lapis Ore' - ' &7 - &f2% Iron Ore' - '&7' - '&3Price: &f$75,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '3': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e4' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f65% Stone' - ' &7 - &f10% Coal Ore' - ' &7 - &f9% Redstone Ore' - ' &7 - &f6% Lapis Ore' - ' &7 - &f4% Iron Ore' - ' &7 - &f3% Gold Ore' - ' &7 - &f2% Diamond Ore' - ' &7 - &f1% Emerald Ore' - '&7' - '&3Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e4' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f65% Stone' - ' &7 - &f10% Coal Ore' - ' &7 - &f9% Redstone Ore' - ' &7 - &f6% Lapis Ore' - ' &7 - &f4% Iron Ore' - ' &7 - &f3% Gold Ore' - ' &7 - &f2% Diamond Ore' - ' &7 - &f1% Emerald Ore' - '&7' - '&3Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '4': has-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the generator rates!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the generator rates!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 minecarts-limit: item: '&' '1': has-next-level: type: MINECART name: '&d&lMinecart Increase &a(Available)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '2': has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '3': has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 '4': has-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the minecarts limit!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the minecarts limit!' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/upgrades1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Upgrades' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '# # @ # % # ^ # #' - '# # # ! # + # # #' - '# # * # ~ # & # #' - '$ $ $ $ $ $ $ $ $' items: '$': type: STAINED_GLASS_PANE data: 15 name: '&f' upgrades: hoppers-limit: item: '@' '1': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the hoppers limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the hoppers limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 crop-growth: item: '%' '1': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 2' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 2' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 3' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 3' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 4' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 4' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the crop growth!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the crop growth!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner-rates: item: '^' '1': has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e2' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e2' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e3' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e3' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e4' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e4' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: MOB_SPAWNER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the spawner rates!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: MOB_SPAWNER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the spawner rates!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 mob-drops: item: '*' '1': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e2' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e2' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e3' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e3' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e4' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e4' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the mob drops!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the mob drops!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 members-limit: item: '~' '1': has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e2' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e2' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e3' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e3' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e4' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e4' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: SKULL_ITEM data: 3 name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the members limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: SKULL_ITEM data: 3 name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the members limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 border-size: item: '!' '1': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e2' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e2' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e3' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e3' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e4' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e4' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the border size!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the border size!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 generator-rates: item: '+' '1': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e2' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f92% Stone' - ' &7 - &f5% Coal Ore' - ' &7 - &f3% Redstone Ore' - '&7' - '&3Price: &f$25,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e2' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f92% Stone' - ' &7 - &f5% Coal Ore' - ' &7 - &f3% Redstone Ore' - '&7' - '&3Price: &f$25,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e3' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f80% Stone' - ' &7 - &f8% Coal Ore' - ' &7 - &f6% Redstone Ore' - ' &7 - &f4% Lapis Ore' - ' &7 - &f2% Iron Ore' - '&7' - '&3Price: &f$75,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e3' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f80% Stone' - ' &7 - &f8% Coal Ore' - ' &7 - &f6% Redstone Ore' - ' &7 - &f4% Lapis Ore' - ' &7 - &f2% Iron Ore' - '&7' - '&3Price: &f$75,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e4' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f65% Stone' - ' &7 - &f10% Coal Ore' - ' &7 - &f9% Redstone Ore' - ' &7 - &f6% Lapis Ore' - ' &7 - &f4% Iron Ore' - ' &7 - &f3% Gold Ore' - ' &7 - &f2% Diamond Ore' - ' &7 - &f1% Emerald Ore' - '&7' - '&3Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e4' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f65% Stone' - ' &7 - &f10% Coal Ore' - ' &7 - &f9% Redstone Ore' - ' &7 - &f6% Lapis Ore' - ' &7 - &f4% Iron Ore' - ' &7 - &f3% Gold Ore' - ' &7 - &f2% Diamond Ore' - ' &7 - &f1% Emerald Ore' - '&7' - '&3Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the generator rates!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the generator rates!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecarts-limit: item: '&' '1': has-next-level: type: MINECART name: '&d&lMinecart Increase &a(Available)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the minecarts limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the minecarts limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/upgrades1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Upgrades' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '# # @ # % # ^ # #' - '# # # ! # + # # #' - '# # * # ~ # & # #' - '$ $ $ $ $ $ $ $ $' items: '$': type: BLACK_STAINED_GLASS_PANE name: '&f' upgrades: hoppers-limit: item: '@' '1': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the hoppers limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the hoppers limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 crop-growth: item: '%' '1': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 2' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 2' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 3' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 3' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 4' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 4' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the crop growth!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the crop growth!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner-rates: item: '^' '1': has-next-level: type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e2' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e2' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e3' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e3' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e4' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e4' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: SPAWNER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the spawner rates!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: SPAWNER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the spawner rates!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 mob-drops: item: '*' '1': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e2' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e2' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e3' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e3' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e4' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e4' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the mob drops!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the mob drops!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 members-limit: item: '~' '1': has-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e2' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e2' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e3' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e3' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e4' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e4' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: PLAYER_HEAD name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the members limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: PLAYER_HEAD name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the members limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 border-size: item: '!' '1': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e2' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e2' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e3' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e3' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e4' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e4' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the border size!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the border size!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 generator-rates: item: '+' '1': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e2' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f92% Stone' - ' &7 - &f5% Coal Ore' - ' &7 - &f3% Redstone Ore' - '&7' - '&3Price: &f$25,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e2' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f92% Stone' - ' &7 - &f5% Coal Ore' - ' &7 - &f3% Redstone Ore' - '&7' - '&3Price: &f$25,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e3' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f80% Stone' - ' &7 - &f8% Coal Ore' - ' &7 - &f6% Redstone Ore' - ' &7 - &f4% Lapis Ore' - ' &7 - &f2% Iron Ore' - '&7' - '&3Price: &f$75,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e3' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f80% Stone' - ' &7 - &f8% Coal Ore' - ' &7 - &f6% Redstone Ore' - ' &7 - &f4% Lapis Ore' - ' &7 - &f2% Iron Ore' - '&7' - '&3Price: &f$75,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e4' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f65% Stone' - ' &7 - &f10% Coal Ore' - ' &7 - &f9% Redstone Ore' - ' &7 - &f6% Lapis Ore' - ' &7 - &f4% Iron Ore' - ' &7 - &f3% Gold Ore' - ' &7 - &f2% Diamond Ore' - ' &7 - &f1% Emerald Ore' - '&7' - '&3Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e4' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f65% Stone' - ' &7 - &f10% Coal Ore' - ' &7 - &f9% Redstone Ore' - ' &7 - &f6% Lapis Ore' - ' &7 - &f4% Iron Ore' - ' &7 - &f3% Gold Ore' - ' &7 - &f2% Diamond Ore' - ' &7 - &f1% Emerald Ore' - '&7' - '&3Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the generator rates!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the generator rates!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecarts-limit: item: '&' '1': has-next-level: type: MINECART name: '&d&lMinecart Increase &a(Available)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the minecarts limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the minecarts limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/upgrades1_20.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Upgrades' previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - '# # @ # % # ^ # #' - '# # # ! # + # # #' - '# # * # ~ # & # #' - '$ $ $ $ $ $ $ $ $' items: '$': type: BLACK_STAINED_GLASS_PANE name: '&f' upgrades: hoppers-limit: item: '@' '1': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the hopper upgrade' - '&7will increase your island''s' - '&7max hoppers limit.' - '&7' - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the hoppers limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the hoppers limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 crop-growth: item: '%' '1': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 2' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 2' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 3' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 3' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: - '&7' - '&eNext Level: 4' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: - '&7' - '&eNext Level: 4' - '&7' - '&7Purchasing the growth upgrade' - '&7gives all crops within your island' - '&7increased growth speed.' - '&7' - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the crop growth!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the crop growth!' flags: - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 spawner-rates: item: '^' '1': has-next-level: type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e2' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e2' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e3' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e3' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: - '&7' - '&bNext Level: &e4' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: - '&7' - '&bNext Level: &e4' - '&7' - '&7Purchasing the spawner upgrade' - '&7gives all spawners within your island' - '&7increased spawn speed.' - '&7' - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - '&aClick to purchase upgrade.' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: SPAWNER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the spawner rates!' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: SPAWNER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the spawner rates!' flags: - HIDE_ADDITIONAL_TOOLTIP sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 mob-drops: item: '*' '1': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e2' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e2' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e3' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e3' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: - '&7' - '&4Next Level: &e4' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: - '&7' - '&4Next Level: &e4' - '&7' - '&7Purchasing the drops upgrade' - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the mob drops!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the mob drops!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 members-limit: item: '~' '1': has-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e2' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e2' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e3' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e3' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: - '&7' - '&2Next Level: &e4' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: - '&7' - '&2Next Level: &e4' - '&7' - '&7Purchasing the members upgrade' - '&7will increase the maximum allowed' - '&7members in your island.' - '&7' - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: PLAYER_HEAD name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the members limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: PLAYER_HEAD name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the members limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 border-size: item: '!' '1': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e2' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e2' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e3' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e3' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: - '&7' - '&9Next Level: &e4' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: - '&7' - '&9Next Level: &e4' - '&7' - '&7Purchasing the border upgrade' - '&7will increase the radius' - '&7of your island.' - '&7' - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the border size!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the border size!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 generator-rates: item: '+' '1': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e2' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f92% Stone' - ' &7 - &f5% Coal Ore' - ' &7 - &f3% Redstone Ore' - '&7' - '&3Price: &f$25,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e2' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f92% Stone' - ' &7 - &f5% Coal Ore' - ' &7 - &f3% Redstone Ore' - '&7' - '&3Price: &f$25,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e3' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f80% Stone' - ' &7 - &f8% Coal Ore' - ' &7 - &f6% Redstone Ore' - ' &7 - &f4% Lapis Ore' - ' &7 - &f2% Iron Ore' - '&7' - '&3Price: &f$75,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e3' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f80% Stone' - ' &7 - &f8% Coal Ore' - ' &7 - &f6% Redstone Ore' - ' &7 - &f4% Lapis Ore' - ' &7 - &f2% Iron Ore' - '&7' - '&3Price: &f$75,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: - '&7' - '&3Next Level: &e4' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f65% Stone' - ' &7 - &f10% Coal Ore' - ' &7 - &f9% Redstone Ore' - ' &7 - &f6% Lapis Ore' - ' &7 - &f4% Iron Ore' - ' &7 - &f3% Gold Ore' - ' &7 - &f2% Diamond Ore' - ' &7 - &f1% Emerald Ore' - '&7' - '&3Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: - '&7' - '&3Next Level: &e4' - '&7' - '&7Purchasing the generator upgrade' - '&7will increase rates of ores from' - '&7cobblestone generators in your island.' - '&7' - '&3Rates:' - ' &7 - &f65% Stone' - ' &7 - &f10% Coal Ore' - ' &7 - &f9% Redstone Ore' - ' &7 - &f6% Lapis Ore' - ' &7 - &f4% Iron Ore' - ' &7 - &f3% Gold Ore' - ' &7 - &f2% Diamond Ore' - ' &7 - &f1% Emerald Ore' - '&7' - '&3Price: &f$150,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the generator rates!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the generator rates!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 minecarts-limit: item: '&' '1': has-next-level: type: MINECART name: '&d&lMinecart Increase &a(Available)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e2' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '2': has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e3' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '3': has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: - '&7' - '&dNext Level: &e4' - '&7' - '&7Purchasing the minecart upgrade' - '&7will increase your island''s' - '&7max minecarts limit.' - '&7' - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 '4': has-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the minecarts limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 no-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - '&7You have reached the maximum' - '&7level of the minecarts limit!' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/values.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '{0} &n${1}' previous-menu: true pattern: - '& & & & & & & & &' - '% $ A B C D E F %' - '% % G H I J K L %' - '% * M N O P Q R %' - '% % S T U V W X %' - '& & & & & & & & &' items: '&': type: STAINED_GLASS_PANE data: 15 name: '&f' '$': type: MOB_SPAWNER name: '&e&lSPAWNERS ->' flags: - HIDE_ATTRIBUTES '*': type: BOOK_AND_QUILL name: '&e&lITEMS ->' 'A': block: MOB_SPAWNER:IRON_GOLEM type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19' name: '&e&l[!] &7Iron Golem Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'B': block: MOB_SPAWNER:BLAZE type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ==' name: '&e&l[!] &7Blaze Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'C': block: MOB_SPAWNER:SPIDER type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19' name: '&e&l[!] &7Spider Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'D': block: MOB_SPAWNER:COW type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19' name: '&e&l[!] &7Cow Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'E': block: MOB_SPAWNER:ZOMBIE type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ==' name: '&e&l[!] &7Zombie Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'F': block: MOB_SPAWNER:SKELETON type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ==' name: '&e&l[!] &7Skeleton Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'G': block: MOB_SPAWNER:CREEPER type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0=' name: '&e&l[!] &7Creeper Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'H': block: MOB_SPAWNER:PIG_ZOMBIE type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRlOWM2ZTk4NTgyZmZkOGZmOGZlYjMzMjJjZDE4NDljNDNmYjE2YjE1OGFiYjExY2E3YjQyZWRhNzc0M2ViIn19fQ==' name: '&e&l[!] &7Zombie Pigman Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'I': block: MOB_SPAWNER:GHAST type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19' name: '&e&l[!] &7Ghast Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'J': block: MOB_SPAWNER:SLIME type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ==' name: '&e&l[!] &7Slime Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'K': block: MOB_SPAWNER:GUARDIAN type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ==' name: '&e&l[!] &7Guardian Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'L': block: MOB_SPAWNER:SQUID type: SKULL_ITEM data: 3 skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ==' name: '&e&l[!] &7Squid Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'M': block: HOPPER type: HOPPER name: '&e&l[!] &7Hopper' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'N': block: BEACON type: BEACON name: '&e&l[!] &7Beacon' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'O': block: IRON_BLOCK type: IRON_BLOCK name: '&e&l[!] &7Iron Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'P': block: GOLD_BLOCK type: GOLD_BLOCK name: '&e&l[!] &7Gold Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'Q': block: DIAMOND_BLOCK type: DIAMOND_BLOCK name: '&e&l[!] &7Diamond Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'R': block: EMERALD_BLOCK type: EMERALD_BLOCK name: '&e&l[!] &7Emerald Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'S': block: BEDROCK type: BEDROCK name: '&e&l[!] &7Bedrock' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'T': block: ENDER_CHEST type: ENDER_CHEST name: '&e&l[!] &7Ender Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'U': block: DRAGON_EGG type: DRAGON_EGG name: '&e&l[!] &7Dragon Egg' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'V': block: CHEST type: CHEST name: '&e&l[!] &7Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'W': block: TRAPPED_CHEST type: TRAPPED_CHEST name: '&e&l[!] &7Trapped Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'X': block: ENCHANTMENT_TABLE type: ENCHANTMENT_TABLE name: '&e&l[!] &7Enchantment Table' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' ================================================ FILE: src/main/resources/menus/values1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '{0} &n${1}' previous-menu: true pattern: - '& & & & & & & & &' - '% $ A B C D E F %' - '% % G H I J K L %' - '% * M N O P Q R %' - '% % S T U V W X %' - '& & & & & & & & &' items: '&': type: BLACK_STAINED_GLASS_PANE name: '&f' '$': type: SPAWNER name: '&e&lSPAWNERS ->' flags: - HIDE_ATTRIBUTES '*': type: WRITABLE_BOOK name: '&e&lITEMS ->' 'A': block: SPAWNER:IRON_GOLEM type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19' name: '&e&l[!] &7Iron Golem Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'B': block: SPAWNER:BLAZE type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ==' name: '&e&l[!] &7Blaze Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'C': block: SPAWNER:SPIDER type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19' name: '&e&l[!] &7Spider Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'D': block: SPAWNER:COW type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19' name: '&e&l[!] &7Cow Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'E': block: SPAWNER:ZOMBIE type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ==' name: '&e&l[!] &7Zombie Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'F': block: SPAWNER:SKELETON type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ==' name: '&e&l[!] &7Skeleton Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'G': block: SPAWNER:CREEPER type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0=' name: '&e&l[!] &7Creeper Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'H': block: SPAWNER:ZOMBIFIED_PIGLIN type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2VhYmFlY2M1ZmFlNWE4YTQ5Yzg4NjNmZjQ4MzFhYWEyODQxOThmMWEyMzk4ODkwYzc2NWUwYThkZTE4ZGE4YyJ9fX0=' name: '&e&l[!] &7Zombified Piglin Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'I': block: SPAWNER:GHAST type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19' name: '&e&l[!] &7Ghast Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'J': block: SPAWNER:SLIME type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ==' name: '&e&l[!] &7Slime Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'K': block: SPAWNER:GUARDIAN type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ==' name: '&e&l[!] &7Guardian Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'L': block: SPAWNER:SQUID type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ==' name: '&e&l[!] &7Squid Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'M': block: HOPPER type: HOPPER name: '&e&l[!] &7Hopper' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'N': block: BEACON type: BEACON name: '&e&l[!] &7Beacon' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'O': block: IRON_BLOCK type: IRON_BLOCK name: '&e&l[!] &7Iron Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'P': block: GOLD_BLOCK type: GOLD_BLOCK name: '&e&l[!] &7Gold Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'Q': block: DIAMOND_BLOCK type: DIAMOND_BLOCK name: '&e&l[!] &7Diamond Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'R': block: EMERALD_BLOCK type: EMERALD_BLOCK name: '&e&l[!] &7Emerald Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'S': block: BEDROCK type: BEDROCK name: '&e&l[!] &7Bedrock' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'T': block: ENDER_CHEST type: ENDER_CHEST name: '&e&l[!] &7Ender Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'U': block: DRAGON_EGG type: DRAGON_EGG name: '&e&l[!] &7Dragon Egg' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'V': block: CHEST type: CHEST name: '&e&l[!] &7Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'W': block: TRAPPED_CHEST type: TRAPPED_CHEST name: '&e&l[!] &7Trapped Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'X': block: ENCHANTING_TABLE type: ENCHANTING_TABLE name: '&e&l[!] &7Enchantment Table' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' ================================================ FILE: src/main/resources/menus/values1_20.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '{0} &n${1}' previous-menu: true pattern: - '& & & & & & & & &' - '% $ A B C D E F %' - '% % G H I J K L %' - '% * M N O P Q R %' - '% % S T U V W X %' - '& & & & & & & & &' items: '&': type: BLACK_STAINED_GLASS_PANE name: '&f' '$': type: SPAWNER name: '&e&lSPAWNERS ->' flags: - HIDE_ADDITIONAL_TOOLTIP '*': type: WRITABLE_BOOK name: '&e&lITEMS ->' 'A': block: SPAWNER:IRON_GOLEM type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19' name: '&e&l[!] &7Iron Golem Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'B': block: SPAWNER:BLAZE type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ==' name: '&e&l[!] &7Blaze Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'C': block: SPAWNER:SPIDER type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19' name: '&e&l[!] &7Spider Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'D': block: SPAWNER:COW type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19' name: '&e&l[!] &7Cow Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'E': block: SPAWNER:ZOMBIE type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ==' name: '&e&l[!] &7Zombie Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'F': block: SPAWNER:SKELETON type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ==' name: '&e&l[!] &7Skeleton Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'G': block: SPAWNER:CREEPER type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0=' name: '&e&l[!] &7Creeper Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'H': block: SPAWNER:ZOMBIFIED_PIGLIN type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2VhYmFlY2M1ZmFlNWE4YTQ5Yzg4NjNmZjQ4MzFhYWEyODQxOThmMWEyMzk4ODkwYzc2NWUwYThkZTE4ZGE4YyJ9fX0=' name: '&e&l[!] &7Zombified Piglin Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'I': block: SPAWNER:GHAST type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19' name: '&e&l[!] &7Ghast Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'J': block: SPAWNER:SLIME type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ==' name: '&e&l[!] &7Slime Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'K': block: SPAWNER:GUARDIAN type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ==' name: '&e&l[!] &7Guardian Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'L': block: SPAWNER:SQUID type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ==' name: '&e&l[!] &7Squid Spawner' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'M': block: HOPPER type: HOPPER name: '&e&l[!] &7Hopper' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'N': block: BEACON type: BEACON name: '&e&l[!] &7Beacon' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'O': block: IRON_BLOCK type: IRON_BLOCK name: '&e&l[!] &7Iron Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'P': block: GOLD_BLOCK type: GOLD_BLOCK name: '&e&l[!] &7Gold Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'Q': block: DIAMOND_BLOCK type: DIAMOND_BLOCK name: '&e&l[!] &7Diamond Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'R': block: EMERALD_BLOCK type: EMERALD_BLOCK name: '&e&l[!] &7Emerald Block' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'S': block: BEDROCK type: BEDROCK name: '&e&l[!] &7Bedrock' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'T': block: ENDER_CHEST type: ENDER_CHEST name: '&e&l[!] &7Ender Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'U': block: DRAGON_EGG type: DRAGON_EGG name: '&e&l[!] &7Dragon Egg' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'V': block: CHEST type: CHEST name: '&e&l[!] &7Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'W': block: TRAPPED_CHEST type: TRAPPED_CHEST name: '&e&l[!] &7Trapped Chest' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' 'X': block: ENCHANTING_TABLE type: ENCHANTING_TABLE name: '&e&l[!] &7Enchantment Table' lore: - '&6&l* &e&lQuantity &fx{0}' - '&6&l* &e&lWorth: &f${1}' - '&6&l* &e&lLevel: &f${2}' ================================================ FILE: src/main/resources/menus/visitors.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Visitors ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ ~ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' unique-visitors: '~' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&7Island Owner: {1}' - '' - '&7Left-Click to expel the player.' - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '~': type: SKULL_ITEM name: '&eUnique Visitors' lore: - '&7Click to open all-time visitors menu.' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/visitors1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Visitors ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ ~ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' unique-visitors: '~' items: '@': type: SKULL_ITEM data: 3 name: '&e{0}' lore: - '&7Island Owner: {1}' - '' - '&7Left-Click to expel the player.' - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '~': type: SKULL_ITEM name: '&eUnique Visitors' lore: - '&7Click to open all-time visitors menu.' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/visitors1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Visitors ({0})' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ ~ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' unique-visitors: '~' items: '@': type: PLAYER_HEAD name: '&e{0}' lore: - '&7Island Owner: {1}' - '' - '&7Left-Click to expel the player.' - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '~': type: SKELETON_SKULL name: '&eUnique Visitors' lore: - '&7Click to open all-time visitors menu.' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/warp-categories.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lWarp Categories' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' # This lore is added to category icons. edit-lore: - '&f ' - '&f ' - '&7&o(( &f&oLeft-Click &7&oto see island warps. ))' - '&7&o(( &f&oRight-Click &7&oto edit the category. ))' items: '@': type: STAINED_GLASS_PANE data: 15 name: '&f' '%': type: PAPER name: '&cPrevious Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page 1' '^': type: PAPER name: '&cNext Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' ================================================ FILE: src/main/resources/menus/warp-categories1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lWarp Categories' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' # This lore is added to category icons. edit-lore: - '&f ' - '&f ' - '&7&o(( &f&oLeft-Click &7&oto see island warps. ))' - '&7&o(( &f&oRight-Click &7&oto edit the category. ))' items: '@': type: BLACK_STAINED_GLASS_PANE name: '&f' '%': type: PAPER name: '&cPrevious Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page 1' '^': type: PAPER name: '&cNext Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' ================================================ FILE: src/main/resources/menus/warp-category-icon-edit.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lCategory: {0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ ! @ @ @ @ @ ~ @' - '@ @ @ @ ^ @ @ @ @' - '@ $ @ @ @ @ @ % @' - '@ @ @ @ @ @ @ @ @' icon-type: '!' icon-rename: '~' icon-relore: '$' icon-confirm: '%' icon-slots: '^' items: '!': type: DIAMOND name: '&6Set Type' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item type. ))' '~': type: ANVIL name: '&6Set Name' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item name. ))' '$': type: PAPER name: '&6Set Lore' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item lore. ))' '%': type: EMERALD name: '&6Confirm Changes' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto confirm all changes. ))' '^': type: STONE sounds: '%': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/warp-category-icon-edit1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lCategory: {0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ ! @ @ @ @ @ ~ @' - '@ @ @ @ ^ @ @ @ @' - '@ $ @ @ @ @ @ % @' - '@ @ @ @ @ @ @ @ @' icon-type: '!' icon-rename: '~' icon-relore: '$' icon-confirm: '%' icon-slots: '^' items: '!': type: DIAMOND name: '&6Set Type' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item type. ))' '~': type: ANVIL name: '&6Set Name' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item name. ))' '$': type: PAPER name: '&6Set Lore' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item lore. ))' '%': type: EMERALD name: '&6Confirm Changes' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto confirm all changes. ))' '^': type: STONE sounds: '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/warp-category-manage.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lCategory: {0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ ! @ @ ~ @ @ $ @' - '@ @ @ @ @ @ @ @ @' success-update-sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 category-rename: '!' category-icon: '~' category-warps: '$' items: '!': type: BOOK name: '&6Rename Category' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto rename the category. ))' '~': type: STONE lore: - '&f ' - '&f ' - '&7&oYou can use the following placeholders:' - '&7&o{0} is used for the warp''s name.' - '&7&o{1} is used for the warp''s location.' - '&7&o{2} is used for the warp''s public status.' - '&7&o(( &f&oRight-Click &7&oto edit the icon. ))' - '&7&o(( &f&oLeft-Click &7&oto edit the category''s slot. ))' '$': type: ENDER_PEARL name: '&6Island Warps' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the category warps. ))' ================================================ FILE: src/main/resources/menus/warp-category-manage1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lCategory: {0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ ! @ @ ~ @ @ $ @' - '@ @ @ @ @ @ @ @ @' success-update-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 category-rename: '!' category-icon: '~' category-warps: '$' items: '!': type: BOOK name: '&6Rename Category' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto rename the category. ))' '~': type: STONE lore: - '&f ' - '&f ' - '&7&oYou can use the following placeholders:' - '&7&o{0} is used for the warp''s name.' - '&7&o{1} is used for the warp''s location.' - '&7&o{2} is used for the warp''s public status.' - '&7&o(( &f&oRight-Click &7&oto edit the icon. ))' - '&7&o(( &f&oLeft-Click &7&oto edit the category''s slot. ))' '$': type: ENDER_PEARL name: '&6Island Warps' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the category warps. ))' ================================================ FILE: src/main/resources/menus/warp-icon-edit.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lWarp: {0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ ! @ @ @ @ @ ~ @' - '@ @ @ @ ^ @ @ @ @' - '@ $ @ @ @ @ @ % @' - '@ @ @ @ @ @ @ @ @' icon-type: '!' icon-rename: '~' icon-relore: '$' icon-confirm: '%' icon-slots: '^' items: '!': type: DIAMOND name: '&6Set Type' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item type. ))' '~': type: ANVIL name: '&6Set Name' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item name. ))' '$': type: PAPER name: '&6Set Lore' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item lore. ))' '%': type: EMERALD name: '&6Confirm Changes' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto confirm all changes. ))' '^': type: STONE sounds: '%': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/warp-icon-edit1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lWarp: {0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ ! @ @ @ @ @ ~ @' - '@ @ @ @ ^ @ @ @ @' - '@ $ @ @ @ @ @ % @' - '@ @ @ @ @ @ @ @ @' icon-type: '!' icon-rename: '~' icon-relore: '$' icon-confirm: '%' icon-slots: '^' items: '!': type: DIAMOND name: '&6Set Type' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item type. ))' '~': type: ANVIL name: '&6Set Name' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item name. ))' '$': type: PAPER name: '&6Set Lore' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto edit the item lore. ))' '%': type: EMERALD name: '&6Confirm Changes' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto confirm all changes. ))' '^': type: STONE sounds: '%': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/warp-manage.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lWarp: {0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ ! @ % @ $ @ @' - '@ @ @ @ ~ @ @ @ @' - '@ @ @ @ @ @ @ @ @' success-update-sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 warp-rename: '!' warp-icon: '~' warp-location: '$' warp-private: '%' items: '!': type: BOOK name: '&6Rename Warp' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto rename the warp. ))' '~': type: STONE lore: - '&f ' - '&f ' - '&7&oYou can use the following placeholders:' - '&7&o{0} is used for the warp''s name.' - '&7&o{1} is used for the warp''s location.' - '&7&o{2} is used for the warp''s public status.' - '&7&o(( &f&oClick &7&oto edit the icon. ))' '$': type: ENDER_PEARL name: '&6Warp Location' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto update the warp location. ))' '%': type: FEATHER name: '&6Private Warp' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto toggle warp to the public. ))' ================================================ FILE: src/main/resources/menus/warp-manage1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lWarp: {0}' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ ! @ % @ $ @ @' - '@ @ @ @ ~ @ @ @ @' - '@ @ @ @ @ @ @ @ @' success-update-sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 warp-rename: '!' warp-icon: '~' warp-location: '$' warp-private: '%' items: '!': type: BOOK name: '&6Rename Warp' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto rename the warp. ))' '~': type: STONE lore: - '&f ' - '&f ' - '&7&oYou can use the following placeholders:' - '&7&o{0} is used for the warp''s name.' - '&7&o{1} is used for the warp''s location.' - '&7&o{2} is used for the warp''s public status.' - '&7&o(( &f&oClick &7&oto edit the icon. ))' '$': type: ENDER_PEARL name: '&6Warp Location' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto update the warp location. ))' '%': type: FEATHER name: '&6Private Warp' lore: - '&f ' - '&f ' - '&7&o(( &f&oClick &7&oto toggle warp to the public. ))' ================================================ FILE: src/main/resources/menus/warps.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Warps' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' # This lore is added to warp icons. edit-lore: - '&f ' - '&f ' - '&7&o(( &f&oLeft-Click &7&oto warp to the location. ))' - '&7&o(( &f&oRight-Click &7&oto edit warp. ))' items: '@': type: BOOK name: '&e{0} {2}' lore: - '&7Located at {1}.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/warps1_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Warps' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' # This lore is added to warp icons. edit-lore: - '&f ' - '&f ' - '&7&o(( &f&oLeft-Click &7&oto warp to the location. ))' - '&7&o(( &f&oRight-Click &7&oto edit warp. ))' items: '@': type: BOOK name: '&e{0} {2}' lore: - '&7Located at {1}.' '%': type: PAPER name: '{0}Previous Page' '*': type: DOUBLE_PLANT name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: STAINED_GLASS_PANE data: 15 name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/menus/warps1_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### title: '&lIsland Warps' previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '@ @ @ @ @ @ @ @ @' - '$ $ $ $ $ $ $ $ $' - '# # % # * # ^ # #' slots: '@' previous-page: '%' current-page: '*' next-page: '^' # This lore is added to warp icons. edit-lore: - '&f ' - '&f ' - '&7&o(( &f&oLeft-Click &7&oto warp to the location. ))' - '&7&o(( &f&oRight-Click &7&oto edit warp. ))' items: '@': type: BOOK name: '&e{0} {2}' lore: - '&7Located at {1}.' '%': type: PAPER name: '{0}Previous Page' '*': type: SUNFLOWER name: '&aCurrent Page' lore: - '&7Page {0}' '^': type: PAPER name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE name: '&f' sounds: '@': type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 ================================================ FILE: src/main/resources/modules/bank/config.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # Whether the module should be enabled. # When disabled, all module commands and features will also be disabled. enabled: true # Set the divider for the island bank money in the total island worth. # You can set it to 0 to disable island bank money to be calculated in island worth. bank-worth-rate: 1000 # Should island bank balance be refunded upon island disband? # When set to 100, all the balance will be refunded. # When set to 0, no balance will be refunded. disband-refund: 0 # Should transaction logs of the island bank be saved to database? # Warning: There may be a lot of transactions, and can increase database. bank-logs: true # If bank-logs is enabled, whether to cache all logs to ram or not. # When set to true, all bank logs will be loaded when server starts and be cached on ram (Improved runtime performance). # When set to false, bank logs will be loaded only when needed, and get cached for 10 minutes before removed from # ram. May drop performance a little, however should help when there are a lot of logged bank transactions. cache-logs: true # All settings related to bank interest. # This feature is a money-generator for the islands. # As long as the island members are online, they will earn money. bank-interest: # Should the feature be enabled? enabled: true # The interval to give the interest reward (in seconds). interval: 86400 # The percentage out of the bank that will be given. # If it's 10, then 10% out of the bank balance will be given. percentage: 10 # The maximum time that the island owner can be offline in order to be rewarded (in seconds). # Can be -1 in order to disable this restriction. recent-active: 86400 ================================================ FILE: src/main/resources/modules/generators/config.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # Whether the module should be enabled. # When disabled, all module commands and features will also be disabled. enabled: true # Whether generators should match their intended world instead of the world they actually generate in. # Right now, toggling this to true will make the basalt generator to always generate nether rates, no matter # in which world it's generating blocks. match-generator-world: true ================================================ FILE: src/main/resources/modules/missions/categories/explorer/explorer_1.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: IslandMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 25000' - 'is admin msg %player% &e&lExplorer | &7Successfully finished the mission Nether Explorer!' - 'is admin msg %player% &e&lExplorer | &7Are you ready for the real challenge?' - 'is admin msg %player% &e&lExplorer | &7&oFor more information about the next mission, checkout /is missions' # List of events that will trigger the mission. events: - IslandSchematicPasteEvent # Requirement of the event to complete the mission. success-check: 'event.getSchematic().endsWith("_nether")' # Icons used in the menus. icons: not-completed: type: PAPER name: '&aNether Explorer' lore: - '&7Go to the Nether.' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&c&l ✘ &7Not Completed' can-complete: type: PAPER name: '&aNether Explorer' lore: - '&7Go to the Nether.' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&a&l ✔ &7Click to redeem your reward.' glow: true completed: type: MAP name: '&aNether Explorer' lore: - '&7Go to the Nether.' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&a&l ✔ &7Already Claimed.' ================================================ FILE: src/main/resources/modules/missions/categories/explorer/explorer_2.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: IslandMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 150000' - 'is admin msg %player% &e&lExplorer | &7Successfully finished the mission The-End Explorer!' - 'is admin msg %player% &e&lExplorer | &7&oYou explored every single world on the server!' # List of events that will trigger the mission. events: - IslandSchematicPasteEvent # Requirement of the event to complete the mission. success-check: 'event.getSchematic().endsWith("_the_end")' # List of required missions that must be completed before completing this one. required-missions: - 'explorer_1' # Icons used in the menus. icons: locked: type: PAPER name: '&aThe-End Explorer' lore: - '&7Go to The-End.' - '' - '&6Rewards:' - '&8 - &7$150,000' - '' - '&c&l ✘ &7Locked' not-completed: type: PAPER name: '&aThe-End Explorer' lore: - '&7Go to The-End.' - '' - '&6Rewards:' - '&8 - &7$150,000' - '' - '&c&l ✘ &7Not Completed' can-complete: type: PAPER name: '&aThe-End Explorer' lore: - '&7Go to The-End.' - '' - '&6Rewards:' - '&8 - &7$150,000' - '' - '&a&l ✔ &7Click to redeem your reward.' glow: true completed: type: MAP name: '&aThe-End Explorer' lore: - '&7Go to The-End.' - '' - '&6Rewards:' - '&8 - &7$150,000' - '' - '&a&l ✔ &7Already Claimed.' ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_1.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: items: '1': type: PUMPKIN_SEEDS amount: 1 '2': type: MELON_SEEDS amount: 1 commands: - 'eco give %player% 2500' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer I!' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'CARROT' amount: 10 '2': types: - 'POTATO' amount: 10 '3': types: - 'WHEAT' amount: 10 # Icons used in the menus. icons: not-completed: type: PAPER name: '&aFarmer I' lore: - '&7Plant a small farm.' - '' - '&6Required Plants:' - '&8 - &7x10 Carrots' - '&8 - &7x10 Potatoes' - '&8 - &7x10 Wheat' - '' - '&6Rewards:' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' - '' - '&6Grown Carrots: &7{value_carrot}/10' - '&6Grown Potatoes: &7{value_potato}/10' - '&6Grown Wheat: &7{value_wheat}/10' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' can-complete: type: PAPER name: '&aFarmer I' lore: - '&7Plant a small farm.' - '' - '&6Required Plants:' - '&8 - &7x10 Carrots' - '&8 - &7x10 Potatoes' - '&8 - &7x10 Wheat' - '' - '&6Rewards:' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' - '' - '&6Grown Carrots: &710/10' - '&6Grown Potatoes: &710/10' - '&6Grown Wheat: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' glow: true completed: type: MAP name: '&aFarmer I' lore: - '&7Plant a small farm.' - '' - '&6Rewards:' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' - '' - '&6Grown Carrots: &710/10' - '&6Grown Potatoes: &710/10' - '&6Grown Wheat: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_11_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: items: '1': type: BEETROOT_SEEDS amount: 1 '2': type: PUMPKIN_SEEDS amount: 1 '3': type: MELON_SEEDS amount: 1 commands: - 'eco give %player% 2500' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer I!' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'CARROT' amount: 10 '2': types: - 'POTATO' amount: 10 '3': types: - 'WHEAT' amount: 10 # Icons used in the menus. icons: not-completed: type: PAPER name: '&aFarmer I' lore: - '&7Plant a small farm.' - '' - '&6Required Plants:' - '&8 - &7x10 Carrots' - '&8 - &7x10 Potatoes' - '&8 - &7x10 Wheat' - '' - '&6Rewards:' - '&8 - &7x1 Beetroot Seed' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' - '' - '&6Grown Carrots: &7{value_carrot}/10' - '&6Grown Potatoes: &7{value_potato}/10' - '&6Grown Wheat: &7{value_wheat}/10' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' can-complete: type: PAPER name: '&aFarmer I' lore: - '&7Plant a small farm.' - '' - '&6Required Plants:' - '&8 - &7x10 Carrots' - '&8 - &7x10 Potatoes' - '&8 - &7x10 Wheat' - '' - '&6Rewards:' - '&8 - &7x1 Beetroot Seed' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' - '' - '&6Grown Carrots: &710/10' - '&6Grown Potatoes: &710/10' - '&6Grown Wheat: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' glow: true completed: type: MAP name: '&aFarmer I' lore: - '&7Plant a small farm.' - '' - '&6Rewards:' - '&8 - &7x1 Beetroot Seed' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' - '' - '&6Grown Carrots: &710/10' - '&6Grown Potatoes: &710/10' - '&6Grown Wheat: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_2.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: items: '1': type: SUGAR_CANE amount: 1 '2': type: CACTUS amount: 1 commands: - 'eco give %player% 5000' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer II!' # List of required missions that must be completed before completing this one. required-missions: - 'farmer_1' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'PUMPKIN' amount: 10 '2': types: - 'MELON' amount: 10 # Icons used in the menus. icons: locked: type: PAPER name: '&aFarmer II' lore: - '&7Expand your farm with pumpkins and melons.' - '' - '&6Required Plants:' - '&8 - &7x10 Pumpkins' - '&8 - &7x10 Melons' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - '&6Grown Pumpkins: &7{value_pumpkin}/10' - '&6Grown Melons: &7{value_melon}/10' - '&c&l ✘ &7Locked' amount: 2 not-completed: type: PAPER name: '&aFarmer II' lore: - '&7Expand your farm with pumpkins and melons.' - '' - '&6Required Plants:' - '&8 - &7x10 Pumpkins' - '&8 - &7x10 Melons' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - '&6Grown Pumpkins: &7{value_pumpkin}/10' - '&6Grown Melons: &7{value_melon}/10' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 2 can-complete: type: PAPER name: '&aFarmer II' lore: - '&7Expand your farm with pumpkins and melons.' - '' - '&6Required Plants:' - '&8 - &7x10 Beetroots' - '&8 - &7x10 Pumpkins' - '&8 - &7x10 Melons' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - '&6Grown Pumpkins: &710/10' - '&6Grown Melons: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 2 glow: true completed: type: MAP name: '&aFarmer II' lore: - '&7Expand your farm with pumpkins and melons.' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - '&6Grown Pumpkins: &710/10' - '&6Grown Melons: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 2 ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: items: '1': type: SUGAR_CANE amount: 1 '2': type: CACTUS amount: 1 commands: - 'eco give %player% 5000' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer II!' # List of required missions that must be completed before completing this one. required-missions: - 'farmer_1' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'BEETROOT' amount: 10 '2': types: - 'PUMPKIN' amount: 10 '3': types: - 'MELON' amount: 10 # Icons used in the menus. icons: locked: type: PAPER name: '&aFarmer II' lore: - '&7Expand your farm with beetroots, pumpkins and melons.' - '' - '&6Required Plants:' - '&8 - &7x10 Beetroots' - '&8 - &7x10 Pumpkins' - '&8 - &7x10 Melons' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - '&6Grown Beetroots: &7{value_beetroot}/10' - '&6Grown Pumpkins: &7{value_pumpkin}/10' - '&6Grown Melons: &7{value_melon}/10' - '&c&l ✘ &7Locked' amount: 2 not-completed: type: PAPER name: '&aFarmer II' lore: - '&7Expand your farm with beetroots, pumpkins and melons.' - '' - '&6Required Plants:' - '&8 - &7x10 Beetroots' - '&8 - &7x10 Pumpkins' - '&8 - &7x10 Melons' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - '&6Grown Beetroots: &7{value_beetroot}/10' - '&6Grown Pumpkins: &7{value_pumpkin}/10' - '&6Grown Melons: &7{value_melon}/10' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 2 can-complete: type: PAPER name: '&aFarmer II' lore: - '&7Expand your farm with beetroots, pumpkins and melons.' - '' - '&6Required Plants:' - '&8 - &7x10 Beetroots' - '&8 - &7x10 Pumpkins' - '&8 - &7x10 Melons' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - '&6Grown Beetroots: &710/10' - '&6Grown Pumpkins: &710/10' - '&6Grown Melons: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 2 glow: true completed: type: MAP name: '&aFarmer II' lore: - '&7Expand your farm with beetroots, pumpkins and melons.' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - '&6Grown Beetroots: &710/10' - '&6Grown Pumpkins: &710/10' - '&6Grown Melons: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 2 ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_3.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'is admin rankup %player% crop-growth' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer III!' # List of required missions that must be completed before completing this one. required-missions: - 'farmer_1' - 'farmer_2' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'SUGAR_CANE' amount: 10 '2': types: - 'CACTUS' amount: 10 # Icons used in the menus. icons: locked: type: PAPER name: '&aFarmer III' lore: - '&7Expand your farm with sugar canes and cactus.' - '' - '&6Required Plants:' - '&8 - &7x10 Sugar Canes' - '&8 - &7x10 Cactus' - '' - '&6Rewards:' - '&8 - &7Crops Upgrade' - '' - '&6Grown Sugar Canes: &7{value_sugar_cane}/10' - '&6Grown Cactus: &7{value_cactus}/10' - '&c&l ✘ &7Locked' amount: 3 not-completed: type: PAPER name: '&aFarmer III' lore: - '&7Expand your farm with sugar canes and cactus.' - '' - '&6Required Plants:' - '&8 - &7x10 Sugar Canes' - '&8 - &7x10 Cactus' - '' - '&6Rewards:' - '&8 - &7Crops Upgrade' - '' - '&6Grown Sugar Canes: &7{value_sugar_cane}/10' - '&6Grown Cactus: &7{value_cactus}/10' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 3 can-complete: type: PAPER name: '&aFarmer III' lore: - '&7Expand your farm with sugar canes and cactus.' - '' - '&6Required Plants:' - '&8 - &7x10 Sugar Canes' - '&8 - &7x10 Cactus' - '' - '&6Rewards:' - '&8 - &7Crops Upgrade' - '' - '&6Grown Sugar Canes: &710/10' - '&6Grown Cactus: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 3 glow: true completed: type: MAP name: '&aFarmer III' lore: - '&7Expand your farm with sugar canes and cactus.' - '' - '&6Rewards:' - '&8 - &7Crops Upgrade' - '' - '&6Grown Sugar Canes: &710/10' - '&6Grown Cactus: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 3 ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'is admin rankup %player% crop-growth' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer III!' # List of required missions that must be completed before completing this one. required-missions: - 'farmer_1' - 'farmer_2' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'SUGAR_CANE' amount: 10 '2': types: - 'CACTUS' amount: 10 # Icons used in the menus. icons: locked: type: PAPER name: '&aFarmer III' lore: - '&7Expand your farm with sugar canes and cactus.' - '' - '&6Required Plants:' - '&8 - &7x10 Sugar Canes' - '&8 - &7x10 Cactus' - '' - '&6Rewards:' - '&8 - &7Crops Upgrade' - '' - '&6Grown Sugar Canes: &7{value_sugar_cane}/10' - '&6Grown Cactus: &7{value_cactus}/10' - '&c&l ✘ &7Locked' amount: 3 not-completed: type: PAPER name: '&aFarmer III' lore: - '&7Expand your farm with sugar canes and cactus.' - '' - '&6Required Plants:' - '&8 - &7x10 Sugar Canes' - '&8 - &7x10 Cactus' - '' - '&6Rewards:' - '&8 - &7Crops Upgrade' - '' - '&6Grown Sugar Canes: &7{value_sugar_cane}/10' - '&6Grown Cactus: &7{value_cactus}/10' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 3 can-complete: type: PAPER name: '&aFarmer III' lore: - '&7Expand your farm with sugar canes and cactus.' - '' - '&6Required Plants:' - '&8 - &7x10 Sugar Canes' - '&8 - &7x10 Cactus' - '' - '&6Rewards:' - '&8 - &7Crops Upgrade' - '' - '&6Grown Sugar Canes: &710/10' - '&6Grown Cactus: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 3 glow: true completed: type: MAP name: '&aFarmer III' lore: - '&7Expand your farm with sugar canes and cactus.' - '' - '&6Rewards:' - '&8 - &7Crops Upgrade' - '' - '&6Grown Sugar Canes: &710/10' - '&6Grown Cactus: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 3 ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_4.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 25000' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer IV!' # List of required missions that must be completed before completing this one. required-missions: - 'farmer_1' - 'farmer_2' - 'farmer_3' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'CARROT' amount: 64 '2': types: - 'POTATO' amount: 64 '3': types: - 'WHEAT' amount: 64 '4': types: - 'PUMPKIN' amount: 64 '5': types: - 'MELON' amount: 64 '6': types: - 'SUGAR_CANE' amount: 64 '7': types: - 'CACTUS' amount: 64 # Icons used in the menus. icons: locked: type: PAPER name: '&aFarmer IV' lore: - '&7Now that you are a professional farmer,' - '&7let''s get the hands dirty.' - '&7Plant x64 of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Grown Carrots: &7{value_carrot}/64' - '&6Grown Potatoes: &7{value_potato}/64' - '&6Grown Wheat: &7{value_wheat}/64' - '&6Grown Pumpkins: &7{value_pumpkin}/64' - '&6Grown Melons: &7{value_melon}/64' - '&6Grown Sugar Canes: &7{value_sugar_cane}/64' - '&6Grown Cactus: &7{value_cactus}/64' - '&c&l ✘ &7Locked' amount: 4 not-completed: type: PAPER name: '&aFarmer IV' lore: - '&7Now that you are a professional farmer,' - '&7let''s get the hands dirty.' - '&7Plant x64 of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Grown Carrots: &7{value_carrot}/64' - '&6Grown Potatoes: &7{value_potato}/64' - '&6Grown Wheat: &7{value_wheat}/64' - '&6Grown Pumpkins: &7{value_pumpkin}/64' - '&6Grown Melons: &7{value_melon}/64' - '&6Grown Sugar Canes: &7{value_sugar_cane}/64' - '&6Grown Cactus: &7{value_cactus}/64' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 4 can-complete: type: PAPER name: '&aFarmer IV' lore: - '&7Now that you are a professional farmer,' - '&7let''s get the hands dirty.' - '&7Plant x64 of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Grown Carrots: &764/64' - '&6Grown Potatoes: &764/64' - '&6Grown Wheat: &764/64' - '&6Grown Pumpkins: &764/64' - '&6Grown Melons: &764/64' - '&6Grown Sugar Canes: &764/64' - '&6Grown Cactus: &764/64' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 4 glow: true completed: type: MAP name: '&aFarmer IV' lore: - '&7Now that you are a professional farmer,' - '&7let''s get the hands dirty.' - '&7Plant x64 of each crop.' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Grown Carrots: &764/64' - '&6Grown Potatoes: &764/64' - '&6Grown Wheat: &764/64' - '&6Grown Pumpkins: &764/64' - '&6Grown Melons: &764/64' - '&6Grown Sugar Canes: &764/64' - '&6Grown Cactus: &764/64' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 4 ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 25000' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer IV!' # List of required missions that must be completed before completing this one. required-missions: - 'farmer_1' - 'farmer_2' - 'farmer_3' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'CARROT' amount: 64 '2': types: - 'POTATO' amount: 64 '3': types: - 'WHEAT' amount: 64 '4': types: - 'BEETROOT' amount: 64 '5': types: - 'PUMPKIN' amount: 64 '6': types: - 'MELON' amount: 64 '7': types: - 'SUGAR_CANE' amount: 64 '8': types: - 'CACTUS' amount: 64 # Icons used in the menus. icons: locked: type: PAPER name: '&aFarmer IV' lore: - '&7Now that you are a professional farmer,' - '&7let''s get the hands dirty.' - '&7Plant x64 of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Grown Carrots: &7{value_carrot}/64' - '&6Grown Potatoes: &7{value_potato}/64' - '&6Grown Wheat: &7{value_wheat}/64' - '&6Grown Beetroots: &7{value_beetroot}/64' - '&6Grown Pumpkins: &7{value_pumpkin}/64' - '&6Grown Melons: &7{value_melon}/64' - '&6Grown Sugar Canes: &7{value_sugar_cane}/64' - '&6Grown Cactus: &7{value_cactus}/64' - '&c&l ✘ &7Locked' amount: 4 not-completed: type: PAPER name: '&aFarmer IV' lore: - '&7Now that you are a professional farmer,' - '&7let''s get the hands dirty.' - '&7Plant x64 of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Grown Carrots: &7{value_carrot}/64' - '&6Grown Potatoes: &7{value_potato}/64' - '&6Grown Wheat: &7{value_wheat}/64' - '&6Grown Beetroots: &7{value_beetroot}/64' - '&6Grown Pumpkins: &7{value_pumpkin}/64' - '&6Grown Melons: &7{value_melon}/64' - '&6Grown Sugar Canes: &7{value_sugar_cane}/64' - '&6Grown Cactus: &7{value_cactus}/64' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 4 can-complete: type: PAPER name: '&aFarmer IV' lore: - '&7Now that you are a professional farmer,' - '&7let''s get the hands dirty.' - '&7Plant x64 of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Grown Carrots: &764/64' - '&6Grown Potatoes: &764/64' - '&6Grown Wheat: &764/64' - '&6Grown Beetroots: &764/64' - '&6Grown Pumpkins: &764/64' - '&6Grown Melons: &764/64' - '&6Grown Sugar Canes: &764/64' - '&6Grown Cactus: &764/64' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 4 glow: true completed: type: MAP name: '&aFarmer IV' lore: - '&7Now that you are a professional farmer,' - '&7let''s get the hands dirty.' - '&7Plant x64 of each crop.' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Grown Carrots: &764/64' - '&6Grown Potatoes: &764/64' - '&6Grown Wheat: &764/64' - '&6Grown Beetroots: &764/64' - '&6Grown Pumpkins: &764/64' - '&6Grown Melons: &764/64' - '&6Grown Sugar Canes: &764/64' - '&6Grown Cactus: &764/64' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 4 ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_5.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 1000000' - 'is admin rankup %player% crop-growth' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer V!' - 'is admin msg %player% &e&lFarmer | &7There is nothing you don''t know how to grow.' - 'is admin msg %player% &e&lFarmer | &7&oYou are now a professional Farmer, congratz!' # List of required missions that must be completed before completing this one. required-missions: - 'farmer_1' - 'farmer_2' - 'farmer_3' - 'farmer_4' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'CARROT' amount: 320 '2': types: - 'POTATO' amount: 320 '3': types: - 'WHEAT' amount: 320 '4': types: - 'PUMPKIN' amount: 320 '5': types: - 'MELON' amount: 320 '6': types: - 'SUGAR_CANE' amount: 320 '7': types: - 'CACTUS' amount: 320 # Icons used in the menus. icons: locked: type: PAPER name: '&aFarmer V' lore: - '&7Let''s go one step further,' - '&7Plant 5 stacks of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$1,000,000' - '&8 - &7Crops Upgrade' - '' - '&6Grown Carrots: &7{value_carrot}/320' - '&6Grown Potatoes: &7{value_potato}/320' - '&6Grown Wheat: &7{value_wheat}/320' - '&6Grown Pumpkins: &7{value_pumpkin}/320' - '&6Grown Melons: &7{value_melon}/320' - '&6Grown Sugar Canes: &7{value_sugar_cane}/320' - '&6Grown Cactus: &7{value_cactus}/320' - '&c&l ✘ &7Locked' amount: 5 not-completed: type: PAPER name: '&aFarmer V' lore: - '&7Let''s go one step further,' - '&7Plant 5 stacks of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$1,000,000' - '&8 - &7Crops Upgrade' - '' - '&6Grown Carrots: &7{value_carrot}/320' - '&6Grown Potatoes: &7{value_potato}/320' - '&6Grown Wheat: &7{value_wheat}/320' - '&6Grown Pumpkins: &7{value_pumpkin}/320' - '&6Grown Melons: &7{value_melon}/320' - '&6Grown Sugar Canes: &7{value_sugar_cane}/320' - '&6Grown Cactus: &7{value_cactus}/320' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 5 can-complete: type: PAPER name: '&aFarmer V' lore: - '&7Let''s go one step further,' - '&7Plant 5 stacks of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$1,000,000' - '&8 - &7Crops Upgrade' - '' - '&6Grown Carrots: &7320/320' - '&6Grown Potatoes: &7320/320' - '&6Grown Wheat: &7320/320' - '&6Grown Pumpkins: &7320/320' - '&6Grown Melons: &7320/320' - '&6Grown Sugar Canes: &7320/320' - '&6Grown Cactus: &7320/320' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 5 glow: true completed: type: MAP name: '&aFarmer V' lore: - '&7Let''s go one step further,' - '&7Plant 5 stacks of each crop.' - '' - '&6Rewards:' - '&8 - &7$1,000,000' - '&8 - &7Crops Upgrade' - '' - '&6Grown Carrots: &7320/320' - '&6Grown Potatoes: &7320/320' - '&6Grown Wheat: &7320/320' - '&6Grown Pumpkins: &7320/320' - '&6Grown Melons: &7320/320' - '&6Grown Sugar Canes: &7320/320' - '&6Grown Cactus: &7320/320' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 5 ================================================ FILE: src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 1000000' - 'is admin rankup %player% crop-growth' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer V!' - 'is admin msg %player% &e&lFarmer | &7There is nothing you don''t know how to grow.' - 'is admin msg %player% &e&lFarmer | &7&oYou are now a professional Farmer, congratz!' # List of required missions that must be completed before completing this one. required-missions: - 'farmer_1' - 'farmer_2' - 'farmer_3' - 'farmer_4' # List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: - 'CARROT' amount: 320 '2': types: - 'POTATO' amount: 320 '3': types: - 'WHEAT' amount: 320 '4': types: - 'BEETROOT' amount: 320 '5': types: - 'PUMPKIN' amount: 320 '6': types: - 'MELON' amount: 320 '7': types: - 'SUGAR_CANE' amount: 320 '8': types: - 'CACTUS' amount: 320 # Icons used in the menus. icons: locked: type: PAPER name: '&aFarmer V' lore: - '&7Let''s go one step further,' - '&7Plant 5 stacks of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$1,000,000' - '&8 - &7Crops Upgrade' - '' - '&6Grown Carrots: &7{value_carrot}/320' - '&6Grown Potatoes: &7{value_potato}/320' - '&6Grown Wheat: &7{value_wheat}/320' - '&6Grown Beetroots: &7{value_beetroot}/320' - '&6Grown Pumpkins: &7{value_pumpkin}/320' - '&6Grown Melons: &7{value_melon}/320' - '&6Grown Sugar Canes: &7{value_sugar_cane}/320' - '&6Grown Cactus: &7{value_cactus}/320' - '&c&l ✘ &7Locked' amount: 5 not-completed: type: PAPER name: '&aFarmer V' lore: - '&7Let''s go one step further,' - '&7Plant 5 stacks of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$1,000,000' - '&8 - &7Crops Upgrade' - '' - '&6Grown Carrots: &7{value_carrot}/320' - '&6Grown Potatoes: &7{value_potato}/320' - '&6Grown Wheat: &7{value_wheat}/320' - '&6Grown Beetroots: &7{value_beetroot}/320' - '&6Grown Pumpkins: &7{value_pumpkin}/320' - '&6Grown Melons: &7{value_melon}/320' - '&6Grown Sugar Canes: &7{value_sugar_cane}/320' - '&6Grown Cactus: &7{value_cactus}/320' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 5 can-complete: type: PAPER name: '&aFarmer V' lore: - '&7Let''s go one step further,' - '&7Plant 5 stacks of each crop.' - '' - '&6Required Plants:' - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$1,000,000' - '&8 - &7Crops Upgrade' - '' - '&6Grown Carrots: &7320/320' - '&6Grown Potatoes: &7320/320' - '&6Grown Wheat: &7320/320' - '&6Grown Beetroots: &7320/320' - '&6Grown Pumpkins: &7320/320' - '&6Grown Melons: &7320/320' - '&6Grown Sugar Canes: &7320/320' - '&6Grown Cactus: &7320/320' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 5 glow: true completed: type: MAP name: '&aFarmer V' lore: - '&7Let''s go one step further,' - '&7Plant 5 stacks of each crop.' - '' - '&6Rewards:' - '&8 - &7$1,000,000' - '&8 - &7Crops Upgrade' - '' - '&6Grown Carrots: &7320/320' - '&6Grown Potatoes: &7320/320' - '&6Grown Wheat: &7320/320' - '&6Grown Beetroots: &7320/320' - '&6Grown Pumpkins: &7320/320' - '&6Grown Melons: &7320/320' - '&6Grown Sugar Canes: &7320/320' - '&6Grown Cactus: &7320/320' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 5 ================================================ FILE: src/main/resources/modules/missions/categories/fisherman/fisherman_1.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 2500' - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman I!' - 'is admin msg %player% &e&lFisherman | &7I heard you can find other items as well...' - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions' # List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: - 'RAW_FISH' amount: 5 # Icons used in the menus. icons: not-completed: type: PAPER name: '&aFisherman I' lore: - '&7Let''s make a fish soup.' - '&7Catch 5 fish.' - '' - '&6Required Caughts:' - '&8 - &7x5 Fish' - '' - '&6Rewards:' - '&8 - &7$2,500' - '' - '&6Fish Caught: &7{1}/5' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' can-complete: type: PAPER name: '&aFisherman I' lore: - '&7Let''s make a fish soup.' - '&7Catch 5 fish.' - '' - '&6Required Caughts:' - '&8 - &7x5 Fish' - '' - '&6Rewards:' - '&8 - &7$2,500' - '' - '&6Fish Caught: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' glow: true completed: type: MAP name: '&aFisherman I' lore: - '&7Let''s make a fish soup.' - '&7Catch 5 fish.' - '' - '&6Rewards:' - '&8 - &7$2,500' - '' - '&6Fish Caught: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' ================================================ FILE: src/main/resources/modules/missions/categories/fisherman/fisherman_11_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 2500' - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman I!' - 'is admin msg %player% &e&lFisherman | &7I heard you can find other items as well...' - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions' # List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: - 'COD' amount: 1 '2': types: - 'SALMON' amount: 1 '3': types: - 'TROPICAL_FISH' amount: 1 '4': types: - 'PUFFERFISH' amount: 1 # Icons used in the menus. icons: not-completed: type: PAPER name: '&aFisherman I' lore: - '&7Let''s make a fish soup.' - '&7Catch 1 fish of each type.' - '' - '&6Required Caughts:' - '&8 - &7x1 Cod' - '&8 - &7x1 Salmon' - '&8 - &7x1 Tropical Fish' - '&8 - &7x1 Pufferfish' - '' - '&6Rewards:' - '&8 - &7$2,500' - '' - '&6Cods Caught: &7{value_cod}/1' - '&6Salmons Caught: &7{value_salmon}/1' - '&6Tropical Fish Caught: &7{value_tropical_fish}/1' - '&6Pufferfish Caught: &7{value_pufferfish}/1' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' can-complete: type: PAPER name: '&aFisherman I' lore: - '&7Let''s make a fish soup.' - '&7Catch 1 fish of each type.' - '' - '&6Required Caughts:' - '&8 - &7x1 Cod' - '&8 - &7x1 Salmon' - '&8 - &7x1 Tropical Fish' - '&8 - &7x1 Pufferfish' - '' - '&6Rewards:' - '&8 - &7$2,500' - '' - '&6Cods Caught: &71/1' - '&6Salmons Caught: &71/1' - '&6Tropical Fish Caught: &71/1' - '&6Pufferfish Caught: &71/1' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' glow: true completed: type: MAP name: '&aFisherman I' lore: - '&7Let''s make a fish soup.' - '&7Catch 1 fish of each type.' - '' - '&6Rewards:' - '&8 - &7$2,500' - '' - '&6Cods Caught: &71/1' - '&6Salmons Caught: &71/1' - '&6Tropical Fish Caught: &71/1' - '&6Pufferfish Caught: &71/1' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' ================================================ FILE: src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 15000' - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman II!' - 'is admin msg %player% &e&lFisherman | &7What about testing our luck?' - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions' # List of required missions that must be completed before completing this one. required-missions: - 'fisherman_1' # List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: - 'BOW' - 'ENCHANTED_BOOK' - 'FISHING_ROD' - 'NAME_TAG' - 'SADDLE' - 'WATER_LILY' - 'BOWL' - 'LEATHER' - 'LEATHER_BOOTS' - 'ROTTEN_FLESH' - 'STICK' - 'STRING' - 'GLASS_BOTTLE' - 'BONE' - 'INK_SACK' - 'TRIPWIRE_HOOK' amount: 5 # Icons used in the menus. icons: locked: type: PAPER name: '&aFisherman II' lore: - '&7Cleaning the ocean from junk can be messy, but fun!' - '&7Catch 5 items.' - '' - '&6Required Caughts:' - '&8 - &7x5 Items' - '' - '&6Rewards:' - '&8 - &7$15,000' - '' - '&6Items: &7{1}/5' - '&c&l ✘ &7Locked' amount: 2 not-completed: type: PAPER name: '&aFisherman II' lore: - '&7Cleaning the ocean from junk can be messy, but fun!' - '&7Catch 5 items.' - '' - '&6Required Caughts:' - '&8 - &7x5 Items' - '' - '&6Rewards:' - '&8 - &7$15,000' - '' - '&6Items: &7{1}/5' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 2 can-complete: type: PAPER name: '&aFisherman II' lore: - '&7Cleaning the ocean from junk can be messy, but fun!' - '&7Catch 5 items.' - '' - '&6Required Caughts:' - '&8 - &7x5 Items' - '' - '&6Rewards:' - '&8 - &7$15,000' - '' - '&6Items: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 2 glow: true completed: type: MAP name: '&aFisherman II' lore: - '&7Cleaning the ocean from junk can be messy, but fun!' - '&7Catch 5 items.' - '' - '&6Rewards:' - '&8 - &7$15,000' - '' - '&6Items: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 2 ================================================ FILE: src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 15000' - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman II!' - 'is admin msg %player% &e&lFisherman | &7What about testing our luck?' - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions' # List of required missions that must be completed before completing this one. required-missions: - 'fisherman_1' # List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: - 'BOW' - 'ENCHANTED_BOOK' - 'FISHING_ROD' - 'NAME_TAG' - 'SADDLE' - 'NAUTILUS_SHELL' - 'LILY_PAD' - 'BOWL' - 'LEATHER' - 'LEATHER_BOOTS' - 'ROTTEN_FLESH' - 'STICK' - 'STRING' - 'GLASS_BOTTLE' - 'BONE' - 'INK_SAC' - 'TRIPWIRE_HOOK' amount: 5 # Icons used in the menus. icons: locked: type: PAPER name: '&aFisherman II' lore: - '&7Cleaning the ocean from junk can be messy, but fun!' - '&7Catch 5 items.' - '' - '&6Required Caughts:' - '&8 - &7x5 Items' - '' - '&6Rewards:' - '&8 - &7$15,000' - '' - '&6Items: &7{1}/5' - '&c&l ✘ &7Locked' amount: 2 not-completed: type: PAPER name: '&aFisherman II' lore: - '&7Cleaning the ocean from junk can be messy, but fun!' - '&7Catch 5 items.' - '' - '&6Required Caughts:' - '&8 - &7x5 Items' - '' - '&6Rewards:' - '&8 - &7$15,000' - '' - '&6Items: &7{1}/5' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 2 can-complete: type: PAPER name: '&aFisherman II' lore: - '&7Cleaning the ocean from junk can be messy, but fun!' - '&7Catch 5 items.' - '' - '&6Required Caughts:' - '&8 - &7x5 Items' - '' - '&6Rewards:' - '&8 - &7$15,000' - '' - '&6Items: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 2 glow: true completed: type: MAP name: '&aFisherman II' lore: - '&7Cleaning the ocean from junk can be messy, but fun!' - '&7Catch 5 items.' - '' - '&6Rewards:' - '&8 - &7$15,000' - '' - '&6Items: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 2 ================================================ FILE: src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 50000' - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman III!' - 'is admin msg %player% &e&lFisherman | &7Now you know how fishing works!' - 'is admin msg %player% &e&lFisherman | &7&oYou are now a professional Fisherman, congratz!' # List of required missions that must be completed before completing this one. required-missions: - 'fisherman_1' - 'fisherman_2' # List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: - 'BOW' - 'ENCHANTED_BOOK' - 'FISHING_ROD' - 'NAME_TAG' - 'SADDLE' amount: 3 # Icons used in the menus. icons: locked: type: PAPER name: '&aFisherman III' lore: - '&7It''s possible to catch treasure in the ocean.' - '&7Catch 3 treasure items.' - '' - '&6Required Caughts:' - '&8 - &7x3 Treasure Items' - '' - '&6Rewards:' - '&8 - &7$50,000' - '' - '&6Treasure Items: &7{1}/3' - '&c&l ✘ &7Locked' amount: 3 not-completed: type: PAPER name: '&aFisherman III' lore: - '&7It''s possible to catch treasure in the ocean.' - '&7Catch 3 treasure items.' - '' - '&6Required Caughts:' - '&8 - &7x3 Treasure Items' - '' - '&6Rewards:' - '&8 - &7$50,000' - '' - '&6Treasure Items: &7{1}/3' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 3 can-complete: type: PAPER name: '&aFisherman III' lore: - '&7It''s possible to catch treasure in the ocean.' - '&7Catch 3 treasure items.' - '' - '&6Required Caughts:' - '&8 - &7x3 Treasure Items' - '' - '&6Rewards:' - '&8 - &7$50,000' - '' - '&6Treasure Items: &73/3' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 3 glow: true completed: type: MAP name: '&aFisherman III' lore: - '&7It''s possible to catch treasure in the ocean.' - '&7Catch 3 treasure items.' - '' - '&6Rewards:' - '&8 - &7$50,000' - '' - '&6Treasure Items: &73/3' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 3 ================================================ FILE: src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 50000' - 'is admin msg %player% &e&lFisherman | &7Successfully finished the mission Fisherman III!' - 'is admin msg %player% &e&lFisherman | &7Now you know how fishing works!' - 'is admin msg %player% &e&lFisherman | &7&oYou are now a professional Fisherman, congratz!' # List of required missions that must be completed before completing this one. required-missions: - 'fisherman_1' - 'fisherman_2' # List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: - 'BOW' - 'ENCHANTED_BOOK' - 'FISHING_ROD' - 'NAME_TAG' - 'SADDLE' - 'NAUTILUS_SHELL' amount: 3 # Icons used in the menus. icons: locked: type: PAPER name: '&aFisherman III' lore: - '&7It''s possible to catch treasure in the ocean.' - '&7Catch 3 treasure items.' - '' - '&6Required Caughts:' - '&8 - &7x3 Treasure Items' - '' - '&6Rewards:' - '&8 - &7$50,000' - '' - '&6Treasure Items: &7{1}/3' - '&c&l ✘ &7Locked' amount: 3 not-completed: type: PAPER name: '&aFisherman III' lore: - '&7It''s possible to catch treasure in the ocean.' - '&7Catch 3 treasure items.' - '' - '&6Required Caughts:' - '&8 - &7x3 Treasure Items' - '' - '&6Rewards:' - '&8 - &7$50,000' - '' - '&6Treasure Items: &7{1}/3' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 3 can-complete: type: PAPER name: '&aFisherman III' lore: - '&7It''s possible to catch treasure in the ocean.' - '&7Catch 3 treasure items.' - '' - '&6Required Caughts:' - '&8 - &7x3 Treasure Items' - '' - '&6Rewards:' - '&8 - &7$50,000' - '' - '&6Treasure Items: &73/3' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 3 glow: true completed: type: MAP name: '&aFisherman III' lore: - '&7It''s possible to catch treasure in the ocean.' - '&7Catch 3 treasure items.' - '' - '&6Rewards:' - '&8 - &7$50,000' - '' - '&6Treasure Items: &73/3' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 3 ================================================ FILE: src/main/resources/modules/missions/categories/miner/miner_1.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: BlocksMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should block counts of players get reset when completing the mission? reset-after-finish: true # Whether only naturally spawned blocks should be counted towards the mission or not. only-natural-blocks: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 1000' - 'is admin rankup %player% generator-rates' - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner I!' - 'is admin msg %player% &e&lMiner | &7Now that you are familiar with generators, mine some iron.' - 'is admin msg %player% &e&lMiner | &7&oFor more information about the next mission, checkout /is missions' # List of all required blocks must be gathered in order to complete the mission. required-blocks: '1': types: - 'STONE' - 'COBBLESTONE' amount: 48 '2': types: - 'COAL_ORE' amount: 16 # Icons used in the menus. icons: not-completed: type: PAPER name: '&aMiner I' lore: - '&7Mine x48 cobblestone and x16 coal ore.' - '' - '&6Required Blocks:' - '&8 - &7x48 Cobblestone' - '&8 - &7x16 Coal Ore' - '' - '&6Rewards:' - '&8 - &7$1,000' - '&8 - &7Generator Upgrade' - '' - '&6Cobblestone Mined: &7{value_stone}/48' - '&6Coal Ore Mined: &7{value_coal_ore}/16' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' can-complete: type: PAPER name: '&aMiner I' lore: - '&7Mine x48 cobblestone and x16 coal ore.' - '' - '&6Required Blocks:' - '&8 - &7x48 Cobblestone' - '&8 - &7x16 Coal Ore' - '' - '&6Rewards:' - '&8 - &7$1,000' - '&8 - &7Generator Upgrade' - '' - '&6Cobblestone Mined: &748/48' - '&6Coal Ore Mined: &716/16' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' glow: true completed: type: MAP name: '&aMiner I' lore: - '&7Mine x48 cobblestone and x16 coal ore.' - '' - '&6Rewards:' - '&8 - &7$1,000' - '&8 - &7Generator Upgrade' - '' - '&6Cobblestone Mined: &748/48' - '&6Coal Ore Mined: &716/16' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' ================================================ FILE: src/main/resources/modules/missions/categories/miner/miner_2.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: BlocksMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should block counts of players get reset when completing the mission? reset-after-finish: true # Whether only naturally spawned blocks should be counted towards the mission or not. only-natural-blocks: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 5000' - 'is admin rankup %player% generator-rates' - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner II!' - 'is admin msg %player% &e&lMiner | &7I like iron, mind getting more for me?' - 'is admin msg %player% &e&lMiner | &7&oFor more information about the next mission, checkout /is missions' # List of required missions that must be completed before completing this one. required-missions: - 'miner_1' # List of all required blocks must be gathered in order to complete the mission. required-blocks: '1': types: - 'STONE' - 'COBBLESTONE' amount: 96 '2': types: - 'COAL_ORE' amount: 32 '3': types: - 'IRON_ORE' amount: 16 # Icons used in the menus. icons: locked: type: PAPER name: '&aMiner II' lore: - '&7Continue mining for ores!' - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x96 Cobblestone' - '&8 - &7x32 Coal Ore' - '&8 - &7x16 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$5,000' - '&8 - &7Generator Upgrade' - '' - '&6Cobblestone Mined: &7{value_cobblestone}/96' - '&6Coal Ore Mined: &7{value_coal_ore}/32' - '&6Iron Ore Mined: &7{value_iron_ore}/16' - '&c&l ✘ &7Locked' amount: 2 not-completed: type: PAPER name: '&aMiner II' lore: - '&7Continue mining for ores!' - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x96 Cobblestone' - '&8 - &7x32 Coal Ore' - '&8 - &7x16 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$5,000' - '&8 - &7Generator Upgrade' - '' - '&6Cobblestone Mined: &7{value_cobblestone}/96' - '&6Coal Ore Mined: &7{value_coal_ore}/32' - '&6Iron Ore Mined: &7{value_iron_ore}/16' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 2 can-complete: type: PAPER name: '&aMiner II' lore: - '&7Continue mining for ores!' - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x96 Cobblestone' - '&8 - &7x32 Coal Ore' - '&8 - &7x16 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$5,000' - '&8 - &7Generator Upgrade' - '' - '&6Cobblestone Mined: &796/96' - '&6Coal Ore Mined: &732/32' - '&6Iron Ore Mined: &716/16' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 2 glow: true completed: type: MAP name: '&aMiner II' lore: - '&7Continue mining for ores!' - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.' - '' - '&6Rewards:' - '&8 - &7$5,000' - '&8 - &7Generator Upgrade' - '' - '&6Cobblestone Mined: &796/96' - '&6Coal Ore Mined: &732/32' - '&6Iron Ore Mined: &716/16' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 2 ================================================ FILE: src/main/resources/modules/missions/categories/miner/miner_3.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: BlocksMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should block counts of players get reset when completing the mission? reset-after-finish: true # Whether only naturally spawned blocks should be counted towards the mission or not. only-natural-blocks: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 25000' - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner III!' - 'is admin msg %player% &e&lMiner | &7Let''s turn you into a professional miner!' - 'is admin msg %player% &e&lMiner | &7&oFor more information about the next mission, checkout /is missions' # List of required missions that must be completed before completing this one. required-missions: - 'miner_1' - 'miner_2' # List of all required blocks must be gathered in order to complete the mission. required-blocks: '1': types: - 'COAL_ORE' amount: 64 '2': types: - 'IRON_ORE' amount: 64 # Icons used in the menus. icons: locked: type: PAPER name: '&aMiner III' lore: - '&7I am willing to buy iron and coal from you.' - '&7Mine x64 coal ore and x64 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x64 Coal Ore' - '&8 - &7x64 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Coal Ore Mined: &7{value_coal_ore}/64' - '&6Iron Ore Mined: &7{value_iron_ore}/64' - '&c&l ✘ &7Locked' amount: 3 not-completed: type: PAPER name: '&aMiner III' lore: - '&7I am willing to buy iron and coal from you.' - '&7Mine x64 coal ore and x64 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x64 Coal Ore' - '&8 - &7x64 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Coal Ore Mined: &7{value_coal_ore}/64' - '&6Iron Ore Mined: &7{value_iron_ore}/64' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 3 can-complete: type: PAPER name: '&aMiner III' lore: - '&7I am willing to buy iron and coal from you.' - '&7Mine x64 coal ore and x64 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x64 Coal Ore' - '&8 - &7x64 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Coal Ore Mined: &764/64' - '&6Iron Ore Mined: &764/64' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 3 glow: true completed: type: MAP name: '&aMiner III' lore: - '&7I am willing to buy iron and coal from you.' - '&7Mine x64 coal ore and x64 iron ore.' - '' - '&6Rewards:' - '&8 - &7$25,000' - '' - '&6Coal Ore Mined: &764/64' - '&6Iron Ore Mined: &764/64' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 3 ================================================ FILE: src/main/resources/modules/missions/categories/miner/miner_4.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: BlocksMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should block counts of players get reset when completing the mission? reset-after-finish: true # Whether only naturally spawned blocks should be counted towards the mission or not. only-natural-blocks: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 125000' - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner IV!' - 'is admin msg %player% &e&lMiner | &7Are you ready for the ultimate test?' - 'is admin msg %player% &e&lMiner | &7&oFor more information about the next mission, checkout /is missions' # List of required missions that must be completed before completing this one. required-missions: - 'miner_1' - 'miner_2' - 'miner_3' # List of all required blocks must be gathered in order to complete the mission. required-blocks: '1': types: - 'COAL_ORE' amount: 320 '2': types: - 'IRON_ORE' amount: 192 # Icons used in the menus. icons: locked: type: PAPER name: '&aMiner IV' lore: - '&7I have more customers, I need more materials!' - '&7Mine x192 coal ore and x320 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x192 Coal Ore' - '&8 - &7x320 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$125,000' - '' - '&6Coal Ore Mined: &7{value_coal_ore}/192' - '&6Iron Ore Mined: &7{value_iron_ore}/320' - '&c&l ✘ &7Locked' amount: 4 not-completed: type: PAPER name: '&aMiner IV' lore: - '&7I have more customers, I need more materials!' - '&7Mine x192 coal ore and x320 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x192 Coal Ore' - '&8 - &7x320 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$125,000' - '' - '&6Coal Ore Mined: &7{value_coal_ore}/192' - '&6Iron Ore Mined: &7{value_iron_ore}/320' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 4 can-complete: type: PAPER name: '&aMiner IV' lore: - '&7I have more customers, I need more materials!' - '&7Mine x192 coal ore and x320 iron ore.' - '' - '&6Required Blocks:' - '&8 - &7x192 Coal Ore' - '&8 - &7x320 Iron Ore' - '' - '&6Rewards:' - '&8 - &7$125,000' - '' - '&6Coal Ore Mined: &7192/192' - '&6Iron Ore Mined: &7320/320' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 4 glow: true completed: type: MAP name: '&aMiner IV' lore: - '&7I have more customers, I need more materials!' - '&7Mine x192 coal ore and x320 iron ore.' - '' - '&6Rewards:' - '&8 - &7$125,000' - '' - '&6Coal Ore Mined: &7192/192' - '&6Iron Ore Mined: &7320/320' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 4 ================================================ FILE: src/main/resources/modules/missions/categories/miner/miner_5.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: BlocksMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should block counts of players get reset when completing the mission? reset-after-finish: true # Whether only naturally spawned blocks should be counted towards the mission or not. only-natural-blocks: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 250000' - 'is admin msg %player% &e&lMiner | &7Successfully finished the mission Miner V!' - 'is admin msg %player% &e&lMiner | &7Diamonds... diamonds... diamonds!' - 'is admin msg %player% &e&lMiner | &7&oYou are now a professional Miner, congratz!' # List of required missions that must be completed before completing this one. required-missions: - 'miner_1' - 'miner_2' - 'miner_3' - 'miner_4' # List of all required blocks must be gathered in order to complete the mission. required-blocks: '1': types: - 'DIAMOND_ORE' amount: 32 # Icons used in the menus. icons: locked: type: PAPER name: '&aMiner V' lore: - '&7It''s time to buy the best goodies.' - '&7Mine x32 diamond ores.' - '' - '&6Required Blocks:' - '&8 - &7x32 Diamond Ore' - '' - '&6Rewards:' - '&8 - &7$250,000' - '' - '&6Diamond Ore Mined: &7{1}/32' - '&c&l ✘ &7Locked' amount: 5 not-completed: type: PAPER name: '&aMiner V' lore: - '&7It''s time to buy the best goodies.' - '&7Mine x32 diamond ores.' - '' - '&6Required Blocks:' - '&8 - &7x32 Diamond Ore' - '' - '&6Rewards:' - '&8 - &7$250,000' - '' - '&6Diamond Ore Mined: &7{1}/32' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 5 can-complete: type: PAPER name: '&aMiner V' lore: - '&7It''s time to buy the best goodies.' - '&7Mine x32 diamond ores.' - '' - '&6Required Blocks:' - '&8 - &7x32 Diamond Ore' - '' - '&6Rewards:' - '&8 - &7$250,000' - '' - '&6Diamond Ore Mined: &732/32' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 5 glow: true completed: type: MAP name: '&aMiner V' lore: - '&7It''s time to buy the best goodies.' - '&7Mine x32 diamond ores.' - '' - '&6Rewards:' - '&8 - &7$250,000' - '' - '&6Diamond Ore Mined: &732/32' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 5 ================================================ FILE: src/main/resources/modules/missions/categories/slayer/slayer_1.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: KillsMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should entity counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 1000' - 'is admin msg %player% &e&lSlayer | &7Successfully finished the mission Slayer I!' - 'is admin msg %player% &e&lSlayer | &7Your sword hasn''t seen blood yet... Kill more mobs!' - 'is admin msg %player% &e&lSlayer | &7&oFor more information about the next mission, checkout /is missions' # List of all required entities must be gathered in order to complete the mission. required-entities: '1': types: - 'SKELETON' - 'CREEPER' - 'ZOMBIE' - 'SPIDER' amount: 5 # Icons used in the menus. icons: not-completed: type: PAPER name: '&aSlayer I' lore: - '&7Kill 5 hostile mobs.' - '' - '&6Required Kills:' - '&8 - &7x5 Skeletons/Creepers/Zombies/Spiders' - '' - '&6Rewards:' - '&8 - &7$1,000' - '' - '&6Hostiles Killed: &7{1}/5' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' can-complete: type: PAPER name: '&aSlayer I' lore: - '&7Kill 5 hostile mobs.' - '' - '&6Required Kills:' - '&8 - &7x5 Skeletons/Creepers/Zombies/Spiders' - '' - '&6Rewards:' - '&8 - &7$1,000' - '' - '&6Hostiles Killed: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' glow: true completed: type: MAP name: '&aSlayer I' lore: - '&7Kill 5 hostile mobs.' - '' - '&6Rewards:' - '&8 - &7$1,000' - '' - '&6Hostiles Killed: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' ================================================ FILE: src/main/resources/modules/missions/categories/slayer/slayer_2.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: KillsMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should entity counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 15000' - 'is admin unlockworld %player% nether true' - 'is admin msg %player% &e&lSlayer | &7Successfully finished the mission Slayer II!' - 'is admin msg %player% &e&lSlayer | &7Explore the nether, bring some goodies back home.' - 'is admin msg %player% &e&lSlayer | &7&oFor more information about the next mission, checkout /is missions' # List of required missions that must be completed before completing this one. required-missions: - 'slayer_1' # List of all required entities must be gathered in order to complete the mission. required-entities: '1': types: - 'SKELETON' amount: 32 '2': types: - 'ZOMBIE' amount: 32 '3': types: - 'SPIDER' amount: 32 '4': types: - 'CREEPER' amount: 24 # Icons used in the menus. icons: locked: type: PAPER name: '&aSlayer II' lore: - '&7It is time you build a farm.' - '&7Kill 120 hostile mobs.' - '' - '&6Required Kills:' - '&8 - &7x32 Skeletons' - '&8 - &7x32 Zombies' - '&8 - &7x32 Spiders' - '&8 - &7x24 Creepers' - '' - '&6Rewards:' - '&8 - &7$15,000' - '&8 - &7Unlock Nether' - '' - '&6Skeletons Killed: &7{value_skeleton}/32' - '&6Zombies Killed: &7{value_zombie}/32' - '&6Spiders Killed: &7{value_spider}/32' - '&6Creepers Killed: &7{value_creeper}/24' - '&c&l ✘ &7Locked' amount: 2 not-completed: type: PAPER name: '&aSlayer II' lore: - '&7It is time you build a farm.' - '&7Kill 120 hostile mobs.' - '' - '&6Required Kills:' - '&8 - &7x32 Skeletons' - '&8 - &7x32 Zombies' - '&8 - &7x32 Spiders' - '&8 - &7x24 Creepers' - '' - '&6Rewards:' - '&8 - &7$15,000' - '&8 - &7Unlock Nether' - '' - '&6Skeletons Killed: &7{value_skeleton}/32' - '&6Zombies Killed: &7{value_zombie}/32' - '&6Spiders Killed: &7{value_spider}/32' - '&6Creepers Killed: &7{value_creeper}/24' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 2 can-complete: type: PAPER name: '&aSlayer II' lore: - '&7It is time you build a farm.' - '&7Kill 120 hostile mobs.' - '' - '&6Required Kills:' - '&8 - &7x32 Skeletons' - '&8 - &7x32 Zombies' - '&8 - &7x32 Spiders' - '&8 - &7x24 Creepers' - '' - '&6Rewards:' - '&8 - &7$15,000' - '&8 - &7Unlock Nether' - '' - '&6Skeletons Killed: &732/32' - '&6Zombies Killed: &732/32' - '&6Spiders Killed: &732/32' - '&6Creepers Killed: &724/24' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 2 glow: true completed: type: MAP name: '&aSlayer II' lore: - '&7It is time you build a farm.' - '&7Kill 120 hostile mobs.' - '' - '&6Rewards:' - '&8 - &7$15,000' - '&8 - &7Unlock Nether' - '' - '&6Skeletons Killed: &732/32' - '&6Zombies Killed: &732/32' - '&6Spiders Killed: &732/32' - '&6Creepers Killed: &724/24' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 2 ================================================ FILE: src/main/resources/modules/missions/categories/slayer/slayer_3.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: KillsMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should entity counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 75000' - 'is admin msg %player% &e&lSlayer | &7Successfully finished the mission Slayer III!' - 'is admin msg %player% &e&lSlayer | &7It is time to show who is the boss here.' - 'is admin msg %player% &e&lSlayer | &7&oFor more information about the next mission, checkout /is missions' # List of required missions that must be completed before completing this one. required-missions: - 'slayer_1' - 'slayer_2' # List of all required entities must be gathered in order to complete the mission. required-entities: '1': types: - 'BLAZE' amount: 12 '2': types: - 'ENDERMAN' amount: 24 '3': types: - 'WITHER_SKELETON' amount: 12 # Icons used in the menus. icons: locked: type: PAPER name: '&aSlayer III' lore: - '&7It is time to prepare for the boss fights.' - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.' - '' - '&6Required Kills:' - '&8 - &7x12 Blazes' - '&8 - &7x12 Wither Skeletons' - '&8 - &7x24 Endermans' - '' - '&6Rewards:' - '&8 - &7$75,000' - '' - '&6Blazes Killed: &7{value_blaze}/12' - '&6Wither Skeletons Killed: &7{value_wither_skeleton}/12' - '&6Endermans Killed: &7{value_enderman}/24' - '&c&l ✘ &7Locked' amount: 3 not-completed: type: PAPER name: '&aSlayer III' lore: - '&7It is time to prepare for the boss fights.' - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.' - '' - '&6Required Kills:' - '&8 - &7x12 Blazes' - '&8 - &7x12 Wither Skeletons' - '&8 - &7x24 Endermans' - '' - '&6Rewards:' - '&8 - &7$75,000' - '' - '&6Blazes Killed: &7{value_blaze}/12' - '&6Wither Skeletons Killed: &7{value_wither_skeleton}/12' - '&6Endermans Killed: &7{value_enderman}/24' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' amount: 3 can-complete: type: PAPER name: '&aSlayer III' lore: - '&7It is time to prepare for the boss fights.' - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.' - '' - '&6Required Kills:' - '&8 - &7x12 Blazes' - '&8 - &7x12 Wither Skeletons' - '&8 - &7x24 Endermans' - '' - '&6Rewards:' - '&8 - &7$75,000' - '' - '&6Blazes Killed: &712/12' - '&6Wither Skeletons Killed: &712/12' - '&6Endermans Killed: &724/24' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' amount: 3 glow: true completed: type: MAP name: '&aSlayer III' lore: - '&7It is time to prepare for the boss fights.' - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.' - '' - '&6Rewards:' - '&8 - &7$75,000' - '' - '&6Blazes Killed: &712/12' - '&6Wither Skeletons Killed: &712/12' - '&6Endermans Killed: &724/24' - '&6Progress: &7100%' - '&a&l ✔ &7Already Claimed.' amount: 3 ================================================ FILE: src/main/resources/modules/missions/categories/slayer/slayer_4.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # The mission file to use mission-file: KillsMissions # Whether the mission should be given when completing all requirements. auto-reward: true # Should entity counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: commands: - 'eco give %player% 250000' - 'is admin unlockworld %player% the_end true' - 'is admin msg %player% &e&lSlayer | &7Successfully finished the mission Slayer IV!' - 'is admin msg %player% &e&lSlayer | &7You passed all the tests, you are ready now for the end...' - 'is admin msg %player% &e&lSlayer | &7&oYou are now a professional Slayer, congratz!' # List of required missions that must be completed before completing this one. required-missions: - 'slayer_1' - 'slayer_2' - 'slayer_3' # List of all required entities must be gathered in order to complete the mission. required-entities: '1': types: - 'WITHER' amount: 1 # Icons used in the menus. icons: locked: type: PAPER name: '&aSlayer IV' lore: - '&7Before the end, there is one mission left.' - '&7Kill the wither.' - '' - '&6Required Kills:' - '&8 - &7x1 Wither' - '' - '&6Rewards:' - '&8 - &7$250,000' - '&8 - &7Unlock The End' - '' - '&6Wither Killed: &c&l✘' - '&c&l ✘ &7Locked' amount: 4 not-completed: type: PAPER name: '&aSlayer IV' lore: - '&7Before the end, there is one mission left.' - '&7Kill the wither.' - '' - '&6Required Kills:' - '&8 - &7x1 Wither' - '' - '&6Rewards:' - '&8 - &7$250,000' - '&8 - &7Unlock The End' - '' - '&6Wither Killed: &c&l✘' - '&c&l ✘ &7Not Completed' amount: 4 can-complete: type: PAPER name: '&aSlayer IV' lore: - '&7Before the end, there is one mission left.' - '&7Kill the wither.' - '' - '&6Required Kills:' - '&8 - &7x1 Wither' - '' - '&6Rewards:' - '&8 - &7$250,000' - '&8 - &7Unlock The End' - '' - '&6Wither Killed: &a&l✔' - '&a&l ✔ &7Click to redeem your reward.' amount: 4 glow: true completed: type: MAP name: '&aSlayer IV' lore: - '&7Before the end, there is one mission left.' - '&7Kill the wither.' - '' - '&6Rewards:' - '&8 - &7$250,000' - '&8 - &7Unlock The End' - '' - '&6Wither Killed: &a&l✔' - '&a&l ✔ &7Already Claimed.' amount: 4 ================================================ FILE: src/main/resources/modules/missions/config.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # Whether the module should be enabled. # When disabled, all module commands and features will also be disabled. enabled: true # Should mission rewards be automatically claimed outside island worlds? # When disabled, rewards for missions with auto-reward enabled will be # automatically claimed only in island worlds. auto-reward-outside-islands: false # Settings related to mission categories. # A tutorial about configuring missions can be found here: # https://wiki.bg-software.com/superiorskyblock/missions categories: miner: name: 'Miner' slot: 20 slayer: name: 'Slayer' slot: 21 farmer: name: 'Farmer' slot: 22 fisherman: name: 'Fisherman' slot: 23 explorer: name: 'Explorer' slot: 24 ================================================ FILE: src/main/resources/modules/upgrades/config.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # Whether the module should be enabled. # When disabled, all module commands and features will also be disabled. enabled: true # Whether crop-growth should be enabled. # When disabled, the plugin will not alter crop growth. crop-growth: true # Whether mob drops should be enabled. # When disabled, the plugin will not alter mob drops. mob-drops: true # Whether island-effects should be enabled. # When disabled, the plugin will not give any effects to any players. island-effects: true # Whether spawner-rates should be enabled. # When disabled, the plugin will not alter spawner rates. spawner-rates: true # Whether block-limits should be enabled. # When disabled, the plugin will not limit placement of blocks. block-limits: true # Whether entity-limits should be enabled. # When disabled, the plugin will not limit spawning of entities. entity-limits: true # All the upgrades of the plugin # https://wiki.bg-software.com/superiorskyblock/upgrades upgrades: hoppers-limit: '1': price: 1000000.0 price-type: "Money" block-limits: HOPPER: 8 commands: - 'island admin setupgrade %player% hoppers-limit 2' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your hoppers limit was increased to 16!' '2': price: 3000000.0 price-type: "Money" block-limits: HOPPER: 16 commands: - 'island admin setupgrade %player% hoppers-limit 3' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your hoppers limit was increased to 32!' '3': price: 9000000.0 price-type: "Money" block-limits: HOPPER: 32 commands: - 'island admin setupgrade %player% hoppers-limit 4' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your hoppers limit was increased to 64!' '4': price: 0.0 price-type: "Money" block-limits: HOPPER: 64 commands: - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for hoppers limit.' crop-growth: '1': price: 100000.0 price-type: "Money" crop-growth: 1 commands: - 'island admin setupgrade %player% crop-growth 2' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your crop-growth multiplier was increased to x2!' '2': price: 500000.0 price-type: "Money" crop-growth: 15 commands: - 'island admin setupgrade %player% crop-growth 3' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your crop-growth multiplier was increased to x3!' '3': price: 1000000.0 price-type: "Money" crop-growth: 25 commands: - 'island admin setupgrade %player% crop-growth 4' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your crop-growth multiplier was increased to x4!' '4': price: 0.0 price-type: "Money" crop-growth: 40 commands: - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for crop growth.' spawner-rates: '1': price: 500000.0 price-type: "Money" spawner-rates: 1 commands: - 'island admin setupgrade %player% spawner-rates 2' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your spawner-rates multiplier was increased to x2!' '2': price: 1000000.0 price-type: "Money" spawner-rates: 2 commands: - 'island admin setupgrade %player% spawner-rates 3' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your spawner-rates multiplier was increased to x3!' '3': price: 2500000.0 price-type: "Money" spawner-rates: 3 commands: - 'island admin setupgrade %player% spawner-rates 4' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your spawner-rates multiplier was increased to x4!' '4': price: 0.0 price-type: "Money" spawner-rates: 4 commands: - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for spawner-rates.' mob-drops: '1': price: 1000000.0 price-type: "Money" mob-drops: 1 commands: - 'island admin setupgrade %player% mob-drops 2' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your mob-drops multiplier was increased to x2!' '2': price: 2000000.0 price-type: "Money" mob-drops: 2 commands: - 'island admin setupgrade %player% mob-drops 3' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your mob-drops multiplier was increased to x3!' '3': price: 5000000.0 price-type: "Money" mob-drops: 3 commands: - 'island admin setupgrade %player% mob-drops 4' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your mob-drops multiplier was increased to x4!' '4': price: 0.0 mob-drops: 4 commands: - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for mob-drops.' members-limit: '1': price: 100000.0 price-type: "Money" team-limit: 4 commands: - 'island admin setupgrade %player% members-limit 2' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your members limit was increased to 8!' '2': price: 300000.0 price-type: "Money" team-limit: 8 commands: - 'island admin setupgrade %player% members-limit 3' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your members limit was increased to 16!' '3': price: 500000.0 price-type: "Money" team-limit: 16 commands: - 'island admin setupgrade %player% members-limit 4' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your members limit was increased to 32!' '4': price: 0.0 price-type: "Money" team-limit: 32 commands: - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for members limit.' border-size: '1': price: 30000.0 price-type: "Money" border-size: 25 commands: - 'island admin setupgrade %player% border-size 2' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your border size was increased to 100x100 blocks!' '2': price: 80000.0 price-type: "Money" border-size: 50 commands: - 'island admin setupgrade %player% border-size 3' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your border size was increased to 150x150 blocks!' '3': price: 150000.0 price-type: "Money" border-size: 75 commands: - 'island admin setupgrade %player% border-size 4' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your border size was increased to 250x250 blocks!' '4': price: 0.0 price-type: "Money" border-size: 125 commands: - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for border size.' generator-rates: '1': price: 25000.0 price-type: "Money" generator-rates: normal: STONE: 95 COAL_ORE: 5 commands: - 'island admin setupgrade %player% generator-rates 2' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your generator was upgraded to level 2!' '2': price: 75000.0 price-type: "Money" generator-rates: normal: STONE: 92 COAL_ORE: 5 REDSTONE_ORE: 3 commands: - 'island admin setupgrade %player% generator-rates 3' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your generator was upgraded to level 3!' '3': price: 150000.0 price-type: "Money" generator-rates: normal: STONE: 80 COAL_ORE: 8 REDSTONE_ORE: 6 LAPIS_ORE: 4 IRON_ORE: 2 commands: - 'island admin setupgrade %player% generator-rates 4' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your generator was upgraded to level 4!' '4': price: 0.0 price-type: "Money" generator-rates: normal: STONE: 65 COAL_ORE: 10 REDSTONE_ORE: 9 LAPIS_ORE: 6 IRON_ORE: 4 GOLD_ORE: 3 DIAMOND_ORE: 2 EMERALD_ORE: 1 commands: - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for generator.' minecarts-limit: '1': price: 1000000.0 price-type: "Money" entity-limits: MINECART: 4 commands: - 'island admin setupgrade %player% minecarts-limit 2' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your minecarts limit was increased to 8!' '2': price: 3000000.0 price-type: "Money" entity-limits: MINECART: 8 commands: - 'island admin setupgrade %player% minecarts-limit 3' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your minecarts limit was increased to 16!' '3': price: 9000000.0 price-type: "Money" entity-limits: MINECART: 16 commands: - 'island admin setupgrade %player% minecarts-limit 4' - 'island admin msgall %player% &e&lSuperiorSkyblock &7Your minecarts limit was increased to 32!' '4': price: 0.0 price-type: "Money" entity-limits: MINECART: 32 commands: - 'island admin msg %player% &e&lSuperiorSkyblock &7You have reached the maximum upgrade for minecarts limit.' ================================================ FILE: src/main/resources/plugin.yml ================================================ name: SuperiorSkyblock2 version: ${project.version} main: com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin description: Feature packed Skyblock core. website: https://bg-software.com/ api-version: '1.13' author: Ome_R # Custom section used by DependenciesManager, which replaces softdepend. class-depends: - AdvancedSpawners - CMI - ChangeSkin - CoreProtect - EpicSpawners - Essentials - FastAsyncWorldEdit - ItemsAdder - JetsMinions - LuckPerms - MergedSpawner - MVdWPlaceholderAPI - Oraxen - PlaceholderAPI - ProtocolLib - PvpingSpawners - RoseStacker - ShopGUIPlus - SilkSpawners - SkinsRestorer - SlimeWorldManager - SuperVanish - UltimateStacker - VanishNoPacket - Vault - WildStacker - WorldEdit loadbefore: - Multiverse-Core - Slimefun - My_Worlds libraries: - org.openjdk.nashorn:nashorn-core:15.4 permissions: superior.*: description: Permission for all admin & island commands default: op children: superior.island.*: description: Permission for all island commands children: superior.island.accept: description: Accept an invitation from a player. superior.island.balance: description: Check the amount of money inside an island's bank. superior.island.ban: description: Ban a player from your island. superior.island.bank: description: Open the island's bank. superior.island.bans: description: Open the bans menu. superior.island.biome: description: Change the biome of the island. superior.island.border: description: Change the border color of the islands. superior.island.chest: description: Open the island's chest. superior.island.close: description: Close the island to the public. superior.island.coop: description: Add a player as a co-op to your island. superior.island.coops: description: Open the coops menu. superior.island.counts: description: See block counts in your island. superior.island.create: description: Create a new island. superior.island.delwarp: description: Delete an island warp. superior.island.demote: description: Demote a member in your island. superior.island.deposit: description: Deposit money from your personal account into the island's bank. superior.island.disband: description: Disband your island permanently. superior.island.expel: description: Kick a visitor from your island. superior.island.fly: description: Toggle island fly. superior.island.help: description: List of all commands. superior.island.invite: description: Invite a player to your island. superior.island.kick: description: Kick a player from your island. superior.island.lang: description: Change your personal language. superior.island.leave: description: Leave your island. superior.island.mission: description: Complete a mission. superior.island.missions: description: Open the missions menu. superior.island.name: description: Change the name of your island. superior.island.open: description: Open the island to the public. superior.island.panel: description: Open island panel. children: superior.island.visitors: description: Open the visitors menu. superior.island.members: description: Open the members menu. superior.island.pardon: description: Unban a player from your island. superior.island.permissions: description: Get all permissions for an island role. superior.island.promote: description: Promote a member in your island. superior.island.rankup: description: Level up an upgrade. superior.island.rate: description: Rate an island. superior.island.ratings: description: Show all island ratings. superior.island.recalc: description: Re-calculates the island worth. superior.island.setdiscord: description: Set the discord of the island for island payouts. superior.island.setpaypal: description: Set the paypal email of the island for island payouts. superior.island.setrole: description: Change the role of a player in your island. superior.island.setteleport: description: Change the teleport location of your island. superior.island.settings: description: Open the settings menu. superior.island.setwarp: description: Create a new island warp. superior.island.show: description: Get information about an island. superior.island.stacker.*: description: Gives the ability to stack blocks. superior.island.team: description: Get information about island members status. superior.island.teamchat: description: Toggle team chat mode. superior.island.teleport: description: Teleport to your island. superior.island.toggle: description: Permission to use the /is toggle command. children: superior.island.toggle.border: description: Toggle island borders. superior.island.toggle.blocks: description: Toggle stacked blocks placements. superior.island.top: description: Open top islands panel. superior.island.transfer: description: Transfer your island's leadership. superior.island.uncoop: description: Remove a player from being a co-op in your island. superior.island.upgrade: description: Open upgrades panel. superior.island.value: description: Get the worth value of a block. superior.island.values: description: Open the values menu. superior.island.visit: description: Teleport to the visitors location of an island. superior.island.warp: description: Warp to an island warp. superior.island.warps: description: List of island warps. superior.island.withdraw: description: Withdraw money from your island's bank into your personal account. superior.admin.*: description: Permission for all admin commands default: op children: superior.admin: description: Use the admin commands. superior.admin.add: description: Add a user to an island. superior.admin.addbanklimit: description: Increase the bank limit for another player's island. superior.admin.addblocklimit: description: Increase block limit for another player's island. superior.admin.addbonus: description: Add a bonus to a player. superior.admin.addcooplimit: description: Increase coop players limit for another player's island. superior.admin.addcropgrowth: description: Increase the crop growth multiplier for another player's island. superior.admin.addeffect: description: Add an island effect for another player's island. superior.admin.addentitylimit: description: Increase entity limit for another player's island. superior.admin.addgenerator: description: Add percentage of a material for the cobblestone generator. superior.admin.addmobdrops: description: Increase the mob drops multiplier for another player's island. superior.admin.addsize: description: Expand another player's island size. superior.admin.addspawnerrates: description: Increase the spawner rates multiplier for another player's island. superior.admin.addteamlimit: description: Increase members limit for another player's island. superior.admin.addwarpslimit: description: Increase the warps limit of an island. superior.admin.bonus: description: Grant a bonus to a player. superior.admin.bypass: description: Toggle bypass mode. superior.admin.bypass.warmup: description: Bypass teleport warmup superior.admin.chest: description: Open island's chest of another island. superior.admin.cleargenerator: description: Clear generator rates for a specific island. superior.admin.close: description: Close an island to the public. superior.admin.count: description: Check a block count on a specific island. superior.admin.delwarp: description: Delete a warp for an island. superior.admin.demote: description: Demote a member in another player's island. superior.admin.deposit: description: Deposit money into another player's island bank. superior.admin.disband: description: Disband another player's island permanently. superior.admin.fly: description: Toggle island fly for another player. superior.admin.givedisbands: description: Give disbands to a player. superior.admin.ignore: description: Ignore an island from top islands. superior.admin.join: description: Join an island without an invitation. superior.admin.kick: description: Kick a player from his island. superior.admin.modules: description: Manage modules of the plugin. superior.admin.mission: description: Change the status of a mission for a player. superior.admin.msg: description: Send a player a message without any prefixes. superior.admin.msgall: description: Send to all island members a message without any prefixes. superior.admin.name: description: Change the name of an island. superior.admin.open: description: Open an island to the public. superior.admin.openmenu: description: Open a custom menu for a player. superior.admin.promote: description: Promote a member in another player's island. superior.admin.purge: description: Purge islands from database. superior.admin.rankup: description: Rankup an upgrade for an island. superior.admin.recalc: description: Re-calculates the worth of an island. superior.admin.reload: description: Reload all configurations and tasks of the plugin. superior.admin.removeblocklimit: description: Remove a block limit for an island. superior.admin.removeentitylimit: description: Remove an entity limit for an island. superior.admin.removeratings: description: Remove all ratings given by a player. superior.admin.resetpermissions: description: Reset all island permissions for a specific island. superior.admin.resetsettings: description: Reset all island settings for a specific island. superior.admin.resetworld: description: Reset a world for an island. superior.admin.schematic: description: Create schematics for the plugin. superior.admin.setbanklimit: description: Set the bank limit for another player's island. superior.admin.setbiome: description: Set the biome of an island. superior.admin.setblockamount: description: Set the block amount in a specific location. superior.admin.setblocklimit: description: Set block limit for another player's island. superior.admin.setchestrow: description: Set the chest rows for another player's island. superior.admin.setcooplimit: description: Set coop players limit for another player's island. superior.admin.setcropgrowth: description: Set the crop growth multiplier for another player's island. superior.admin.setdisbands: description: Set a player's amount of island disbands. superior.admin.seteffect: description: Set the island effect level of another player's island. superior.admin.setentitylimit: description: Set entity limit for another player's island. superior.admin.setgenerator: description: Change percentage of a material for the cobblestone generator. superior.admin.setislandpreview: description: Set the preview location for an island. superior.admin.setleader: description: Transfer an island to someone else. superior.admin.setmobdrops: description: Set the mob drops multiplier for another player's island. superior.admin.setpermission: description: Set a required role for a permission for all the islands. superior.admin.setrate: description: Set the rating of another player. superior.admin.setrolelimit: description: Set role limit for another player's island. superior.admin.setsettings: description: Toggle settings for a specific island. superior.admin.setsize: description: Change another player's island size. superior.admin.setspawn: description: Set the spawn location of the server. superior.admin.setspawnerrates: description: Set the spawner rates multiplier for another player's island. superior.admin.setteamlimit: description: Set members limit for another player's island. superior.admin.settings: description: Open the plugin settings editor. superior.admin.setupgrade: description: Set the level of an upgrade for another player's island. superior.admin.setwarpslimit: description: Set the warps limit of an island. superior.admin.show: description: Get information about an island. superior.admin.spawn: description: Teleport to the spawn location. superior.admin.spy: description: Toggle chat spy mode. superior.admin.stats: description: Show stats about the plugin. superior.admin.syncupgrades: description: Sync upgrade values for an island. superior.admin.teleport: description: Teleport to other islands. superior.admin.unignore: description: Unignore an island from top islands. superior.admin.withdraw: description: Withdraw money from another player's island bank. superior.admin.world: description: Unlock a world for an island. superior.chat.color: description: Gives access to use colors within island chat. ================================================ FILE: src/main/resources/safe_blocks.yml ================================================ ###################################################### ## ## ## SuperiorSkyblock 2 ## ## Developed by Ome_R ## ## ## ###################################################### # A list of safe blocks. # Players can only get teleported (when teleporting to islands) on blocks from this list. safe-blocks: [ ]