package us.talabrek.ultimateskyblock; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import dk.lockfuglsang.minecraft.animation.AnimationHandler; import dk.lockfuglsang.minecraft.command.Command; import dk.lockfuglsang.minecraft.command.CommandManager; import dk.lockfuglsang.minecraft.file.FileUtil; import dk.lockfuglsang.minecraft.po.I18nUtil; import dk.lockfuglsang.minecraft.util.TimeUtil; import dk.lockfuglsang.minecraft.util.VersionUtil; import dk.lockfuglsang.minecraft.yml.YmlConfiguration; import io.papermc.lib.PaperLib; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.Biome; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import us.talabrek.ultimateskyblock.api.IslandLevel; import us.talabrek.ultimateskyblock.api.IslandRank; import us.talabrek.ultimateskyblock.api.async.Callback; import us.talabrek.ultimateskyblock.api.event.EventLogic; import us.talabrek.ultimateskyblock.api.event.uSkyBlockEvent; import us.talabrek.ultimateskyblock.api.event.uSkyBlockScoreChangedEvent; import us.talabrek.ultimateskyblock.api.uSkyBlockAPI; import us.talabrek.ultimateskyblock.challenge.ChallengeLogic; import us.talabrek.ultimateskyblock.chat.ChatEvents; import us.talabrek.ultimateskyblock.chat.ChatLogic; import us.talabrek.ultimateskyblock.chat.IslandTalkCommand; import us.talabrek.ultimateskyblock.chat.PartyTalkCommand; import us.talabrek.ultimateskyblock.command.AdminCommand; import us.talabrek.ultimateskyblock.command.ChallengeCommand; import us.talabrek.ultimateskyblock.command.IslandCommand; import us.talabrek.ultimateskyblock.command.admin.DebugCommand; import us.talabrek.ultimateskyblock.command.admin.SetMaintenanceCommand; import us.talabrek.ultimateskyblock.command.island.BiomeCommand; import us.talabrek.ultimateskyblock.event.ExploitEvents; import us.talabrek.ultimateskyblock.event.GriefEvents; import us.talabrek.ultimateskyblock.event.InternalEvents; import us.talabrek.ultimateskyblock.event.ItemDropEvents; import us.talabrek.ultimateskyblock.event.MenuEvents; import us.talabrek.ultimateskyblock.event.NetherTerraFormEvents; import us.talabrek.ultimateskyblock.event.PlayerEvents; import us.talabrek.ultimateskyblock.event.SpawnEvents; import us.talabrek.ultimateskyblock.event.ToolMenuEvents; import us.talabrek.ultimateskyblock.event.WorldGuardEvents; import us.talabrek.ultimateskyblock.handler.AsyncWorldEditHandler; import us.talabrek.ultimateskyblock.handler.ConfirmHandler; import us.talabrek.ultimateskyblock.handler.CooldownHandler; import us.talabrek.ultimateskyblock.handler.WorldGuardHandler; import us.talabrek.ultimateskyblock.handler.placeholder.PlaceholderHandler; import us.talabrek.ultimateskyblock.hook.HookManager; import us.talabrek.ultimateskyblock.imports.USBImporterExecutor; import us.talabrek.ultimateskyblock.island.BlockLimitLogic; import us.talabrek.ultimateskyblock.island.IslandGenerator; import us.talabrek.ultimateskyblock.island.IslandInfo; import us.talabrek.ultimateskyblock.island.IslandLocatorLogic; import us.talabrek.ultimateskyblock.island.IslandLogic; import us.talabrek.ultimateskyblock.island.LimitLogic; import us.talabrek.ultimateskyblock.island.OrphanLogic; import us.talabrek.ultimateskyblock.island.level.ChunkSnapshotLevelLogic; import us.talabrek.ultimateskyblock.island.level.IslandScore; import us.talabrek.ultimateskyblock.island.level.LevelLogic; import us.talabrek.ultimateskyblock.island.task.CreateIslandTask; import us.talabrek.ultimateskyblock.island.task.RecalculateRunnable; import us.talabrek.ultimateskyblock.island.task.SetBiomeTask; import us.talabrek.ultimateskyblock.menu.ConfigMenu; import us.talabrek.ultimateskyblock.menu.SkyBlockMenu; import us.talabrek.ultimateskyblock.player.IslandPerk; import us.talabrek.ultimateskyblock.player.PerkLogic; import us.talabrek.ultimateskyblock.player.PlayerInfo; import us.talabrek.ultimateskyblock.player.PlayerLogic; import us.talabrek.ultimateskyblock.player.PlayerNotifier; import us.talabrek.ultimateskyblock.player.PlayerPerk; import us.talabrek.ultimateskyblock.player.TeleportLogic; import us.talabrek.ultimateskyblock.signs.SignEvents; import us.talabrek.ultimateskyblock.signs.SignLogic; import us.talabrek.ultimateskyblock.util.IslandUtil; import us.talabrek.ultimateskyblock.util.LocationUtil; import us.talabrek.ultimateskyblock.util.PlayerUtil; import us.talabrek.ultimateskyblock.util.ServerUtil; import us.talabrek.ultimateskyblock.uuid.BukkitPlayerDB; import us.talabrek.ultimateskyblock.uuid.FilePlayerDB; import us.talabrek.ultimateskyblock.uuid.MemoryPlayerDB; import us.talabrek.ultimateskyblock.uuid.PlayerDB; import us.talabrek.ultimateskyblock.world.WorldManager; import java.io.File; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Random; import java.util.UUID; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import static dk.lockfuglsang.minecraft.po.I18nUtil.pre; import static dk.lockfuglsang.minecraft.po.I18nUtil.tr; import static us.talabrek.ultimateskyblock.util.LocationUtil.isSafeLocation; import static us.talabrek.ultimateskyblock.util.LogUtil.log; public class uSkyBlock extends JavaPlugin implements uSkyBlockAPI, CommandManager.RequirementChecker { private static final String CN = uSkyBlock.class.getName(); private static final String[][] depends = new String[][]{ new String[]{"Vault", "1.7.0", "optional"}, new String[]{"WorldEdit", "7.0", "optionalIf", "FastAsyncWorldEdit"}, new String[]{"WorldGuard", "7.0"}, new String[]{"FastAsyncWorldEdit", "1.13", "optional"}, new String[]{"Multiverse-Core", "2.5", "optional"}, new String[]{"Multiverse-Portals", "2.5", "optional"}, new String[]{"Multiverse-NetherPortals", "2.5", "optional"}, }; private static String missingRequirements = null; private static final Random RND = new Random(System.currentTimeMillis()); private SkyBlockMenu menu; private ConfigMenu configMenu; private ChallengeLogic challengeLogic; private EventLogic eventLogic; private LevelLogic levelLogic; private IslandLogic islandLogic; private OrphanLogic orphanLogic; private PerkLogic perkLogic; private TeleportLogic teleportLogic; private LimitLogic limitLogic; /* MANAGERS */ private HookManager hookManager; private MetricsManager metricsManager; private WorldManager worldManager; private IslandGenerator islandGenerator; private PlayerNotifier notifier; private USBImporterExecutor importer; private static uSkyBlock instance; // TODO: 28/06/2016 - R4zorax: These two should probably be moved to the proper classes public File directoryPlayers; public File directoryIslands; private BukkitTask autoRecalculateTask; private IslandLocatorLogic islandLocatorLogic; private PlayerDB playerDB; private ConfirmHandler confirmHandler; private AnimationHandler animationHandler; private CooldownHandler cooldownHandler; private PlayerLogic playerLogic; private ChatLogic chatLogic; private volatile boolean maintenanceMode = false; private BlockLimitLogic blockLimitLogic; public uSkyBlock() { } @Override public void onDisable() { HandlerList.unregisterAll(this); Bukkit.getScheduler().cancelTasks(this); try { WorldManager.skyBlockWorld = null; // Force a reload on config. } catch (Exception e) { log(Level.INFO, tr("Something went wrong saving the island and/or party data!"), e); } PlaceholderHandler.unregister(this); if (animationHandler != null) { animationHandler.stop(); } challengeLogic.shutdown(); eventLogic.shutdown(); playerLogic.shutdown(); islandLogic.shutdown(); playerDB.shutdown(); // Must be before playerNameChangeManager!! AsyncWorldEditHandler.onDisable(this); DebugCommand.disableLogging(null); } @Override public FileConfiguration getConfig() { return FileUtil.getYmlConfiguration("config.yml"); } @Override public void onEnable() { WorldManager.skyBlockWorld = null; // Force a re-import or what-ever... WorldManager.skyBlockNetherWorld = null; missingRequirements = null; instance = this; CommandManager.registerRequirements(this); FileUtil.setDataFolder(getDataFolder()); FileUtil.setAllwaysOverwrite("levelConfig.yml"); I18nUtil.setDataFolder(getDataFolder()); reloadConfigs(); getServer().getScheduler().runTaskLater(getInstance(), new Runnable() { @Override public void run() { ServerUtil.init(uSkyBlock.this); if (!isRequirementsMet(Bukkit.getConsoleSender(), null)) { return; } uSkyBlock.this.getHookManager().setupEconomyHook(); uSkyBlock.this.getHookManager().setupPermissionsHook(); AsyncWorldEditHandler.onEnable(uSkyBlock.this); WorldGuardHandler.setupGlobal(getWorldManager().getWorld()); if (getWorldManager().getNetherWorld() != null) { WorldGuardHandler.setupGlobal(getWorldManager().getNetherWorld()); } registerEventsAndCommands(); if (!getConfig().getBoolean("importer.name2uuid.imported", false)) { Bukkit.getConsoleSender().sendMessage(tr("Converting data to UUID, this make take a while!")); getImporter().importUSB(Bukkit.getConsoleSender(), "name2uuid"); } log(Level.INFO, getVersionInfo(false)); } }, getConfig().getLong("init.initDelay", 50L)); metricsManager = new MetricsManager(this); PaperLib.suggestPaper(this); } public synchronized boolean isRequirementsMet(CommandSender sender, Command command, String... args) { if (maintenanceMode && !( (command instanceof AdminCommand && args != null && args.length > 0 && args[0].equals("maintenance")) || command instanceof SetMaintenanceCommand)) { sender.sendMessage(tr("\u00a7cMAINTENANCE:\u00a7e uSkyBlock is currently in maintenance mode")); return false; } if (missingRequirements == null) { PluginManager pluginManager = getServer().getPluginManager(); missingRequirements = ""; for (String[] pluginReq : depends) { if (pluginReq.length > 2 && pluginReq[2].equals("optional")) { // Do check the version if an optional requirement is present. if (!pluginManager.isPluginEnabled(pluginReq[0])) { continue; } } if (pluginReq.length > 2 && pluginReq[2].equals("optionalIf")) { if (pluginManager.isPluginEnabled(pluginReq[3])) { continue; } } if (pluginManager.isPluginEnabled(pluginReq[0])) { PluginDescriptionFile desc = pluginManager.getPlugin(pluginReq[0]).getDescription(); if (VersionUtil.getVersion(desc.getVersion()).isLT(pluginReq[1])) { missingRequirements += tr("\u00a7buSkyBlock\u00a7e depends on \u00a79{0}\u00a7e >= \u00a7av{1}\u00a7e but only \u00a7cv{2}\u00a7e was found!\n", pluginReq[0], pluginReq[1], desc.getVersion()); } } else { missingRequirements += tr("\u00a7buSkyBlock\u00a7e depends on \u00a79{0}\u00a7e >= \u00a7av{1}", pluginReq[0], pluginReq[1]); } } } if (missingRequirements.isEmpty()) { return true; } else { sender.sendMessage(missingRequirements.split("\n")); return false; } } private void createFolders() { if (!getDataFolder().exists()) { getDataFolder().mkdirs(); } directoryPlayers = new File(getDataFolder() + File.separator + "players"); if (!directoryPlayers.exists()) { directoryPlayers.mkdirs(); } directoryIslands = new File(getDataFolder() + File.separator + "islands"); if (!directoryIslands.exists()) { directoryIslands.mkdirs(); } IslandInfo.setDirectory(directoryIslands); } public static uSkyBlock getInstance() { return uSkyBlock.instance; } public void registerEvents() { final PluginManager manager = getServer().getPluginManager(); manager.registerEvents(new InternalEvents(this), this); manager.registerEvents(new PlayerEvents(this), this); manager.registerEvents(new MenuEvents(this), this); manager.registerEvents(new ExploitEvents(this), this); if (getConfig().getBoolean("options.protection.enabled", true)) { manager.registerEvents(new GriefEvents(this), this); if (getConfig().getBoolean("options.protection.item-drops", true)) { manager.registerEvents(new ItemDropEvents(this), this); } } if (getConfig().getBoolean("options.island.spawn-limits.enabled", true)) { manager.registerEvents(new SpawnEvents(this), this); } if (getConfig().getBoolean("options.protection.visitors.block-banned-entry", true)) { manager.registerEvents(new WorldGuardEvents(this), this); } if (Settings.nether_enabled) { manager.registerEvents(new NetherTerraFormEvents(this), this); } if (getConfig().getBoolean("tool-menu.enabled", true)) { manager.registerEvents(new ToolMenuEvents(this), this); } if (getConfig().getBoolean("signs.enabled", true)) { manager.registerEvents(new SignEvents(this, new SignLogic(this)), this); } PlaceholderHandler.register(this); manager.registerEvents(new ChatEvents(chatLogic, this), this); } public Location getSafeHomeLocation(final PlayerInfo p) { Location home = LocationUtil.findNearestSafeLocation(p.getHomeLocation(), null); if (home == null) { home = LocationUtil.findNearestSafeLocation(p.getIslandLocation(), null); } return home; } public Location getSafeWarpLocation(final PlayerInfo p) { us.talabrek.ultimateskyblock.api.IslandInfo islandInfo = getIslandInfo(p); if (islandInfo != null) { Location warp = LocationUtil.findNearestSafeLocation(islandInfo.getWarpLocation(), null); if (warp == null) { warp = LocationUtil.findNearestSafeLocation(islandInfo.getIslandLocation(), null); } return warp; } return null; } private void postDelete(final PlayerInfo pi) { pi.save(); } private void postDelete(final IslandInfo islandInfo) { WorldGuardHandler.removeIslandRegion(islandInfo.getName()); islandLogic.deleteIslandConfig(islandInfo.getName()); orphanLogic.save(); } public boolean deleteEmptyIsland(String islandName, final Runnable runner) { final IslandInfo islandInfo = getIslandInfo(islandName); if (islandInfo != null && islandInfo.getMembers().isEmpty()) { islandLogic.clearIsland(islandInfo.getIslandLocation(), new Runnable() { @Override public void run() { postDelete(islandInfo); if (runner != null) { runner.run(); } } }); return true; } else { return false; } } public void deletePlayerIsland(final String player, final Runnable runner) { PlayerInfo pi = playerLogic.getPlayerInfo(player); final PlayerInfo finalPI = pi; final IslandInfo islandInfo = getIslandInfo(pi); Location islandLocation = islandInfo.getIslandLocation(); for (String member : islandInfo.getMembers()) { pi = playerLogic.getPlayerInfo(member); islandInfo.removeMember(pi); } islandLogic.clearIsland(islandLocation, new Runnable() { @Override public void run() { postDelete(finalPI); postDelete(islandInfo); if (runner != null) runner.run(); } }); } public boolean restartPlayerIsland(final Player player, final Location next, final String cSchem) { if (!perkLogic.getSchemes(player).contains(cSchem)) { player.sendMessage(tr("\u00a7eYou do not have access to that island-schematic!")); return false; } final PlayerInfo playerInfo = getPlayerInfo(player); if (playerInfo != null) { playerInfo.setIslandGenerating(true); } if (getWorldManager().isSkyWorld(player.getWorld())) { // Clear first, since the player could log out and we NEED to make sure their inventory gets cleared. clearPlayerInventory(player); } islandLogic.clearIsland(next, new Runnable() { @Override public void run() { generateIsland(player, playerInfo, next, cSchem); } }); return true; } public void clearPlayerInventory(Player player) { getLogger().entering(CN, "clearPlayerInventory", player); PlayerInfo playerInfo = getPlayerInfo(player); if (!getWorldManager().isSkyWorld(player.getWorld())) { getLogger().finer("not clearing, since player is not in skyworld, marking for clear on next entry"); if (playerInfo != null) { playerInfo.setClearInventoryOnNextEntry(true); } return; } if (playerInfo != null) { playerInfo.setClearInventoryOnNextEntry(false); } if (getConfig().getBoolean("options.restart.clearInventory", true)) { player.getInventory().clear(); } if (getConfig().getBoolean("options.restart.clearPerms", true)) { playerInfo.clearPerms(player); } if (getConfig().getBoolean("options.restart.clearArmor", true)) { ItemStack[] armor = player.getEquipment().getArmorContents(); player.getEquipment().setArmorContents(new ItemStack[armor.length]); } if (getConfig().getBoolean("options.restart.clearEnderChest", true)) { player.getEnderChest().clear(); } if (getConfig().getBoolean("options.restart.clearCurrency", false)) { getHookManager().getEconomyHook().ifPresent((hook) -> hook.withdrawPlayer(player, hook.getBalance(player))); } getLogger().exiting(CN, "clearPlayerInventory"); } public synchronized boolean devSetPlayerIsland(final Player sender, final Location l, final String player) { final PlayerInfo pi = playerLogic.getPlayerInfo(player); String islandName = WorldGuardHandler.getIslandNameAt(l); Location islandLocation = IslandUtil.getIslandLocation(islandName); final Location newLoc = LocationUtil.alignToDistance(islandLocation, Settings.island_distance); if (newLoc == null) { return false; } boolean deleteOldIsland = false; if (pi.getHasIsland()) { Location oldLoc = pi.getIslandLocation(); if (oldLoc != null && !(newLoc.getBlockX() == oldLoc.getBlockX() && newLoc.getBlockZ() == oldLoc.getBlockZ())) { deleteOldIsland = true; } } if (newLoc.equals(pi.getIslandLocation())) { sender.sendMessage(tr("\u00a74Player is already assigned to this island!")); deleteOldIsland = false; } // Purge current islandinfo and partymembers if there's an active party at this location (issue #948) getIslandLogic().purge(islandName); Runnable resetIsland = () -> { pi.setHomeLocation(null); pi.setIslandLocation(newLoc); pi.setHomeLocation(getSafeHomeLocation(pi)); IslandInfo island = islandLogic.createIslandInfo(pi.locationForParty(), player); WorldGuardHandler.updateRegion(island); pi.save(); }; if (deleteOldIsland) { deletePlayerIsland(pi.getPlayerName(), resetIsland); } else { resetIsland.run(); } return true; } public boolean homeSet(final Player player) { if (!player.getWorld().getName().equalsIgnoreCase(getWorldManager().getWorld().getName())) { player.sendMessage(tr("\u00a74You must be closer to your island to set your skyblock home!")); return true; } if (playerIsOnOwnIsland(player)) { PlayerInfo playerInfo = playerLogic.getPlayerInfo(player); if (playerInfo != null && isSafeLocation(player.getLocation())) { playerInfo.setHomeLocation(player.getLocation()); playerInfo.save(); player.sendMessage(tr("\u00a7aYour skyblock home has been set to your current location.")); } else { player.sendMessage(tr("\u00a74Your current location is not a safe home-location.")); } return true; } player.sendMessage(tr("\u00a74You must be closer to your island to set your skyblock home!")); return true; } public boolean playerIsOnIsland(final Player player) { return playerIsOnOwnIsland(player) || playerIsTrusted(player); } public boolean playerIsOnOwnIsland(Player player) { return locationIsOnIsland(player, player.getLocation()) || locationIsOnNetherIsland(player, player.getLocation()); } private boolean playerIsTrusted(Player player) { String islandName = WorldGuardHandler.getIslandNameAt(player.getLocation()); if (islandName != null) { us.talabrek.ultimateskyblock.api.IslandInfo islandInfo = islandLogic.getIslandInfo(islandName); if (islandInfo != null && islandInfo.getTrustees().contains(player.getName())) { return true; } } return false; } public boolean locationIsOnNetherIsland(final Player player, final Location loc) { if (!getWorldManager().isSkyNether(loc.getWorld())) { return false; } PlayerInfo playerInfo = playerLogic.getPlayerInfo(player); if (playerInfo != null && playerInfo.getHasIsland()) { Location p = playerInfo.getIslandNetherLocation(); if (p == null) { return false; } ProtectedRegion region = WorldGuardHandler.getNetherRegionAt(p); return region != null && region.contains(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); } return false; } public boolean locationIsOnIsland(final Player player, final Location loc) { if (!getWorldManager().isSkyWorld(loc.getWorld())) { return false; } PlayerInfo playerInfo = playerLogic.getPlayerInfo(player); if (playerInfo != null && playerInfo.getHasIsland()) { Location p = playerInfo.getIslandLocation(); if (p == null) { return false; } ProtectedRegion region = WorldGuardHandler.getIslandRegionAt(p); return region != null && region.contains(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); } return false; } public boolean hasIsland(final Player player) { PlayerInfo playerInfo = getPlayerInfo(player); return playerInfo != null && playerInfo.getHasIsland(); } public boolean islandAtLocation(final Location loc) { return ((WorldGuardHandler.getIntersectingRegions(loc).size() > 0) || islandLogic.hasIsland(loc) ); } public boolean islandInSpawn(final Location loc) { if (loc == null) { return true; } return WorldGuardHandler.isIslandIntersectingSpawn(loc); } @Override public ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, @Nullable String id) { return getWorldManager().getDefaultWorldGenerator(worldName, id); } public PlayerInfo getPlayerInfo(Player player) { return playerLogic.getPlayerInfo(player); } public PlayerInfo getPlayerInfo(UUID uuid) { return playerLogic.getPlayerInfo(uuid); } public PlayerInfo getPlayerInfo(String playerName) { return playerLogic.getPlayerInfo(playerName); } public boolean setBiome(final Location loc, final String bName) { Biome biome = getBiome(bName); if (biome == null) return false; setBiome(loc, biome); return true; } public Biome getBiome(String bName) { if (bName == null) return null; return BiomeCommand.BIOMES.get(bName.toLowerCase()); } private void setBiome(Location loc, Biome biome) { new SetBiomeTask(this, loc, biome, null).runTask(this); } public void createIsland(final Player player, String cSchem) { PlayerInfo pi = getPlayerInfo(player); if (pi.isIslandGenerating()) { player.sendMessage(tr("\u00a7cYour island is in the process of generating, you cannot create now.")); return; } if (!perkLogic.getSchemes(player).contains(cSchem)) { player.sendMessage(tr("\u00a7eYou do not have access to that island-schematic!")); return; } if (pi != null) { pi.setIslandGenerating(true); } try { Location next = getIslandLocatorLogic().getNextIslandLocation(player); if (getWorldManager().isSkyWorld(player.getWorld())) { getTeleportLogic().spawnTeleport(player, true); } generateIsland(player, pi, next, cSchem); } catch (Exception ex) { player.sendMessage(tr("Could not create your Island. Please contact a server moderator.")); log(Level.SEVERE, "Error creating island", ex); } log(Level.INFO, "Finished creating player island."); } private void generateIsland(final Player player, final PlayerInfo pi, final Location next, final String cSchem) { if (!perkLogic.getSchemes(player).contains(cSchem)) { player.sendMessage(tr("\u00a7eYou do not have access to that island-schematic!")); orphanLogic.addOrphan(next); return; } final PlayerPerk playerPerk = new PlayerPerk(pi, perkLogic.getPerk(player)); player.sendMessage(tr("\u00a7eGetting your island ready, please be patient, it can take a while.")); BukkitRunnable createTask = new CreateIslandTask(this, player, playerPerk, next, cSchem); IslandInfo tempInfo = islandLogic.createIslandInfo(LocationUtil.getIslandName(next), pi.getPlayerName()); WorldGuardHandler.protectIsland(this, player, tempInfo); islandLogic.clearIsland(next, createTask); } public IslandInfo setNewPlayerIsland(final PlayerInfo playerInfo, final Location loc) { playerInfo.startNewIsland(loc); Location chestLocation = LocationUtil.findChestLocation(loc); Optional<Location> chestSpawnLocation = LocationUtil.findNearestSpawnLocation( chestLocation != null ? chestLocation : loc); if (chestSpawnLocation.isPresent()) { playerInfo.setHomeLocation(chestSpawnLocation.get()); } else { log(Level.SEVERE, "Could not find a safe chest within 15 blocks of the island spawn. Bad schematic!"); } IslandInfo info = islandLogic.createIslandInfo(playerInfo.locationForParty(), playerInfo.getPlayerName()); Player onlinePlayer = playerInfo.getPlayer(); if (onlinePlayer != null && onlinePlayer.isOnline()) { info.updatePermissionPerks(onlinePlayer, perkLogic.getPerk(onlinePlayer)); } if (challengeLogic.isResetOnCreate()) { playerInfo.resetAllChallenges(); } playerInfo.save(); return info; } public IslandInfo getIslandInfo(Player player) { PlayerInfo playerInfo = getPlayerInfo(player); return islandLogic.getIslandInfo(playerInfo); } @Override public IslandInfo getIslandInfo(Location location) { return getIslandInfo(WorldGuardHandler.getIslandNameAt(location)); } @Override public boolean isGTE(String versionNumber) { return VersionUtil.getVersion(getDescription().getVersion()).isGTE(versionNumber); } public IslandInfo getIslandInfo(String location) { return islandLogic.getIslandInfo(location); } public IslandInfo getIslandInfo(PlayerInfo pi) { return islandLogic.getIslandInfo(pi); } public SkyBlockMenu getMenu() { return menu; } public ConfigMenu getConfigMenu() { return configMenu; } public ChallengeLogic getChallengeLogic() { return challengeLogic; } public LevelLogic getLevelLogic() { return levelLogic; } public PerkLogic getPerkLogic() { return perkLogic; } public IslandLocatorLogic getIslandLocatorLogic() { return islandLocatorLogic; } @Override public void reloadConfig() { reloadConfigs(); registerEventsAndCommands(); } private void reloadConfigs() { createFolders(); HandlerList.unregisterAll(this); hookManager = new HookManager(this); if (challengeLogic != null) { challengeLogic.shutdown(); } if (playerLogic != null) { playerLogic.shutdown(); } if (islandLogic != null) { islandLogic.shutdown(); } PlaceholderHandler.unregister(this); if (Settings.loadPluginConfig(getConfig())) { saveConfig(); } I18nUtil.clearCache(); // Update all of the loaded configs. FileUtil.reload(); String playerDbStorage = getConfig().getString("options.advanced.playerdb.storage", "yml"); if (playerDbStorage.equalsIgnoreCase("yml")) { playerDB = new FilePlayerDB(this); } else if (playerDbStorage.equalsIgnoreCase("memory")) { playerDB = new MemoryPlayerDB(getConfig()); } else { playerDB = new BukkitPlayerDB(); } getServer().getPluginManager().registerEvents(playerDB, this); worldManager = new WorldManager(this); eventLogic = new EventLogic(this); teleportLogic = new TeleportLogic(this); PlayerUtil.loadConfig(playerDB, getConfig()); islandGenerator = new IslandGenerator(getDataFolder(), getConfig()); perkLogic = new PerkLogic(this, islandGenerator); challengeLogic = new ChallengeLogic(FileUtil.getYmlConfiguration("challenges.yml"), this); menu = new SkyBlockMenu(this, challengeLogic); configMenu = new ConfigMenu(this); YmlConfiguration levelConfig = FileUtil.getYmlConfiguration("levelConfig.yml"); // Disabled until AWE/FAWE supports 1.13 //levelLogic = AsyncWorldEditHandler.isAWE() ? new AweLevelLogic(this, levelConfig) : new ChunkSnapshotLevelLogic(this, levelConfig); levelLogic = new ChunkSnapshotLevelLogic(this, levelConfig); orphanLogic = new OrphanLogic(this); islandLocatorLogic = new IslandLocatorLogic(this); islandLogic = new IslandLogic(this, directoryIslands, orphanLogic); limitLogic = new LimitLogic(this); blockLimitLogic = new BlockLimitLogic(this); notifier = new PlayerNotifier(getConfig()); playerLogic = new PlayerLogic(this); if (autoRecalculateTask != null) { autoRecalculateTask.cancel(); } chatLogic = new ChatLogic(this); } public void registerEventsAndCommands() { if (!isRequirementsMet(Bukkit.getConsoleSender(), null)) { return; } registerEvents(); int refreshEveryMinute = getConfig().getInt("options.island.autoRefreshScore", 0); if (refreshEveryMinute > 0) { int refreshTicks = refreshEveryMinute * 1200; // Ticks per minute autoRecalculateTask = new RecalculateRunnable(this).runTaskTimer(this, refreshTicks, refreshTicks); } else { autoRecalculateTask = null; } confirmHandler = new ConfirmHandler(this, getConfig().getInt("options.advanced.confirmTimeout", 10)); cooldownHandler = new CooldownHandler(this); animationHandler = new AnimationHandler(this); getCommand("island").setExecutor(new IslandCommand(this, menu)); getCommand("challenges").setExecutor(new ChallengeCommand(this)); getCommand("usb").setExecutor(new AdminCommand(this, confirmHandler, animationHandler)); getCommand("islandtalk").setExecutor(new IslandTalkCommand(this, chatLogic)); getCommand("partytalk").setExecutor(new PartyTalkCommand(this, chatLogic)); } public IslandLogic getIslandLogic() { return islandLogic; } public OrphanLogic getOrphanLogic() { return orphanLogic; } public BlockLimitLogic getBlockLimitLogic() { return blockLimitLogic; } /** * @param player The player executing the command * @param command The command to execute * @param onlyInSky Whether the command is restricted to a sky-associated world. */ public void execCommand(Player player, String command, boolean onlyInSky) { if (command == null || player == null) { return; } if (onlyInSky && !getWorldManager().isSkyAssociatedWorld(player.getWorld())) { return; } command = command .replaceAll("\\{player\\}", Matcher.quoteReplacement(player.getName())) .replaceAll("\\{playerName\\}", Matcher.quoteReplacement(player.getDisplayName())) .replaceAll("\\{playername\\}", Matcher.quoteReplacement(player.getDisplayName())) .replaceAll("\\{position\\}", Matcher.quoteReplacement(LocationUtil.asString(player.getLocation()))); // Figure out what this should be Matcher m = Pattern.compile("^\\{p=(?<prob>0?\\.[0-9]+)\\}(.*)$").matcher(command); if (m.matches()) { double p = Double.parseDouble(m.group("prob")); command = m.group(2); if (RND.nextDouble() > p) { return; // Skip the command } } m = Pattern.compile("^\\{d=(?<delay>[0-9]+)\\}(.*)$").matcher(command); int delay = 0; if (m.matches()) { delay = Integer.parseInt(m.group("delay")); command = m.group(2); } if (command.contains("{party}")) { PlayerInfo playerInfo = getPlayerInfo(player); IslandInfo islandInfo = getIslandInfo(playerInfo); for (String member : islandInfo.getMembers()) { doExecCommand(player, command.replaceAll("\\{party\\}", Matcher.quoteReplacement(member)), delay); } } else { doExecCommand(player, command, delay); } } private void doExecCommand(final Player player, final String command, int delay) { if (delay == 0) { sync(new Runnable() { @Override public void run() { doExecCommand(player, command); } }); } else if (delay > 0) { sync(new Runnable() { @Override public void run() { doExecCommand(player, command); } }, delay); } else { log(Level.INFO, "WARN: Misconfigured command found, with negative delay! " + command); } } private void doExecCommand(Player player, String command) { if (command.startsWith("op:")) { if (player.isOp()) { player.performCommand(command.substring(3).trim()); } else { player.setOp(true); // Prevent privilege escalation if called command throws unhandled exception try { player.performCommand(command.substring(3).trim()); } finally { player.setOp(false); } } } else if (command.startsWith("console:")) { getServer().dispatchCommand(getServer().getConsoleSender(), command.substring(8).trim()); } else { player.performCommand(command); } } public USBImporterExecutor getImporter() { if (importer == null) { importer = new USBImporterExecutor(this); } return importer; } public boolean playerIsInSpawn(Player player) { Location pLoc = player.getLocation(); if (!getWorldManager().isSkyWorld(pLoc.getWorld())) { return false; } Location spawnCenter = new Location(WorldManager.skyBlockWorld, 0, pLoc.getBlockY(), 0); return spawnCenter.distance(pLoc) <= Settings.general_spawnSize; } /** * Notify the player, but max. every X seconds. */ public void notifyPlayer(Player player, String msg) { notifier.notifyPlayer(player, msg); } public static uSkyBlockAPI getAPI() { return getInstance(); } // API @Override public List<IslandLevel> getTopTen() { return getRanks(0, 10); } @Override public List<IslandLevel> getRanks(int offset, int length) { return islandLogic != null ? islandLogic.getRanks(offset, length) : Collections.<IslandLevel>emptyList(); } @Override public double getIslandLevel(Player player) { PlayerInfo info = getPlayerInfo(player); if (info != null) { us.talabrek.ultimateskyblock.api.IslandInfo islandInfo = getIslandInfo(info); if (islandInfo != null) { return islandInfo.getLevel(); } } return 0; } @Override public IslandRank getIslandRank(Player player) { PlayerInfo playerInfo = getPlayerInfo(player); return islandLogic != null && playerInfo != null && playerInfo.getHasIsland() ? islandLogic.getRank(playerInfo.locationForParty()) : null; } @Override public IslandRank getIslandRank(Location location) { String islandNameAt = WorldGuardHandler.getIslandNameAt(location); if (islandNameAt != null && islandLogic != null) { return islandLogic.getRank(islandNameAt); } return null; } public void fireChangeEvent(CommandSender sender, uSkyBlockEvent.Cause cause) { Player player = (sender instanceof Player) ? (Player) sender : null; final uSkyBlockEvent event = new uSkyBlockEvent(player, this, cause); fireAsyncEvent(event); } public void fireAsyncEvent(final Event event) { getServer().getScheduler().runTaskAsynchronously(this, () -> getServer().getPluginManager().callEvent(event) ); } public String getVersionInfo(boolean checkEnabled) { PluginDescriptionFile description = getDescription(); String msg = pre("\u00a77Name: \u00a7b{0}\n", description.getName()); msg += pre("\u00a77Version: \u00a7b{0}\n", description.getVersion()); msg += pre("\u00a77Description: \u00a7b{0}\n", description.getDescription()); msg += pre("\u00a77Language: \u00a7b{0} ({1})\n", getConfig().get("language", "en"), I18nUtil.getI18n().getLocale()); msg += pre("\u00a79 State: d={0}, r={1}, i={2}, p={3}, n={4}, awe={5}\n", Settings.island_distance, Settings.island_radius, islandLogic.getSize(), playerLogic.getSize(), Settings.nether_enabled, AsyncWorldEditHandler.isAWE()); msg += pre("\u00a77Server: \u00a7e{0} {1}\n", getServer().getName(), getServer().getVersion()); msg += pre("\u00a79 State: online={0}, bungee={1}\n", ServerUtil.isOnlineMode(), ServerUtil.isBungeeEnabled()); msg += pre("\u00a77------------------------------\n"); for (String[] dep : depends) { Plugin dependency = getServer().getPluginManager().getPlugin(dep[0]); if (dependency != null) { String status = pre("N/A"); if (checkEnabled) { if (dependency.isEnabled()) { if (VersionUtil.getVersion(dependency.getDescription().getVersion()).isLT(dep[1])) { status = pre("\u00a7eWRONG-VERSION"); } else { status = pre("\u00a72ENABLED"); } } else { status = pre("\u00a74DISABLED"); } } msg += pre("\u00a77\u00a7d{0} \u00a7f{1} \u00a77({2}\u00a77)\n", dependency.getName(), dependency.getDescription().getVersion(), status); } } msg += pre("\u00a77------------------------------\n"); return msg; } public PlayerDB getPlayerDB() { return playerDB; } private IslandScore adjustScore(IslandScore score, IslandInfo islandInfo) { IslandPerk islandPerk = perkLogic.getIslandPerk(islandInfo.getSchematicName()); double blockScore = score.getScore(); blockScore = blockScore * islandPerk.getScoreMultiply() * islandInfo.getScoreMultiplier() + islandPerk.getScoreOffset() + islandInfo.getScoreOffset(); return new IslandScore(blockScore, score.getTop()); } public void calculateScoreAsync(final Player player, String islandName, final Callback<us.talabrek.ultimateskyblock.api.model.IslandScore> callback) { final IslandInfo islandInfo = getIslandInfo(islandName); getLevelLogic().calculateScoreAsync(islandInfo.getIslandLocation(), new Callback<IslandScore>() { @Override public void run() { IslandScore score = adjustScore(getState(), islandInfo); callback.setState(score); islandInfo.setLevel(score.getScore()); getIslandLogic().updateRank(islandInfo, score); fireAsyncEvent(new uSkyBlockScoreChangedEvent(player, getInstance(), score, islandInfo.getIslandLocation())); callback.run(); } }); } public ConfirmHandler getConfirmHandler() { return confirmHandler; } public CooldownHandler getCooldownHandler() { return cooldownHandler; } public EventLogic getEventLogic() { return eventLogic; } public PlayerLogic getPlayerLogic() { return playerLogic; } public TeleportLogic getTeleportLogic() { return teleportLogic; } public LimitLogic getLimitLogic() { return limitLogic; } public IslandGenerator getIslandGenerator() { return islandGenerator; } public HookManager getHookManager() { return hookManager; } public WorldManager getWorldManager() { return worldManager; } public boolean isMaintenanceMode() { return maintenanceMode; } /** * CAUTION! If anyone calls this with true, they MUST ensure it is later called with false, * or the plugin will effectively be in a locked state. * * @param maintenanceMode whether or not to enable maintenance-mode. */ public void setMaintenanceMode(boolean maintenanceMode) { this.maintenanceMode = maintenanceMode; if (maintenanceMode) { if (playerLogic != null) { playerLogic.flushCache(); } if (islandLogic != null) { islandLogic.flushCache(); } } } @Override public boolean onCommand(CommandSender sender, org.bukkit.command.Command command, String label, String[] args) { if (!isRequirementsMet(sender, null, args)) { sender.sendMessage(tr("\u00a7cCommand is currently disabled!")); } return true; } public BukkitTask async(Runnable runnable) { return Bukkit.getScheduler().runTaskAsynchronously(this, runnable); } public BukkitTask async(Runnable runnable, long delayMs) { return Bukkit.getScheduler().runTaskLaterAsynchronously(this, runnable, TimeUtil.millisAsTicks(delayMs)); } public BukkitTask async(Runnable runnable, long delay, long every) { return Bukkit.getScheduler().runTaskTimerAsynchronously(this, runnable, TimeUtil.millisAsTicks(delay), TimeUtil.millisAsTicks(every)); } public BukkitTask sync(Runnable runnable) { return Bukkit.getScheduler().runTask(this, runnable); } public BukkitTask sync(Runnable runnable, long delayMs) { return Bukkit.getScheduler().runTaskLater(this, runnable, TimeUtil.millisAsTicks(delayMs)); } public BukkitTask sync(Runnable runnable, long delay, long every) { return Bukkit.getScheduler().runTaskTimer(this, runnable, TimeUtil.millisAsTicks(delay), TimeUtil.millisAsTicks(every)); } public void execCommands(Player player, List<String> cmdList) { for (String cmd : cmdList) { execCommand(player, cmd, false); } } }