diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index 8378e37d2..694c6f319 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -2,6 +2,7 @@ plugins { id "com.github.johnrengelman.shadow" } repositories { + mavenLocal() maven { url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" } maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url = "https://jitpack.io" } @@ -15,7 +16,7 @@ repositories { maven { url = "https://mvn.intellectualsites.com/content/repositories/snapshots" } maven { url = "https://repo.wea-ondara.net/repository/public/" } maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } - mavenLocal() + maven { url = "http://repo.mvdw-software.be/content/groups/public/" } } @@ -25,7 +26,7 @@ dependencies { compile(project(":PlotSquared-Core")) compile("com.destroystokyo.paper:paper-api:1.16.1-R0.1-SNAPSHOT") implementation("org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT") - compile(group: "com.sk89q.worldedit", name: "worldedit-bukkit", version: "7.1.0") { + compile(group: "com.sk89q.worldedit", name: "worldedit-bukkit", version: "7.2.0-SNAPSHOT") { exclude(module: "bukkit") } @@ -44,8 +45,10 @@ dependencies { implementation('net.kyori:adventure-text-minimessage:3.0.0-SNAPSHOT') compile("se.hyperver.hyperverse:Core:0.6.0-SNAPSHOT"){ transitive = false } compile('com.sk89q:squirrelid:1.0.0-SNAPSHOT'){ transitive = false } + compile('be.maximvdw:MVdWPlaceholderAPI:2.1.1-SNAPSHOT'){ transitive = false } // logging implementation('org.apache.logging.log4j:log4j-slf4j-impl:2.8.1') + compile('be.maximvdw:MVdWPlaceholderAPI:3.1.1-SNAPSHOT'){ transitive = false } } sourceCompatibility = 1.8 diff --git a/Bukkit/pom.xml b/Bukkit/pom.xml index b9e6fbb23..6a6cb057e 100644 --- a/Bukkit/pom.xml +++ b/Bukkit/pom.xml @@ -27,7 +27,7 @@ com.plotsquared PlotSquared-Core - 5.12.5 + 6.0.0-SUPER-SNAPSHOT compile @@ -39,7 +39,7 @@ com.sk89q.worldedit worldedit-bukkit - 7.1.0 + 7.2.0-SNAPSHOT compile @@ -90,10 +90,22 @@ + + be.maximvdw + MVdWPlaceholderAPI + 3.1.1-SNAPSHOT + compile + + + * + * + + + com.sk89q.worldedit worldedit-core - 7.0.0 + 7.2.0-SNAPSHOT runtime @@ -110,30 +122,6 @@ - - net.kyori - text-api - 3.0.2 - runtime - - - net.kyori - text-serializer-gson - 3.0.2 - runtime - - - net.kyori - text-serializer-legacy - 3.0.2 - runtime - - - net.kyori - text-serializer-plain - 3.0.2 - runtime - com.google.guava guava @@ -182,6 +170,18 @@ 4.0-dev-106 runtime + + net.kyori + adventure-platform-bukkit + 4.0.0-SNAPSHOT + runtime + + + net.kyori + adventure-text-minimessage + 3.0.0-SNAPSHOT + runtime + org.apache.logging.log4j log4j-slf4j-impl diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index d05fb7bf7..65233e117 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -36,15 +36,19 @@ import com.plotsquared.bukkit.inject.BackupModule; import com.plotsquared.bukkit.inject.BukkitModule; import com.plotsquared.bukkit.inject.PermissionModule; import com.plotsquared.bukkit.inject.WorldManagerModule; +import com.plotsquared.bukkit.listener.BlockEventListener; import com.plotsquared.bukkit.listener.ChunkListener; +import com.plotsquared.bukkit.listener.EntityEventListener; import com.plotsquared.bukkit.listener.EntitySpawnListener; import com.plotsquared.bukkit.listener.PaperListener; -import com.plotsquared.bukkit.listener.PlayerEvents; +import com.plotsquared.bukkit.listener.PlayerEventListener; +import com.plotsquared.bukkit.listener.ProjectileEventListener; +import com.plotsquared.bukkit.listener.ServerListener; import com.plotsquared.bukkit.listener.SingleWorldListener; import com.plotsquared.bukkit.listener.WorldEvents; import com.plotsquared.bukkit.placeholder.PlaceholderFormatter; -import com.plotsquared.bukkit.placeholder.Placeholders; import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.bukkit.placeholder.PAPIPlaceholders; import com.plotsquared.bukkit.player.BukkitPlayerManager; import com.plotsquared.bukkit.util.task.BukkitTaskManager; import com.plotsquared.bukkit.util.BukkitUtil; @@ -94,7 +98,6 @@ import com.plotsquared.core.plot.flag.implementations.ServerPlotFlag; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; -import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.ConsoleColors; @@ -160,7 +163,8 @@ import static com.plotsquared.core.util.PremiumVerification.getResourceID; import static com.plotsquared.core.util.PremiumVerification.getUserID; import static com.plotsquared.core.util.ReflectionUtils.getRefClass; -@SuppressWarnings("unused") public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPlatform { +@SuppressWarnings("unused") +public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPlatform { private static final Logger logger = LoggerFactory.getLogger("P2/" + BukkitPlatform.class.getSimpleName()); private static final int BSTATS_ID = 1404; @@ -233,10 +237,8 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; final PlotSquared plotSquared = new PlotSquared(this, "Bukkit"); if (PlotSquared.platform().getServerVersion()[1] < 13) { - System.out.println( - "You can't use this version of PlotSquared on a server less than Minecraft 1.13.2."); - System.out - .println("Please check the download page for the link to the legacy versions."); + System.out.println("You can't use this version of PlotSquared on a server less than Minecraft 1.13.2."); + System.out.println("Please check the download page for the link to the legacy versions."); System.out.println("The server will now be shutdown to prevent any corruption."); Bukkit.shutdown(); return; @@ -244,11 +246,9 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; // We create the injector after PlotSquared has been initialized, so that we have access // to generated instances and settings - this.injector = Guice.createInjector(Stage.PRODUCTION, new PermissionModule(), - new WorldManagerModule(), - new PlotSquaredModule(), - new BukkitModule(this), - new BackupModule()); + this.injector = Guice + .createInjector(Stage.PRODUCTION, new PermissionModule(), new WorldManagerModule(), new PlotSquaredModule(), new BukkitModule(this), + new BackupModule()); this.injector.injectMembers(this); this.serverLocale = Locale.forLanguageTag(Settings.Enabled_Components.DEFAULT_LOCALE); @@ -292,8 +292,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; // Do stuff that was previously done in PlotSquared // Kill entities - if (Settings.Enabled_Components.KILL_ROAD_MOBS - || Settings.Enabled_Components.KILL_ROAD_VEHICLES) { + if (Settings.Enabled_Components.KILL_ROAD_MOBS || Settings.Enabled_Components.KILL_ROAD_VEHICLES) { this.runEntityTask(); } @@ -311,7 +310,11 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } if (Settings.Enabled_Components.EVENTS) { - getServer().getPluginManager().registerEvents(getInjector().getInstance(PlayerEvents.class), this); + getServer().getPluginManager().registerEvents(getInjector().getInstance(PlayerEventListener.class), this); + getServer().getPluginManager().registerEvents(getInjector().getInstance(BlockEventListener.class), this); + getServer().getPluginManager().registerEvents(getInjector().getInstance(EntityEventListener.class), this); + getServer().getPluginManager().registerEvents(getInjector().getInstance(ProjectileEventListener.class), this); + getServer().getPluginManager().registerEvents(getInjector().getInstance(ServerListener.class), this); getServer().getPluginManager().registerEvents(getInjector().getInstance(EntitySpawnListener.class), this); if (PaperLib.isPaper() && Settings.Paper_Components.PAPER_LISTENERS) { getServer().getPluginManager().registerEvents(getInjector().getInstance(PaperListener.class), this); @@ -325,10 +328,6 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; getServer().getPluginManager().registerEvents(getInjector().getInstance(ChunkListener.class), this); } - // Start the global block queue - final GlobalBlockQueue globalBlockQueue = this.injector.getInstance(GlobalBlockQueue.class); - globalBlockQueue.runTask(); - // Commands if (Settings.Enabled_Components.COMMANDS) { this.registerCommands(); @@ -372,9 +371,9 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; continue; } if (!worldUtil.isWorld(world) && !world.equals("*")) { - logger.warn("[P2] `{}` was not properly loaded - {} will now try to load it properly", - world, this.getPluginName()); - logger.warn("[P2] - Are you trying to delete this world? Remember to remove it from the worlds.yml, bukkit.yml and multiverse worlds.yml"); + logger.warn("[P2] `{}` was not properly loaded - {} will now try to load it properly", world, this.getPluginName()); + logger.warn( + "[P2] - Are you trying to delete this world? Remember to remove it from the worlds.yml, bukkit.yml and multiverse worlds.yml"); logger.warn("[P2] - Your world management plugin may be faulty (or non existent)"); logger.warn("[P2] This message may also be a false positive and could be ignored."); this.setGenerator(world); @@ -408,16 +407,14 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService("user_cache.db"); final SQLiteUUIDService legacyUUIDService; - if (Settings.UUID.LEGACY_DATABASE_SUPPORT && - FileUtils.getFile(PlotSquared.platform().getDirectory(), "usercache.db").exists()) { + if (Settings.UUID.LEGACY_DATABASE_SUPPORT && FileUtils.getFile(PlotSquared.platform().getDirectory(), "usercache.db").exists()) { legacyUUIDService = new SQLiteUUIDService("usercache.db"); } else { legacyUUIDService = null; } final LuckPermsUUIDService luckPermsUUIDService; - if (Settings.UUID.SERVICE_LUCKPERMS && - Bukkit.getPluginManager().getPlugin("LuckPerms") != null) { + if (Settings.UUID.SERVICE_LUCKPERMS && Bukkit.getPluginManager().getPlugin("LuckPerms") != null) { luckPermsUUIDService = new LuckPermsUUIDService(); logger.info("[P2] (UUID) Using LuckPerms as a complementary UUID service"); } else { @@ -425,8 +422,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } final BungeePermsUUIDService bungeePermsUUIDService; - if (Settings.UUID.SERVICE_BUNGEE_PERMS && - Bukkit.getPluginManager().getPlugin("BungeePerms") != null) { + if (Settings.UUID.SERVICE_BUNGEE_PERMS && Bukkit.getPluginManager().getPlugin("BungeePerms") != null) { bungeePermsUUIDService = new BungeePermsUUIDService(); logger.info("[P2] (UUID) Using BungeePerms as a complementary UUID service"); } else { @@ -474,11 +470,9 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; this.backgroundPipeline.registerService(essentialsUUIDService); } - final SquirrelIdUUIDService impromptuMojangService = - new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT); + final SquirrelIdUUIDService impromptuMojangService = new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT); this.impromptuPipeline.registerService(impromptuMojangService); - final SquirrelIdUUIDService backgroundMojangService = - new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT); + final SquirrelIdUUIDService backgroundMojangService = new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT); this.backgroundPipeline.registerService(backgroundMojangService); } else { this.impromptuPipeline.registerService(sqLiteUUIDService); @@ -499,7 +493,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { - injector.getInstance(Placeholders.class).register(); + injector.getInstance(PAPIPlaceholders.class).register(); if (Settings.Enabled_Components.EXTERNAL_PLACEHOLDERS) { ChatFormatter.formatters.add(getInjector().getInstance(PlaceholderFormatter.class)); } @@ -537,8 +531,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; this.methodUnloadSetup = true; try { ReflectionUtils.RefClass classCraftWorld = getRefClass("{cb}.CraftWorld"); - this.methodUnloadChunk0 = classCraftWorld.getRealClass() - .getDeclaredMethod("unloadChunk0", int.class, int.class, boolean.class); + this.methodUnloadChunk0 = classCraftWorld.getRealClass().getDeclaredMethod("unloadChunk0", int.class, int.class, boolean.class); this.methodUnloadChunk0.setAccessible(true); } catch (Throwable event) { event.printStackTrace(); @@ -569,8 +562,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } final Plot plot = area.getOwnedPlot(id); if (plot != null) { - if (!plot.getFlag(ServerPlotFlag.class) || PlotSquared.platform().getPlayerManager() - .getPlayerIfExists(plot.getOwner()) == null) { + if (!plot.getFlag(ServerPlotFlag.class) || PlotSquared.platform().getPlayerManager().getPlayerIfExists(plot.getOwner()) == null) { if (world.getKeepSpawnInMemory()) { world.setKeepSpawnInMemory(false); return; @@ -588,8 +580,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; boolean result; if (methodUnloadChunk0 != null) { try { - result = (boolean) methodUnloadChunk0 - .invoke(world, chunkI.getX(), chunkI.getZ(), true); + result = (boolean) methodUnloadChunk0.invoke(world, chunkI.getX(), chunkI.getZ(), true); } catch (Throwable e) { methodUnloadChunk0 = null; e.printStackTrace(); @@ -612,8 +603,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } } - private void startUuidCaching(@Nonnull final SQLiteUUIDService sqLiteUUIDService, - @Nonnull final CacheUUIDService cacheUUIDService) { + private void startUuidCaching(@Nonnull final SQLiteUUIDService sqLiteUUIDService, @Nonnull final CacheUUIDService cacheUUIDService) { // Load all uuids into a big chunky boi queue final Queue uuidQueue = new LinkedBlockingQueue<>(); PlotSquared.get().forEachPlotRaw(plot -> { @@ -653,8 +643,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; // fresh batch secondRun = false; // Populate the request list - for (int i = 0; - i < Settings.UUID.BACKGROUND_LIMIT && !uuidQueue.isEmpty(); i++) { + for (int i = 0; i < Settings.UUID.BACKGROUND_LIMIT && !uuidQueue.isEmpty(); i++) { uuidList.add(uuidQueue.poll()); read++; } @@ -760,8 +749,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; case "MINECART_TNT": case "BOAT": if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { - com.plotsquared.core.location.Location location = - BukkitUtil.adapt(entity.getLocation()); + com.plotsquared.core.location.Location location = BukkitUtil.adapt(entity.getLocation()); Plot plot = location.getPlot(); if (plot == null) { if (location.isPlotArea()) { @@ -791,9 +779,8 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; case "FIREBALL": case "DRAGON_FIREBALL": case "DROPPED_ITEM": - if (Settings.Enabled_Components.KILL_ROAD_ITEMS && plotArea - .getOwnedPlotAbs(BukkitUtil.adapt(entity.getLocation())) - == null) { + if (Settings.Enabled_Components.KILL_ROAD_ITEMS + && plotArea.getOwnedPlotAbs(BukkitUtil.adapt(entity.getLocation())) == null) { entity.remove(); } // dropped item @@ -817,15 +804,12 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; PlotId originalPlotId = (PlotId) meta.get(0).value(); if (originalPlotId != null) { - com.plotsquared.core.location.Location pLoc = - BukkitUtil.adapt(entity.getLocation()); + com.plotsquared.core.location.Location pLoc = BukkitUtil.adapt(entity.getLocation()); PlotArea area = pLoc.getPlotArea(); if (area != null) { PlotId currentPlotId = area.getPlotAbs(pLoc).getId(); - if (!originalPlotId.equals(currentPlotId) && ( - currentPlotId == null || !area - .getPlot(originalPlotId) - .equals(area.getPlot(currentPlotId)))) { + if (!originalPlotId.equals(currentPlotId) && (currentPlotId == null || !area.getPlot(originalPlotId) + .equals(area.getPlot(currentPlotId)))) { if (entity.hasMetadata("ps-tmp-teleport")) { continue; } @@ -836,15 +820,12 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } } else { //This is to apply the metadata to already spawned shulkers (see EntitySpawnListener.java) - com.plotsquared.core.location.Location pLoc = - BukkitUtil.adapt(entity.getLocation()); + com.plotsquared.core.location.Location pLoc = BukkitUtil.adapt(entity.getLocation()); PlotArea area = pLoc.getPlotArea(); if (area != null) { PlotId currentPlotId = area.getPlotAbs(pLoc).getId(); if (currentPlotId != null) { - entity.setMetadata("shulkerPlot", - new FixedMetadataValue( - (Plugin) PlotSquared.platform(), currentPlotId)); + entity.setMetadata("shulkerPlot", new FixedMetadataValue((Plugin) PlotSquared.platform(), currentPlotId)); } } } @@ -925,11 +906,9 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; if (BukkitUtil.adapt(location).isPlotRoad()) { if (entity instanceof LivingEntity) { LivingEntity livingEntity = (LivingEntity) entity; - if (!livingEntity.isLeashed() || !entity - .hasMetadata("keep")) { + if (!livingEntity.isLeashed() || !entity.hasMetadata("keep")) { Entity passenger = entity.getPassenger(); - if (!(passenger instanceof Player) && entity - .getMetadata("keep").isEmpty()) { + if (!(passenger instanceof Player) && entity.getMetadata("keep").isEmpty()) { if (entity.hasMetadata("ps-tmp-teleport")) { continue; } @@ -940,8 +919,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } } else { Entity passenger = entity.getPassenger(); - if (!(passenger instanceof Player) && entity - .getMetadata("keep").isEmpty()) { + if (!(passenger instanceof Player) && entity.getMetadata("keep").isEmpty()) { if (entity.hasMetadata("ps-tmp-teleport")) { continue; } @@ -962,9 +940,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; }), TaskTime.seconds(1L)); } - @Override @Nullable - public final ChunkGenerator getDefaultWorldGenerator(@Nonnull final String worldName, - final String id) { + @Override @Nullable public final ChunkGenerator getDefaultWorldGenerator(@Nonnull final String worldName, final String id) { final IndependentPlotGenerator result; if (id != null && id.equalsIgnoreCase("single")) { result = getInjector().getInstance(SingleWorldGenerator.class); @@ -977,8 +953,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; return (ChunkGenerator) result.specify(worldName); } - @Override @Nullable public GeneratorWrapper getGenerator(@Nonnull final String world, - @Nullable final String name) { + @Override @Nullable public GeneratorWrapper getGenerator(@Nonnull final String world, @Nullable final String name) { if (name == null) { return null; } @@ -990,8 +965,8 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } return new BukkitPlotGenerator(world, gen, this.plotAreaManager); } else { - return new BukkitPlotGenerator(world, getInjector() - .getInstance(Key.get(IndependentPlotGenerator.class, DefaultGenerator.class)), this.plotAreaManager); + return new BukkitPlotGenerator(world, getInjector().getInstance(Key.get(IndependentPlotGenerator.class, DefaultGenerator.class)), + this.plotAreaManager); } } @@ -1011,19 +986,14 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; map.put(plotAreaType.name().toLowerCase(), terrainTypes); } for (final PlotArea plotArea : this.plotAreaManager.getAllPlotAreas()) { - final Map terrainTypeMap = - map.get(plotArea.getType().name().toLowerCase()); - terrainTypeMap.put(plotArea.getTerrain().name().toLowerCase(), - terrainTypeMap.get(plotArea.getTerrain().name().toLowerCase()) + 1); + final Map terrainTypeMap = map.get(plotArea.getType().name().toLowerCase()); + terrainTypeMap.put(plotArea.getTerrain().name().toLowerCase(), terrainTypeMap.get(plotArea.getTerrain().name().toLowerCase()) + 1); } return map; })); - metrics.addCustomChart(new Metrics.SimplePie("premium", - () -> PremiumVerification.isPremium() ? "Premium" : "Non-Premium")); + metrics.addCustomChart(new Metrics.SimplePie("premium", () -> PremiumVerification.isPremium() ? "Premium" : "Non-Premium")); metrics.addCustomChart(new Metrics.SimplePie("worldedit_implementation", - () -> Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit") != null ? - "FastAsyncWorldEdit" : - "WorldEdit")); + () -> Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit") != null ? "FastAsyncWorldEdit" : "WorldEdit")); } @Override public void unregister(@Nonnull final PlotPlayer player) { @@ -1036,12 +1006,10 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; // create world ConfigurationSection worldConfig = this.worldConfiguration.getConfigurationSection("worlds." + worldName); String manager = worldConfig.getString("generator.plugin", getPluginName()); - PlotAreaBuilder builder = PlotAreaBuilder.newBuilder().plotManager(manager) - .generatorName(worldConfig.getString("generator.init", manager)) - .plotAreaType(ConfigurationUtil.getType(worldConfig)) - .terrainType(ConfigurationUtil.getTerrain(worldConfig)) - .settingsNodesWrapper(new SettingsNodesWrapper(new ConfigurationNode[0], null)) - .worldName(worldName); + PlotAreaBuilder builder = + PlotAreaBuilder.newBuilder().plotManager(manager).generatorName(worldConfig.getString("generator.init", manager)) + .plotAreaType(ConfigurationUtil.getType(worldConfig)).terrainType(ConfigurationUtil.getTerrain(worldConfig)) + .settingsNodesWrapper(new SettingsNodesWrapper(new ConfigurationNode[0], null)).worldName(worldName); getInjector().getInstance(SetupUtils.class).setupWorld(builder); world = Bukkit.getWorld(worldName); } else { @@ -1071,16 +1039,14 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; return name.substring(name.lastIndexOf('.') + 1); } - @Override public GeneratorWrapper wrapPlotGenerator(@Nullable final String world, - @Nonnull final IndependentPlotGenerator generator) { + @Override public GeneratorWrapper wrapPlotGenerator(@Nullable final String world, @Nonnull final IndependentPlotGenerator generator) { return new BukkitPlotGenerator(world, generator, this.plotAreaManager); } @Override public List, Boolean>> getPluginIds() { List, Boolean>> names = new ArrayList<>(); for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) { - Map.Entry id = new AbstractMap.SimpleEntry<>(plugin.getName(), - plugin.getDescription().getVersion()); + Map.Entry id = new AbstractMap.SimpleEntry<>(plugin.getName(), plugin.getDescription().getVersion()); names.add(new AbstractMap.SimpleEntry<>(id, plugin.isEnabled())); } return names; @@ -1115,11 +1081,11 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } @Override @Nonnull public PlatformWorldManager getWorldManager() { - return getInjector().getInstance(Key.get(new TypeLiteral>() {})); + return getInjector().getInstance(Key.get(new TypeLiteral>() { + })); } - @Override @Nonnull @SuppressWarnings("ALL") - public PlayerManager, ? extends Player> getPlayerManager() { + @Override @Nonnull @SuppressWarnings("ALL") public PlayerManager, ? extends Player> getPlayerManager() { return (PlayerManager) getInjector().getInstance(PlayerManager.class); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java index e74266394..9a05dd773 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BlockStatePopulator.java @@ -30,8 +30,9 @@ import com.plotsquared.core.generator.IndependentPlotGenerator; import com.plotsquared.core.location.ChunkWrapper; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.queue.LocalBlockQueue; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.queue.ScopedQueueCoordinator; +import com.sk89q.worldedit.bukkit.BukkitWorld; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.generator.BlockPopulator; @@ -44,30 +45,25 @@ final class BlockStatePopulator extends BlockPopulator { private final IndependentPlotGenerator plotGenerator; private final PlotAreaManager plotAreaManager; - private LocalBlockQueue queue; + private QueueCoordinator queue; - public BlockStatePopulator(@Nonnull final IndependentPlotGenerator plotGenerator, - @Nonnull final PlotAreaManager plotAreaManager) { + public BlockStatePopulator(@Nonnull final IndependentPlotGenerator plotGenerator, @Nonnull final PlotAreaManager plotAreaManager) { this.plotGenerator = plotGenerator; this.plotAreaManager = plotAreaManager; } - @Override - public void populate(@Nonnull final World world, @Nonnull final Random random, - @Nonnull final Chunk source) { + @Override public void populate(@Nonnull final World world, @Nonnull final Random random, @Nonnull final Chunk source) { if (this.queue == null) { - this.queue = PlotSquared.platform().getGlobalBlockQueue() - .getNewQueue(world.getName(), false); + this.queue = PlotSquared.platform().getGlobalBlockQueue().getNewQueue(new BukkitWorld(world)); } final PlotArea area = this.plotAreaManager.getPlotArea(world.getName(), null); if (area == null) { return; } - final ChunkWrapper wrap = - new ChunkWrapper(area.getWorldName(), source.getX(), source.getZ()); - final ScopedLocalBlockQueue chunk = this.queue.getForChunk(wrap.x, wrap.z); + final ChunkWrapper wrap = new ChunkWrapper(area.getWorldName(), source.getX(), source.getZ()); + final ScopedQueueCoordinator chunk = this.queue.getForChunk(wrap.x, wrap.z); if (this.plotGenerator.populateChunk(chunk, area)) { - this.queue.flush(); + this.queue.enqueue(); } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java index 94d6d99e4..c1db952e2 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/BukkitPlotGenerator.java @@ -34,7 +34,7 @@ import com.plotsquared.core.generator.SingleWorldGenerator; import com.plotsquared.core.location.ChunkWrapper; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.ChunkManager; import com.sk89q.worldedit.math.BlockVector2; import org.bukkit.World; @@ -62,7 +62,7 @@ public class BukkitPlotGenerator extends ChunkGenerator private final String levelName; - public BukkitPlotGenerator(@Nonnull final String name, + public BukkitPlotGenerator(@Nonnull final String name, @Nonnull final IndependentPlotGenerator generator, @Nonnull final PlotAreaManager plotAreaManager) { this.plotAreaManager = plotAreaManager; @@ -186,7 +186,7 @@ public class BukkitPlotGenerator extends ChunkGenerator return result.getChunkData(); } - private void generate(BlockVector2 loc, World world, ScopedLocalBlockQueue result) { + private void generate(BlockVector2 loc, World world, ScopedQueueCoordinator result) { // Load if improperly loaded if (!this.loaded) { String name = world.getName(); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/DelegatePlotGenerator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/DelegatePlotGenerator.java index 6906c446d..6a0a3ce7d 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/DelegatePlotGenerator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/DelegatePlotGenerator.java @@ -31,7 +31,7 @@ import com.plotsquared.core.generator.IndependentPlotGenerator; import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.MathMan; import com.sk89q.worldedit.bukkit.BukkitAdapter; import org.bukkit.World; @@ -63,7 +63,7 @@ final class DelegatePlotGenerator extends IndependentPlotGenerator { return PlotSquared.platform().getDefaultGenerator().getNewPlotArea(world, id, min, max); } - @Override public void generateChunk(final ScopedLocalBlockQueue result, PlotArea settings) { + @Override public void generateChunk(final ScopedQueueCoordinator result, PlotArea settings) { World world = BukkitUtil.getWorld(this.world); Location min = result.getMin(); int chunkX = min.getX() >> 4; @@ -71,11 +71,7 @@ final class DelegatePlotGenerator extends IndependentPlotGenerator { Random random = new Random(MathMan.pair((short) chunkX, (short) chunkZ)); try { ChunkGenerator.BiomeGrid grid = new ChunkGenerator.BiomeGrid() { - @Override - public void setBiome( - final int x, - final int z, - @Nonnull final Biome biome) { + @Override public void setBiome(int x, int z, @Nonnull Biome biome) { result.setBiome(x, z, BukkitAdapter.adapt(biome)); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java index cbd5dc213..a5702d156 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java @@ -31,7 +31,8 @@ import com.google.inject.Singleton; import com.google.inject.assistedinject.FactoryModuleBuilder; import com.plotsquared.bukkit.BukkitPlatform; import com.plotsquared.bukkit.player.BukkitPlayerManager; -import com.plotsquared.bukkit.queue.BukkitLocalQueue; +import com.plotsquared.bukkit.queue.BukkitChunkCoordinator; +import com.plotsquared.bukkit.queue.BukkitQueueCoordinator; import com.plotsquared.bukkit.schematic.BukkitSchematicHandler; import com.plotsquared.bukkit.util.BukkitChunkManager; import com.plotsquared.bukkit.util.BukkitEconHandler; @@ -45,10 +46,13 @@ import com.plotsquared.core.generator.HybridGen; import com.plotsquared.core.generator.IndependentPlotGenerator; import com.plotsquared.core.inject.annotations.ConsoleActor; import com.plotsquared.core.inject.annotations.DefaultGenerator; +import com.plotsquared.core.inject.factory.ChunkCoordinatorBuilderFactory; +import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory; import com.plotsquared.core.inject.factory.HybridPlotWorldFactory; import com.plotsquared.core.plot.world.DefaultPlotAreaManager; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotAreaManager; +import com.plotsquared.core.queue.ChunkCoordinator; import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.QueueProvider; import com.plotsquared.core.util.ChunkManager; @@ -88,8 +92,7 @@ public class BukkitModule extends AbstractModule { bind(InventoryUtil.class).to(BukkitInventoryUtil.class); bind(SetupUtils.class).to(BukkitSetupUtils.class); bind(WorldUtil.class).to(BukkitUtil.class); - bind(GlobalBlockQueue.class).toInstance(new GlobalBlockQueue( - QueueProvider.of(BukkitLocalQueue.class, BukkitLocalQueue.class), 1, Settings.QUEUE.TARGET_TIME)); + bind(GlobalBlockQueue.class).toInstance(new GlobalBlockQueue(QueueProvider.of(BukkitQueueCoordinator.class))); bind(ChunkManager.class).to(BukkitChunkManager.class); bind(RegionManager.class).to(BukkitRegionManager.class); bind(SchematicHandler.class).to(BukkitSchematicHandler.class); @@ -99,6 +102,8 @@ public class BukkitModule extends AbstractModule { bind(PlotAreaManager.class).to(DefaultPlotAreaManager.class); } install(new FactoryModuleBuilder().build(HybridPlotWorldFactory.class)); + install(new FactoryModuleBuilder().implement(ChunkCoordinator.class, BukkitChunkCoordinator.class).build(ChunkCoordinatorFactory.class)); + install(new FactoryModuleBuilder().build(ChunkCoordinatorBuilderFactory.class)); } @Provides @Singleton @Nullable EconHandler provideEconHandler() { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/BlockEventListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/BlockEventListener.java new file mode 100644 index 000000000..99828db99 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/BlockEventListener.java @@ -0,0 +1,1078 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.listener; + +import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.Permission; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.flag.implementations.BlockBurnFlag; +import com.plotsquared.core.plot.flag.implementations.BlockIgnitionFlag; +import com.plotsquared.core.plot.flag.implementations.BreakFlag; +import com.plotsquared.core.plot.flag.implementations.CoralDryFlag; +import com.plotsquared.core.plot.flag.implementations.DisablePhysicsFlag; +import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.plot.flag.implementations.ExplosionFlag; +import com.plotsquared.core.plot.flag.implementations.GrassGrowFlag; +import com.plotsquared.core.plot.flag.implementations.IceFormFlag; +import com.plotsquared.core.plot.flag.implementations.IceMeltFlag; +import com.plotsquared.core.plot.flag.implementations.InstabreakFlag; +import com.plotsquared.core.plot.flag.implementations.KelpGrowFlag; +import com.plotsquared.core.plot.flag.implementations.LiquidFlowFlag; +import com.plotsquared.core.plot.flag.implementations.MycelGrowFlag; +import com.plotsquared.core.plot.flag.implementations.PlaceFlag; +import com.plotsquared.core.plot.flag.implementations.RedstoneFlag; +import com.plotsquared.core.plot.flag.implementations.SnowFormFlag; +import com.plotsquared.core.plot.flag.implementations.SnowMeltFlag; +import com.plotsquared.core.plot.flag.implementations.SoilDryFlag; +import com.plotsquared.core.plot.flag.implementations.VineGrowFlag; +import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; +import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.task.TaskManager; +import com.plotsquared.core.util.task.TaskTime; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.world.block.BlockType; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Fireball; +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.block.BlockBreakEvent; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.block.BlockDispenseEvent; +import org.bukkit.event.block.BlockExplodeEvent; +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.world.StructureGrowEvent; +import org.bukkit.material.Directional; +import org.bukkit.projectiles.BlockProjectileSource; +import org.bukkit.util.Vector; + +import javax.annotation.Nonnull; +import javax.inject.Inject; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +@SuppressWarnings("unused") +public class BlockEventListener implements Listener { + + private final PlotAreaManager plotAreaManager; + private final WorldEdit worldEdit; + + @Inject public BlockEventListener(@Nonnull final PlotAreaManager plotAreaManager, @Nonnull final WorldEdit worldEdit) { + this.plotAreaManager = plotAreaManager; + this.worldEdit = worldEdit; + } + + public static void sendBlockChange(final org.bukkit.Location bloc, final BlockData data) { + TaskManager.runTaskLater(() -> { + String world = bloc.getWorld().getName(); + int x = bloc.getBlockX(); + int z = bloc.getBlockZ(); + int distance = Bukkit.getViewDistance() * 16; + + for (final PlotPlayer player : PlotSquared.platform().getPlayerManager().getPlayers()) { + Location location = player.getLocation(); + if (location.getWorldName().equals(world)) { + if (16 * Math.abs(location.getX() - x) / 16 > distance || 16 * Math.abs(location.getZ() - z) / 16 > distance) { + continue; + } + ((BukkitPlayer) player).player.sendBlockChange(bloc, data); + } + } + }, TaskTime.ticks(3L)); + } + + @EventHandler public void onRedstoneEvent(BlockRedstoneEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = location.getOwnedPlot(); + if (plot == null) { + if (area.isRoadFlags() && !area.getRoadFlag(RedstoneFlag.class)) { + event.setNewCurrent(0); + } + return; + } + if (!plot.getFlag(RedstoneFlag.class)) { + event.setNewCurrent(0); + plot.debug("Redstone event was cancelled because redstone = false"); + return; + } + if (Settings.Redstone.DISABLE_OFFLINE) { + boolean disable = false; + if (!plot.getOwner().equals(DBFunc.SERVER)) { + if (plot.isMerged()) { + disable = true; + for (UUID owner : plot.getOwners()) { + if (PlotSquared.platform().getPlayerManager().getPlayerIfExists(owner) != null) { + disable = false; + break; + } + } + } else { + disable = PlotSquared.platform().getPlayerManager().getPlayerIfExists(plot.getOwnerAbs()) == null; + } + } + if (disable) { + for (UUID trusted : plot.getTrusted()) { + if (PlotSquared.platform().getPlayerManager().getPlayerIfExists(trusted) != null) { + disable = false; + break; + } + } + if (disable) { + event.setNewCurrent(0); + plot.debug("Redstone event was cancelled because no trusted player was in the plot"); + return; + } + } + } + if (Settings.Redstone.DISABLE_UNOCCUPIED) { + for (final PlotPlayer player : PlotSquared.platform().getPlayerManager().getPlayers()) { + if (plot.equals(player.getCurrentPlot())) { + return; + } + } + event.setNewCurrent(0); + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onPhysicsEvent(BlockPhysicsEvent event) { + switch (event.getChangedType()) { + case COMPARATOR: { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + if (location.isPlotArea()) { + return; + } + Plot plot = location.getOwnedPlotAbs(); + if (plot == null) { + return; + } + if (!plot.getFlag(RedstoneFlag.class)) { + event.setCancelled(true); + plot.debug("Prevented comparator update because redstone = false"); + } + return; + } + case ANVIL: + case DRAGON_EGG: + case GRAVEL: + case SAND: + case TURTLE_EGG: + case TURTLE_HELMET: + case TURTLE_SPAWN_EGG: { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlotAbs(location); + if (plot == null) { + return; + } + if (plot.getFlag(DisablePhysicsFlag.class)) { + event.setCancelled(true); + plot.debug("Prevented block physics because disable-physics = true"); + } + return; + } + default: + if (Settings.Redstone.DETECT_INVALID_EDGE_PISTONS) { + Block block = event.getBlock(); + switch (block.getType()) { + case PISTON: + case STICKY_PISTON: + org.bukkit.block.data.Directional piston = (org.bukkit.block.data.Directional) block.getBlockData(); + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlotAbs(location); + if (plot == null) { + return; + } + switch (piston.getFacing()) { + case EAST: + location = location.add(1, 0, 0); + break; + case SOUTH: + location = location.add(-1, 0, 0); + break; + case WEST: + location = location.add(0, 0, 1); + break; + case NORTH: + location = location.add(0, 0, -1); + break; + } + Plot newPlot = area.getOwnedPlotAbs(location); + if (!plot.equals(newPlot)) { + event.setCancelled(true); + plot.debug("Prevented piston update because of invalid edge piston detection"); + return; + } + } + } + break; + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void blockCreate(BlockPlaceEvent event) { + Location location = BukkitUtil.adapt(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(player); + Plot plot = area.getPlot(location); + if (plot != null) { + if ((location.getY() > area.getMaxBuildHeight() || location.getY() < area + .getMinBuildHeight()) && !Permissions + .hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { + event.setCancelled(true); + pp.sendMessage( + TranslatableCaption.of("height.height_limit"), + Template.of("limit", String.valueOf(area.getMaxBuildHeight())) + ); + } + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + return; + } + } else if (!plot.isAdded(pp.getUUID())) { + List place = plot.getFlag(PlaceFlag.class); + if (place != null) { + Block block = event.getBlock(); + if (place.contains( + BlockTypeWrapper.get(BukkitAdapter.asBlockType(block.getType())))) { + return; + } + } + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + plot.debug(player.getName() + " could not place " + event.getBlock().getType() + + " because of the place flag"); + return; + } + } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + return; + } + } + if (plot.getFlag(DisablePhysicsFlag.class)) { + Block block = event.getBlockPlaced(); + if (block.getType().hasGravity()) { + sendBlockChange(block.getLocation(), block.getBlockData()); + plot.debug(event.getBlock().getType() + + " did not fall because of disable-physics = true"); + } + } + } else if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_ROAD)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.LOWEST) public void blockDestroy(BlockBreakEvent event) { + Player player = event.getPlayer(); + Location location = BukkitUtil.adapt(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getPlot(location); + if (plot != null) { + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + if (event.getBlock().getY() == 0) { + if (!Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.groundlevel") + ); + event.setCancelled(true); + return; + } + } else if ((location.getY() > area.getMaxBuildHeight() || location.getY() < area + .getMinBuildHeight()) && !Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { + event.setCancelled(true); + plotPlayer.sendMessage( + TranslatableCaption.of("height.height_limit"), + Template.of("limit", String.valueOf(area.getMaxBuildHeight())) + ); + } + if (!plot.hasOwner()) { + if (!Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY_UNOWNED, true)) { + event.setCancelled(true); + } + return; + } + if (!plot.isAdded(plotPlayer.getUUID())) { + List destroy = plot.getFlag(BreakFlag.class); + Block block = event.getBlock(); + final BlockType blockType = BukkitAdapter.asBlockType(block.getType()); + for (final BlockTypeWrapper blockTypeWrapper : destroy) { + if (blockTypeWrapper.accepts(blockType)) { + return; + } + } + if (Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY_OTHER)) { + return; + } + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.other") + ); + event.setCancelled(true); + } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + if (!Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + return; + } + } + return; + } + BukkitPlayer pp = BukkitUtil.adapt(player); + if (Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_DESTROY_ROAD)) { + return; + } + if (this.worldEdit!= null && pp.getAttribute("worldedit")) { + if (player.getInventory().getItemInMainHand().getType() == Material + .getMaterial(this.worldEdit.getConfiguration().wandItem)) { + return; + } + } + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.road") + ); + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockSpread(BlockSpreadEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + if (location.isPlotRoad()) { + event.setCancelled(true); + return; + } + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + return; + } + switch (event.getSource().getType()) { + case GRASS_BLOCK: + if (!plot.getFlag(GrassGrowFlag.class)) { + plot.debug("Grass could not grow because grass-grow = false"); + event.setCancelled(true); + } + break; + case MYCELIUM: + if (!plot.getFlag(MycelGrowFlag.class)) { + plot.debug("Mycelium could not grow because mycel-grow = false"); + event.setCancelled(true); + } + break; + case VINE: + if (!plot.getFlag(VineGrowFlag.class)) { + plot.debug("Vine could not grow because vine-grow = false"); + event.setCancelled(true); + } + break; + case KELP: + if (!plot.getFlag(KelpGrowFlag.class)) { + plot.debug("Kelp could not grow because kelp-grow = false"); + event.setCancelled(true); + } + break; + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockForm(BlockFormEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + if (location.isPlotRoad()) { + event.setCancelled(true); + return; + } + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + return; + } + switch (event.getNewState().getType()) { + case SNOW: + case SNOW_BLOCK: + if (!plot.getFlag(SnowFormFlag.class)) { + plot.debug("Snow could not form because snow-form = false"); + event.setCancelled(true); + } + return; + case ICE: + case FROSTED_ICE: + case PACKED_ICE: + if (!plot.getFlag(IceFormFlag.class)) { + plot.debug("Ice could not form because ice-form = false"); + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onEntityBlockForm(EntityBlockFormEvent event) { + String world = event.getBlock().getWorld().getName(); + if (!this.plotAreaManager.hasPlotArea(world)) { + return; + } + Location location = BukkitUtil.adapt(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + event.setCancelled(true); + return; + } + Entity entity = event.getEntity(); + if (entity instanceof Player) { + Player player = (Player) entity; + if (!plot.hasOwner()) { + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + if (plot.getFlag(IceFormFlag.class)) { + plot.debug("Ice could not be formed because ice-form = false"); + return; + } + event.setCancelled(true); + return; + } + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + if (!plot.isAdded(plotPlayer.getUUID())) { + if (plot.getFlag(IceFormFlag.class)) { + plot.debug("Ice could not be formed because ice-form = false"); + return; + } + event.setCancelled(true); + return; + } + return; + } + if (!plot.getFlag(IceFormFlag.class)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockDamage(BlockDamageEvent event) { + Player player = event.getPlayer(); + Location location = BukkitUtil.adapt(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + if (player.getGameMode() != GameMode.SURVIVAL) { + return; + } + Plot plot = area.getPlot(location); + if (plot != null) { + if (plot.getFlag(InstabreakFlag.class)) { + Block block = event.getBlock(); + BlockBreakEvent call = new BlockBreakEvent(block, player); + Bukkit.getServer().getPluginManager().callEvent(call); + if (!call.isCancelled()) { + event.getBlock().breakNaturally(); + } + } + if (location.getY() == 0) { + event.setCancelled(true); + return; + } + if (!plot.hasOwner()) { + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + if (Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY_UNOWNED)) { + return; + } + event.setCancelled(true); + return; + } + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + if (!plot.isAdded(plotPlayer.getUUID())) { + List destroy = plot.getFlag(BreakFlag.class); + Block block = event.getBlock(); + if (destroy + .contains(BlockTypeWrapper.get(BukkitAdapter.asBlockType(block.getType()))) + || Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY_OTHER)) { + return; + } + plot.debug(player.getName() + " could not break " + block.getType() + + " because it was not in the break flag"); + event.setCancelled(true); + return; + } + return; + } + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + if (Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY_ROAD)) { + return; + } + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onFade(BlockFadeEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + event.setCancelled(true); + return; + } + switch (block.getType()) { + case ICE: + if (!plot.getFlag(IceMeltFlag.class)) { + plot.debug("Ice could not melt because ice-melt = false"); + event.setCancelled(true); + } + break; + case SNOW: + if (!plot.getFlag(SnowMeltFlag.class)) { + plot.debug("Snow could not melt because snow-melt = false"); + event.setCancelled(true); + } + break; + case FARMLAND: + if (!plot.getFlag(SoilDryFlag.class)) { + plot.debug("Soil could not dry because soil-dry = false"); + event.setCancelled(true); + } + break; + case TUBE_CORAL_BLOCK: + case BRAIN_CORAL_BLOCK: + case BUBBLE_CORAL_BLOCK: + case FIRE_CORAL_BLOCK: + case HORN_CORAL_BLOCK: + case TUBE_CORAL: + case BRAIN_CORAL: + case BUBBLE_CORAL: + case FIRE_CORAL: + case HORN_CORAL: + case TUBE_CORAL_FAN: + case BRAIN_CORAL_FAN: + case BUBBLE_CORAL_FAN: + case FIRE_CORAL_FAN: + case HORN_CORAL_FAN: + case BRAIN_CORAL_WALL_FAN: + case BUBBLE_CORAL_WALL_FAN: + case FIRE_CORAL_WALL_FAN: + case HORN_CORAL_WALL_FAN: + case TUBE_CORAL_WALL_FAN: + if (!plot.getFlag(CoralDryFlag.class)) { + plot.debug("Coral could not dry because coral-dry = false"); + event.setCancelled(true); + } + break; + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onChange(BlockFromToEvent event) { + Block from = event.getBlock(); + + // Check liquid flow flag inside of origin plot too + final Location fLocation = BukkitUtil.adapt(from.getLocation()); + final PlotArea fromArea = fLocation.getPlotArea(); + if (fromArea != null) { + final Plot plot = fromArea.getOwnedPlot(fLocation); + if (plot != null && plot.getFlag(LiquidFlowFlag.class) == LiquidFlowFlag.FlowStatus.DISABLED && event.getBlock().isLiquid()) { + plot.debug("Liquid could now flow because liquid-flow = disabled"); + event.setCancelled(true); + return; + } + } + + Block to = event.getToBlock(); + Location tLocation = BukkitUtil.adapt(to.getLocation()); + PlotArea area = tLocation.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(tLocation); + if (plot != null) { + if (!area.contains(fLocation.getX(), fLocation.getZ()) || !Objects.equals(plot, area.getOwnedPlot(fLocation))) { + event.setCancelled(true); + return; + } + if (plot.getFlag(LiquidFlowFlag.class) == LiquidFlowFlag.FlowStatus.ENABLED && event.getBlock().isLiquid()) { + return; + } + if (plot.getFlag(DisablePhysicsFlag.class)) { + plot.debug(event.getBlock().getType() + " could not update because disable-physics = true"); + event.setCancelled(true); + return; + } + if (plot.getFlag(LiquidFlowFlag.class) == LiquidFlowFlag.FlowStatus.DISABLED && event.getBlock().isLiquid()) { + plot.debug("Liquid could not flow because liquid-flow = disabled"); + event.setCancelled(true); + } + } else if (!area.contains(fLocation.getX(), fLocation.getZ()) || !Objects.equals(null, area.getOwnedPlot(fLocation))) { + event.setCancelled(true); + } else if (event.getBlock().isLiquid()) { + final org.bukkit.Location location = event.getBlock().getLocation(); + + /* + X = block location + A-H = potential plot locations + Z + ^ + | A B C + o D X E + | F G H + v + <-----O-----> x + */ + if (BukkitUtil.adapt(location.clone().add(-1, 0, 1) /* A */).getPlot() != null + || BukkitUtil.adapt(location.clone().add(1, 0, 0) /* B */).getPlot() != null + || BukkitUtil.adapt(location.clone().add(1, 0, 1) /* C */).getPlot() != null + || BukkitUtil.adapt(location.clone().add(-1, 0, 0) /* D */).getPlot() != null + || BukkitUtil.adapt(location.clone().add(1, 0, 0) /* E */).getPlot() != null + || BukkitUtil.adapt(location.clone().add(-1, 0, -1) /* F */).getPlot() != null + || BukkitUtil.adapt(location.clone().add(0, 0, -1) /* G */).getPlot() != null + || BukkitUtil.adapt(location.clone().add(1, 0, 1) /* H */).getPlot() != null) { + event.setCancelled(true); + } + } + } + + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onGrow(BlockGrowEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + if (location.isUnownedPlotArea()) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockPistonExtend(BlockPistonExtendEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + BlockFace face = event.getDirection(); + Vector relative = new Vector(face.getModX(), face.getModY(), face.getModZ()); + PlotArea area = location.getPlotArea(); + if (area == null) { + if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) { + return; + } + for (Block block1 : event.getBlocks()) { + Location bloc = BukkitUtil.adapt(block1.getLocation()); + if (bloc.isPlotArea() || bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ()).isPlotArea()) { + event.setCancelled(true); + return; + } + } + if (location.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ()).isPlotArea()) { + // Prevent pistons from extending if they are: bordering a plot + // area, facing inside plot area, and not pushing any blocks + event.setCancelled(true); + } + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + event.setCancelled(true); + return; + } + for (Block block1 : event.getBlocks()) { + Location bloc = BukkitUtil.adapt(block1.getLocation()); + if (!area.contains(bloc.getX(), bloc.getZ()) || !area.contains(bloc.getX() + relative.getBlockX(), bloc.getZ() + relative.getBlockZ())) { + event.setCancelled(true); + return; + } + if (!plot.equals(area.getOwnedPlot(bloc)) || !plot + .equals(area.getOwnedPlot(bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ())))) { + event.setCancelled(true); + return; + } + } + if (!plot.equals(area.getOwnedPlot(location.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ())))) { + // This branch is only necessary to prevent pistons from extending + // if they are: on a plot edge, facing outside the plot, and not + // pushing any blocks + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockPistonRetract(BlockPistonRetractEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + BlockFace face = event.getDirection(); + Vector relative = new Vector(face.getModX(), face.getModY(), face.getModZ()); + PlotArea area = location.getPlotArea(); + if (area == null) { + if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) { + return; + } + for (Block block1 : event.getBlocks()) { + Location bloc = BukkitUtil.adapt(block1.getLocation()); + if (bloc.isPlotArea() || bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ()).isPlotArea()) { + event.setCancelled(true); + return; + } + } + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + event.setCancelled(true); + return; + } + for (Block block1 : event.getBlocks()) { + Location bloc = BukkitUtil.adapt(block1.getLocation()); + if (!area.contains(bloc.getX(), bloc.getZ()) || !area.contains(bloc.getX() + relative.getBlockX(), bloc.getZ() + relative.getBlockZ())) { + event.setCancelled(true); + return; + } + if (!plot.equals(area.getOwnedPlot(bloc)) || !plot + .equals(area.getOwnedPlot(bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ())))) { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockDispense(BlockDispenseEvent event) { + Material type = event.getItem().getType(); + switch (type) { + case SHULKER_BOX: + case WHITE_SHULKER_BOX: + case ORANGE_SHULKER_BOX: + case MAGENTA_SHULKER_BOX: + case LIGHT_BLUE_SHULKER_BOX: + case YELLOW_SHULKER_BOX: + case LIME_SHULKER_BOX: + case PINK_SHULKER_BOX: + case GRAY_SHULKER_BOX: + case LIGHT_GRAY_SHULKER_BOX: + case CYAN_SHULKER_BOX: + case PURPLE_SHULKER_BOX: + case BLUE_SHULKER_BOX: + case BROWN_SHULKER_BOX: + case GREEN_SHULKER_BOX: + case RED_SHULKER_BOX: + case BLACK_SHULKER_BOX: + case CARVED_PUMPKIN: + case WITHER_SKELETON_SKULL: + case FLINT_AND_STEEL: + case BONE_MEAL: + case SHEARS: + case GLASS_BOTTLE: + case GLOWSTONE: + case COD_BUCKET: + case PUFFERFISH_BUCKET: + case SALMON_BUCKET: + case TROPICAL_FISH_BUCKET: + case BUCKET: + case WATER_BUCKET: + case LAVA_BUCKET: { + if (event.getBlock().getType() == Material.DROPPER) { + return; + } + BlockFace targetFace = ((Directional) event.getBlock().getState().getData()).getFacing(); + Location location = BukkitUtil.adapt(event.getBlock().getRelative(targetFace).getLocation()); + if (location.isPlotRoad()) { + event.setCancelled(true); + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onStructureGrow(StructureGrowEvent event) { + if (!this.plotAreaManager.hasPlotArea(event.getWorld().getName())) { + return; + } + List blocks = event.getBlocks(); + if (blocks.isEmpty()) { + return; + } + Location location = BukkitUtil.adapt(blocks.get(0).getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + for (int i = blocks.size() - 1; i >= 0; i--) { + location = BukkitUtil.adapt(blocks.get(i).getLocation()); + if (location.isPlotArea()) { + blocks.remove(i); + } + } + return; + } else { + Plot origin = area.getOwnedPlot(location); + if (origin == null) { + event.setCancelled(true); + return; + } + for (int i = blocks.size() - 1; i >= 0; i--) { + location = BukkitUtil.adapt(blocks.get(i).getLocation()); + if (!area.contains(location.getX(), location.getZ())) { + blocks.remove(i); + continue; + } + Plot plot = area.getOwnedPlot(location); + if (!Objects.equals(plot, origin)) { + event.getBlocks().remove(i); + } + } + } + Plot origin = area.getPlot(location); + if (origin == null) { + event.setCancelled(true); + return; + } + for (int i = blocks.size() - 1; i >= 0; i--) { + location = BukkitUtil.adapt(blocks.get(i).getLocation()); + Plot plot = area.getOwnedPlot(location); + /* + * plot → the base plot of the merged area + * origin → the plot where the event gets called + */ + + // Are plot and origin different AND are both plots merged + if (!Objects.equals(plot, origin) && (!plot.isMerged() && !origin.isMerged())) { + event.getBlocks().remove(i); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBigBoom(BlockExplodeEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + String world = location.getWorldName(); + if (!this.plotAreaManager.hasPlotArea(world)) { + return; + } + PlotArea area = location.getPlotArea(); + if (area == null) { + Iterator iterator = event.blockList().iterator(); + while (iterator.hasNext()) { + location = BukkitUtil.adapt(iterator.next().getLocation()); + if (location.isPlotArea()) { + iterator.remove(); + } + } + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null || !plot.getFlag(ExplosionFlag.class)) { + event.setCancelled(true); + if (plot != null) { + plot.debug("Explosion was cancelled because explosion = false"); + } + } + event.blockList().removeIf(blox -> !plot.equals(area.getOwnedPlot(BukkitUtil.adapt(blox.getLocation())))); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockBurn(BlockBurnEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + + Plot plot = location.getOwnedPlot(); + if (plot == null || !plot.getFlag(BlockBurnFlag.class)) { + if (plot != null) { + plot.debug("Block burning was cancelled because block-burn = false"); + } + event.setCancelled(true); + } + + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockIgnite(BlockIgniteEvent event) { + Player player = event.getPlayer(); + Entity ignitingEntity = event.getIgnitingEntity(); + Block block = event.getBlock(); + BlockIgniteEvent.IgniteCause igniteCause = event.getCause(); + Location location1 = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location1.getPlotArea(); + if (area == null) { + return; + } + if (igniteCause == BlockIgniteEvent.IgniteCause.LIGHTNING) { + event.setCancelled(true); + return; + } + + Plot plot = area.getOwnedPlot(location1); + if (player != null) { + BukkitPlayer pp = BukkitUtil.adapt(player); + if (plot == null) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_ROAD)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.road") + ); + event.setCancelled(true); + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.unowned") + ); + event.setCancelled(true); + } + } else if (!plot.isAdded(pp.getUUID())) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + } + } else if (!plot.getFlag(BlockIgnitionFlag.class)) { + event.setCancelled(true); + } + } else { + if (plot == null) { + event.setCancelled(true); + return; + } + if (ignitingEntity != null) { + if (!plot.getFlag(BlockIgnitionFlag.class)) { + event.setCancelled(true); + plot.debug("Block ignition was cancelled because block-ignition = false"); + return; + } + if (igniteCause == BlockIgniteEvent.IgniteCause.FIREBALL) { + if (ignitingEntity instanceof Fireball) { + Projectile fireball = (Projectile) ignitingEntity; + Location location = null; + if (fireball.getShooter() instanceof Entity) { + Entity shooter = (Entity) fireball.getShooter(); + location = BukkitUtil.adapt(shooter.getLocation()); + } else if (fireball.getShooter() instanceof BlockProjectileSource) { + Block shooter = + ((BlockProjectileSource) fireball.getShooter()).getBlock(); + location = BukkitUtil.adapt(shooter.getLocation()); + } + if (location != null && !plot.equals(location.getPlot())) { + event.setCancelled(true); + } + } + } + + } else if (event.getIgnitingBlock() != null) { + Block ignitingBlock = event.getIgnitingBlock(); + Plot plotIgnited = BukkitUtil.adapt(ignitingBlock.getLocation()).getPlot(); + if (igniteCause == BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL && ( + !plot.getFlag(BlockIgnitionFlag.class) || plotIgnited == null || !plotIgnited + .equals(plot)) || (igniteCause == BlockIgniteEvent.IgniteCause.SPREAD + || igniteCause == BlockIgniteEvent.IgniteCause.LAVA) && ( + !plot.getFlag(BlockIgnitionFlag.class) || plotIgnited == null || !plotIgnited + .equals(plot))) { + event.setCancelled(true); + } + } + } + } +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntityEventListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntityEventListener.java new file mode 100644 index 000000000..2d4162881 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntityEventListener.java @@ -0,0 +1,330 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.listener; + +import com.plotsquared.bukkit.util.BukkitEntityUtil; +import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.flag.implementations.DisablePhysicsFlag; +import com.plotsquared.core.plot.flag.implementations.ExplosionFlag; +import com.plotsquared.core.plot.flag.implementations.InvincibleFlag; +import com.plotsquared.core.plot.flag.implementations.MobPlaceFlag; +import com.plotsquared.core.plot.world.PlotAreaManager; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.EntityCombustByEntityEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.ExplosionPrimeEvent; +import org.bukkit.event.vehicle.VehicleCreateEvent; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; + +import javax.annotation.Nonnull; +import javax.inject.Inject; +import java.util.Iterator; +import java.util.List; + +@SuppressWarnings("unused") +public class EntityEventListener implements Listener { + + private final PlotAreaManager plotAreaManager; + private float lastRadius; + + @Inject public EntityEventListener(@Nonnull final PlotAreaManager plotAreaManager) { + this.plotAreaManager = plotAreaManager; + } + + @EventHandler(priority = EventPriority.HIGHEST) public void onEntityCombustByEntity(EntityCombustByEntityEvent event) { + EntityDamageByEntityEvent eventChange = + new EntityDamageByEntityEvent(event.getCombuster(), event.getEntity(), EntityDamageEvent.DamageCause.FIRE_TICK, event.getDuration()); + onEntityDamageByEntityEvent(eventChange); + if (eventChange.isCancelled()) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) public void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) { + Entity damager = event.getDamager(); + Location location = BukkitUtil.adapt(damager.getLocation()); + if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) { + return; + } + Entity victim = event.getEntity(); +/* + if (victim.getType().equals(EntityType.ITEM_FRAME)) { + Plot plot = BukkitUtil.getLocation(victim).getPlot(); + if (plot != null && !plot.isAdded(damager.getUniqueId())) { + event.setCancelled(true); + return; + } + } +*/ + if (!BukkitEntityUtil.entityDamage(damager, victim, event.getCause())) { + if (event.isCancelled()) { + if (victim instanceof Ageable) { + Ageable ageable = (Ageable) victim; + if (ageable.getAge() == -24000) { + ageable.setAge(0); + ageable.setAdult(); + } + } + } + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void creatureSpawnEvent(CreatureSpawnEvent event) { + Entity entity = event.getEntity(); + Location location = BukkitUtil.adapt(entity.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + CreatureSpawnEvent.SpawnReason reason = event.getSpawnReason(); + switch (reason.toString()) { + case "DISPENSE_EGG": + case "EGG": + case "OCELOT_BABY": + case "SPAWNER_EGG": + if (!area.isSpawnEggs()) { + event.setCancelled(true); + return; + } + break; + case "REINFORCEMENTS": + case "NATURAL": + case "MOUNT": + case "PATROL": + case "RAID": + case "SHEARED": + case "SHOULDER_ENTITY": + case "SILVERFISH_BLOCK": + case "TRAP": + case "VILLAGE_DEFENSE": + case "VILLAGE_INVASION": + case "BEEHIVE": + case "CHUNK_GEN": + if (!area.isMobSpawning()) { + event.setCancelled(true); + return; + } + case "BREEDING": + if (!area.isSpawnBreeding()) { + event.setCancelled(true); + return; + } + break; + case "BUILD_IRONGOLEM": + case "BUILD_SNOWMAN": + case "BUILD_WITHER": + case "CUSTOM": + if (!area.isSpawnCustom() && entity.getType() != EntityType.ARMOR_STAND) { + event.setCancelled(true); + return; + } + break; + case "SPAWNER": + if (!area.isMobSpawnerSpawning()) { + event.setCancelled(true); + return; + } + break; + } + Plot plot = area.getOwnedPlotAbs(location); + if (plot == null) { + if (!area.isMobSpawning()) { + event.setCancelled(true); + } + return; + } + if (BukkitEntityUtil.checkEntity(entity, plot)) { + event.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onEntityFall(EntityChangeBlockEvent event) { + if (event.getEntityType() != EntityType.FALLING_BLOCK) { + return; + } + Block block = event.getBlock(); + World world = block.getWorld(); + String worldName = world.getName(); + if (!this.plotAreaManager.hasPlotArea(worldName)) { + return; + } + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlotAbs(location); + if (plot == null || plot.getFlag(DisablePhysicsFlag.class)) { + event.setCancelled(true); + plot.debug("Falling block event was cancelled because disable-physics = true"); + return; + } + if (event.getTo().hasGravity()) { + Entity entity = event.getEntity(); + List meta = entity.getMetadata("plot"); + if (meta.isEmpty()) { + return; + } + Plot origin = (Plot) meta.get(0).value(); + if (origin != null && !origin.equals(plot)) { + event.setCancelled(true); + entity.remove(); + } + } else if (event.getTo() == Material.AIR) { + event.getEntity().setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.platform(), plot)); + } + } + + @EventHandler(priority = EventPriority.HIGH) public void onDamage(EntityDamageEvent event) { + if (event.getEntityType() != EntityType.PLAYER) { + return; + } + Location location = BukkitUtil.adapt(event.getEntity().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = location.getOwnedPlot(); + if (plot == null) { + if (area.isRoadFlags() && area.getRoadFlag(InvincibleFlag.class)) { + event.setCancelled(true); + } + return; + } + if (plot.getFlag(InvincibleFlag.class)) { + plot.debug(event.getEntity().getName() + " could not take damage because invincible = true"); + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBigBoom(EntityExplodeEvent event) { + Location location = BukkitUtil.adapt(event.getLocation()); + PlotArea area = location.getPlotArea(); + boolean plotArea = location.isPlotArea(); + if (!plotArea) { + if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) { + return; + } + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot != null) { + if (plot.getFlag(ExplosionFlag.class)) { + List meta = event.getEntity().getMetadata("plot"); + Plot origin; + if (meta.isEmpty()) { + origin = plot; + } else { + origin = (Plot) meta.get(0).value(); + } + if (this.lastRadius != 0) { + List nearby = event.getEntity().getNearbyEntities(this.lastRadius, this.lastRadius, this.lastRadius); + for (Entity near : nearby) { + if (near instanceof TNTPrimed || near.getType().equals(EntityType.MINECART_TNT)) { + if (!near.hasMetadata("plot")) { + near.setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.platform(), plot)); + } + } + } + this.lastRadius = 0; + } + Iterator iterator = event.blockList().iterator(); + while (iterator.hasNext()) { + Block block = iterator.next(); + location = BukkitUtil.adapt(block.getLocation()); + if (!area.contains(location.getX(), location.getZ()) || !origin.equals(area.getOwnedPlot(location))) { + iterator.remove(); + } + } + return; + } else { + plot.debug("Explosion was cancelled because explosion = false"); + } + } + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPeskyMobsChangeTheWorldLikeWTFEvent(EntityChangeBlockEvent event) { + Entity e = event.getEntity(); + if (!(e instanceof FallingBlock)) { + Location location = BukkitUtil.adapt(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area != null) { + Plot plot = area.getOwnedPlot(location); + if (plot != null && plot.getFlag(MobPlaceFlag.class)) { + plot.debug(e.getType() + " could not change block because mob-place = false"); + return; + } + event.setCancelled(true); + } + } + } + + @EventHandler public void onPrime(ExplosionPrimeEvent event) { + this.lastRadius = event.getRadius() + 1; + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onVehicleCreate(VehicleCreateEvent event) { + Vehicle entity = event.getVehicle(); + Location location = BukkitUtil.adapt(entity.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlotAbs(location); + if (plot == null || BukkitEntityUtil.checkEntity(entity, plot)) { + entity.remove(); + return; + } + if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { + entity.setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.platform(), plot)); + } + } +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntitySpawnListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntitySpawnListener.java index e32376d4d..24d22e6a0 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntitySpawnListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntitySpawnListener.java @@ -25,6 +25,7 @@ */ package com.plotsquared.bukkit.listener; +import com.plotsquared.bukkit.util.BukkitEntityUtil; import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; @@ -66,8 +67,7 @@ public class EntitySpawnListener implements Listener { public static void testNether(final Entity entity) { @Nonnull World world = entity.getWorld(); - if (world.getEnvironment() != World.Environment.NETHER - && world.getEnvironment() != World.Environment.THE_END) { + if (world.getEnvironment() != World.Environment.NETHER && world.getEnvironment() != World.Environment.THE_END) { return; } test(entity); @@ -91,8 +91,7 @@ public class EntitySpawnListener implements Listener { List meta = entity.getMetadata(KEY); if (meta.isEmpty()) { if (PlotSquared.get().getPlotAreaManager().hasPlotArea(world.getName())) { - entity.setMetadata(KEY, - new FixedMetadataValue((Plugin) PlotSquared.platform(), entity.getLocation())); + entity.setMetadata(KEY, new FixedMetadataValue((Plugin) PlotSquared.platform(), entity.getLocation())); } } else { org.bukkit.Location origin = (org.bukkit.Location) meta.get(0).value(); @@ -123,8 +122,7 @@ public class EntitySpawnListener implements Listener { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void creatureSpawnEvent(EntitySpawnEvent event) { + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void creatureSpawnEvent(EntitySpawnEvent event) { Entity entity = event.getEntity(); Location location = BukkitUtil.adapt(entity.getLocation()); PlotArea area = location.getPlotArea(); @@ -155,13 +153,12 @@ public class EntitySpawnListener implements Listener { } switch (entity.getType()) { case ENDER_CRYSTAL: - if (PlayerEvents.checkEntity(entity, plot)) { + if (BukkitEntityUtil.checkEntity(entity, plot)) { event.setCancelled(true); } case SHULKER: if (!entity.hasMetadata("shulkerPlot")) { - entity.setMetadata("shulkerPlot", - new FixedMetadataValue((Plugin) PlotSquared.platform(), plot.getId())); + entity.setMetadata("shulkerPlot", new FixedMetadataValue((Plugin) PlotSquared.platform(), plot.getId())); } } } @@ -192,8 +189,7 @@ public class EntitySpawnListener implements Listener { } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void vehicleMove(VehicleMoveEvent event) { + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void vehicleMove(VehicleMoveEvent event) { testNether(event.getVehicle()); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEventListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEventListener.java new file mode 100644 index 000000000..2678a7484 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEventListener.java @@ -0,0 +1,1627 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.listener; + +import com.destroystokyo.paper.MaterialTags; +import com.google.common.base.Charsets; +import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.bukkit.util.BukkitEntityUtil; +import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.bukkit.util.UpdateUtility; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.configuration.caption.Caption; +import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.listener.PlayerBlockEventType; +import com.plotsquared.core.listener.PlotListener; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.Permission; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.plot.PlotInventory; +import com.plotsquared.core.plot.flag.FlagContainer; +import com.plotsquared.core.plot.flag.implementations.AnimalInteractFlag; +import com.plotsquared.core.plot.flag.implementations.BlockedCmdsFlag; +import com.plotsquared.core.plot.flag.implementations.ChatFlag; +import com.plotsquared.core.plot.flag.implementations.DenyTeleportFlag; +import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.plot.flag.implementations.DropProtectionFlag; +import com.plotsquared.core.plot.flag.implementations.HangingBreakFlag; +import com.plotsquared.core.plot.flag.implementations.HangingPlaceFlag; +import com.plotsquared.core.plot.flag.implementations.HostileInteractFlag; +import com.plotsquared.core.plot.flag.implementations.ItemDropFlag; +import com.plotsquared.core.plot.flag.implementations.KeepInventoryFlag; +import com.plotsquared.core.plot.flag.implementations.MiscInteractFlag; +import com.plotsquared.core.plot.flag.implementations.PlayerInteractFlag; +import com.plotsquared.core.plot.flag.implementations.PreventCreativeCopyFlag; +import com.plotsquared.core.plot.flag.implementations.TamedInteractFlag; +import com.plotsquared.core.plot.flag.implementations.UntrustedVisitFlag; +import com.plotsquared.core.plot.flag.implementations.UseFlag; +import com.plotsquared.core.plot.flag.implementations.VehicleBreakFlag; +import com.plotsquared.core.plot.flag.implementations.VehicleUseFlag; +import com.plotsquared.core.plot.flag.implementations.VillagerInteractFlag; +import com.plotsquared.core.plot.flag.types.BlockTypeWrapper; +import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.util.EventDispatcher; +import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.util.MathMan; +import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.PremiumVerification; +import com.plotsquared.core.util.RegExUtil; +import com.plotsquared.core.util.entity.EntityCategories; +import com.plotsquared.core.util.task.TaskManager; +import com.plotsquared.core.util.task.TaskTime; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.world.block.BlockType; +import io.papermc.lib.PaperLib; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.FluidCollisionMode; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.command.PluginCommand; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.Event; +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.EntityPickupItemEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.hanging.HangingPlaceEvent; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +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.PlayerEggThrowEvent; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.vehicle.VehicleDestroyEvent; +import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; +import org.bukkit.event.vehicle.VehicleMoveEvent; +import org.bukkit.help.HelpTopic; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; +import org.bukkit.util.Vector; + +import javax.annotation.Nonnull; +import javax.inject.Inject; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.regex.Pattern; + +/** + * Player Events involving plots. + */ +@SuppressWarnings("unused") +public class PlayerEventListener extends PlotListener implements Listener { + + private final EventDispatcher eventDispatcher; + private final WorldEdit worldEdit; + private final PlotAreaManager plotAreaManager; + // To prevent recursion + private boolean tmpTeleport = true; + private Field fieldPlayer; + private PlayerMoveEvent moveTmp; + private String internalVersion; + + { + try { + fieldPlayer = PlayerEvent.class.getDeclaredField("player"); + fieldPlayer.setAccessible(true); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + } + + @Inject public PlayerEventListener(@Nonnull final PlotAreaManager plotAreaManager, + @Nonnull final EventDispatcher eventDispatcher, + @Nonnull final WorldEdit worldEdit) { + super(eventDispatcher); + this.eventDispatcher = eventDispatcher; + this.worldEdit = worldEdit; + this.plotAreaManager = plotAreaManager; + } + + @EventHandler public void onVehicleEntityCollision(VehicleEntityCollisionEvent e) { + if (e.getVehicle().getType() == EntityType.BOAT) { + Location location = BukkitUtil.adapt(e.getEntity().getLocation()); + if (location.isPlotArea()) { + if (e.getEntity() instanceof Player) { + PlotPlayer player = BukkitUtil.adapt((Player) e.getEntity()); + Plot plot = player.getCurrentPlot(); + if (plot != null) { + if (!plot.isAdded(player.getUUID())) { + //Here the event is only canceled if the player is not the owner + //of the property on which he is located. + e.setCancelled(true); + } + } else { + e.setCancelled(true); + } + } else { + //Here the event is cancelled too, otherwise you can move the + //boat with EchoPets or other mobs running around on the plot. + e.setCancelled(true); + } + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void playerCommand(PlayerCommandPreprocessEvent event) { + String msg = event.getMessage().toLowerCase().replaceAll("/", "").trim(); + if (msg.isEmpty()) { + return; + } + Player player = event.getPlayer(); + PlotPlayer plotPlayer = BukkitUtil.adapt(player); + Location location = plotPlayer.getLocation(); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + String[] parts = msg.split(" "); + Plot plot = plotPlayer.getCurrentPlot(); + // Check WorldEdit + switch (parts[0].toLowerCase()) { + case "up": + case "/up": + case "worldedit:up": + case "worldedit:/up": + if (plot == null || (!plot.isAdded(plotPlayer.getUUID()) && !Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_OTHER, true))) { + event.setCancelled(true); + return; + } + } + if (plot == null && !area.isRoadFlags()) { + return; + } + + List blockedCommands = plot != null ? + plot.getFlag(BlockedCmdsFlag.class) : + area.getFlag(BlockedCmdsFlag.class); + if (!blockedCommands.isEmpty() && !Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_INTERACT_BLOCKED_CMDS)) { + String part = parts[0]; + if (parts[0].contains(":")) { + part = parts[0].split(":")[1]; + msg = msg.replace(parts[0].split(":")[0] + ':', ""); + } + String s1 = part; + List aliases = new ArrayList<>(); + for (HelpTopic cmdLabel : Bukkit.getServer().getHelpMap().getHelpTopics()) { + if (part.equals(cmdLabel.getName())) { + break; + } + String label = cmdLabel.getName().replaceFirst("/", ""); + if (aliases.contains(label)) { + continue; + } + PluginCommand p; + if ((p = Bukkit.getPluginCommand(label)) != null) { + for (String a : p.getAliases()) { + if (aliases.contains(a)) { + continue; + } + aliases.add(a); + a = a.replaceFirst("/", ""); + if (!a.equals(label) && a.equals(part)) { + part = label; + break; + } + } + } + } + if (!s1.equals(part)) { + msg = msg.replace(s1, part); + } + for (String s : blockedCommands) { + Pattern pattern; + if (!RegExUtil.compiledPatterns.containsKey(s)) { + RegExUtil.compiledPatterns.put(s, pattern = Pattern.compile(s)); + } else { + pattern = RegExUtil.compiledPatterns.get(s); + } + if (pattern.matcher(msg).matches()) { + String perm; + if (plot != null && plot.isAdded(plotPlayer.getUUID())) { + perm = "plots.admin.command.blocked-cmds.shared"; + } else { + perm = "plots.admin.command.blocked-cmds.road"; + } + if (!Permissions.hasPermission(plotPlayer, perm)) { + plotPlayer.sendMessage(TranslatableCaption.of("blockedcmds.command_blocked")); + event.setCancelled(true); + } + return; + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPreLogin(final AsyncPlayerPreLoginEvent event) { + final UUID uuid; + if (Settings.UUID.OFFLINE) { + if (Settings.UUID.FORCE_LOWERCASE) { + uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + event.getName().toLowerCase()).getBytes(Charsets.UTF_8)); + } else { + uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + event.getName()).getBytes(Charsets.UTF_8)); + } + } else { + uuid = event.getUniqueId(); + } + PlotSquared.get().getImpromptuUUIDPipeline().storeImmediately(event.getName(), uuid); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onConnect(PlayerJoinEvent event) { + final Player player = event.getPlayer(); + PlotSquared.platform().getPlayerManager().removePlayer(player.getUniqueId()); + final PlotPlayer pp = BukkitUtil.adapt(player); + + Location location = pp.getLocation(); + PlotArea area = location.getPlotArea(); + if (area != null) { + Plot plot = area.getPlot(location); + if (plot != null) { + plotEntry(pp, plot); + } + } + // Delayed + + // Async + TaskManager.runTaskLaterAsync(() -> { + if (!player.hasPlayedBefore() && player.isOnline()) { + player.saveData(); + } + this.eventDispatcher.doJoinTask(pp); + }, TaskTime.seconds(1L)); + + if (pp.hasPermission(Permission.PERMISSION_ADMIN_UPDATE_NOTIFICATION.toString()) && Settings.Enabled_Components.UPDATE_NOTIFICATIONS + && PremiumVerification.isPremium() && UpdateUtility.hasUpdate) { + Caption boundary = TranslatableCaption.of("update.update_boundary"); + Caption updateNotification = TranslatableCaption.of("update.update_notification"); + Template internalVersion = Template.of("p2version", String.valueOf(UpdateUtility.internalVersion.versionString())); + Template spigotVersion = Template.of("spigotversion", UpdateUtility.spigotVersion); + Template downloadUrl = Template.of("downloadurl", "https://www.spigotmc.org/resources/77506/updates"); + pp.sendMessage(boundary); + pp.sendMessage(updateNotification, internalVersion, spigotVersion, downloadUrl); + pp.sendMessage(boundary); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void playerRespawn(PlayerRespawnEvent event) { + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.adapt(player); + this.eventDispatcher.doRespawnTask(pp); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onTeleport(PlayerTeleportEvent event) { + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(player); + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + Plot lastPlot = lastPlotAccess.get().orElse(null); + org.bukkit.Location to = event.getTo(); + //noinspection ConstantConditions + if (to != null) { + Location location = BukkitUtil.adapt(to); + PlotArea area = location.getPlotArea(); + if (area == null) { + if (lastPlot != null) { + plotExit(pp, lastPlot); + lastPlotAccess.remove(); + } + try (final MetaDataAccess lastLocationAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + lastLocationAccess.remove(); + } + return; + } + Plot plot = area.getPlot(location); + if (plot != null) { + final boolean result = DenyTeleportFlag.allowsTeleport(pp, plot); + // there is one possibility to still allow teleportation: + // to is identical to the plot's home location, and untrusted-visit is true + // i.e. untrusted-visit can override deny-teleport + // this is acceptable, because otherwise it wouldn't make sense to have both flags set + if (!result && !(plot.getFlag(UntrustedVisitFlag.class) && plot.getHomeSynchronous().equals(BukkitUtil.adaptComplete(to)))) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.entry.denied") + ); + event.setCancelled(true);} + } + } + } + playerMove(event); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void vehicleMove(VehicleMoveEvent event) + throws IllegalAccessException { + final org.bukkit.Location from = event.getFrom(); + final org.bukkit.Location to = event.getTo(); + + int toX, toZ; + if ((toX = MathMan.roundInt(to.getX())) != MathMan.roundInt(from.getX()) | (toZ = MathMan.roundInt(to.getZ())) != MathMan + .roundInt(from.getZ())) { + Vehicle vehicle = event.getVehicle(); + + // Check allowed + if (!vehicle.getPassengers().isEmpty()) { + Entity passenger = vehicle.getPassengers().get(0); + + if (passenger instanceof Player) { + final Player player = (Player) passenger; + // reset + if (moveTmp == null) { + moveTmp = new PlayerMoveEvent(null, from, to); + } + moveTmp.setFrom(from); + moveTmp.setTo(to); + moveTmp.setCancelled(false); + fieldPlayer.set(moveTmp, player); + + List passengers = vehicle.getPassengers(); + + this.playerMove(moveTmp); + org.bukkit.Location dest; + if (moveTmp.isCancelled()) { + dest = from; + } else if (MathMan.roundInt(moveTmp.getTo().getX()) != toX || MathMan.roundInt(moveTmp.getTo().getZ()) != toZ) { + dest = to; + } else { + dest = null; + } + if (dest != null) { + vehicle.eject(); + vehicle.setVelocity(new Vector(0d, 0d, 0d)); + PaperLib.teleportAsync(vehicle, dest); + passengers.forEach(vehicle::addPassenger); + return; + } + } + if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { + final com.sk89q.worldedit.world.entity.EntityType entityType = BukkitAdapter.adapt(vehicle.getType()); + // Horses etc are vehicles, but they're also animals + // so this filters out all living entities + if (EntityCategories.VEHICLE.contains(entityType) && !EntityCategories.ANIMAL.contains(entityType)) { + List meta = vehicle.getMetadata("plot"); + Plot toPlot = BukkitUtil.adapt(to).getPlot(); + if (!meta.isEmpty()) { + Plot origin = (Plot) meta.get(0).value(); + if (origin != null && !origin.getBasePlot(false).equals(toPlot)) { + vehicle.remove(); + } + } else if (toPlot != null) { + vehicle.setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.platform(), toPlot)); + } + } + } + } + + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void playerMove(PlayerMoveEvent event) { + org.bukkit.Location from = event.getFrom(); + org.bukkit.Location to = event.getTo(); + int x2; + if (MathMan.roundInt(from.getX()) != (x2 = MathMan.roundInt(to.getX()))) { + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(player); + // Cancel teleport + if (TaskManager.removeFromTeleportQueue(pp.getName())) { + pp.sendMessage(TranslatableCaption.of("teleport.teleport_failed")); + } + // Set last location + Location location = BukkitUtil.adapt(to); + try (final MetaDataAccess lastLocationAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + lastLocationAccess.remove(); + } + PlotArea area = location.getPlotArea(); + if (area == null) { + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlotAccess.remove(); + } + return; + } + Plot now = area.getPlot(location); + Plot lastPlot; + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlot = lastPlotAccess.get().orElse(null); + } + if (now == null) { + try (final MetaDataAccess kickAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { + if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse(false)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.exit.denied") + ); + this.tmpTeleport = false; + if (lastPlot.equals(BukkitUtil.adapt(from).getPlot())) { + player.teleport(from); + } else { + player.teleport(player.getWorld().getSpawnLocation()); + } + this.tmpTeleport = true; + event.setCancelled(true); + return;} + } + } else if (now.equals(lastPlot)) { + ForceFieldListener.handleForcefield(player, pp, now); + } else if (!plotEntry(pp, now) && this.tmpTeleport) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.entry.denied") + ); + this.tmpTeleport = false; + to.setX(from.getBlockX()); + to.setY(from.getBlockY()); + to.setZ(from.getBlockZ()); + player.teleport(event.getTo()); + this.tmpTeleport = true; + return; + } + int border = area.getBorder(); + if (x2 > border && this.tmpTeleport) { + to.setX(border - 1); + this.tmpTeleport = false; + player.teleport(event.getTo()); + this.tmpTeleport = true; + pp.sendMessage(TranslatableCaption.of("border.border")); + } + if (x2 < -border && this.tmpTeleport) { + to.setX(-border + 1); + this.tmpTeleport = false; + player.teleport(event.getTo()); + this.tmpTeleport = true; + pp.sendMessage(TranslatableCaption.of("border.border")); + } + } + int z2; + if (MathMan.roundInt(from.getZ()) != (z2 = MathMan.roundInt(to.getZ()))) { + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(player); + // Cancel teleport + if (TaskManager.removeFromTeleportQueue(pp.getName())) { + pp.sendMessage(TranslatableCaption.of("teleport.teleport_failed")); + } + // Set last location + Location location = BukkitUtil.adapt(to); + try (final MetaDataAccess lastLocationAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + lastLocationAccess.set(location); + } + PlotArea area = location.getPlotArea(); + if (area == null) { + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlotAccess.remove(); + } + return; + } + Plot now = area.getPlot(location); + Plot lastPlot; + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlot = lastPlotAccess.get().orElse(null); + } + if (now == null) { + try (final MetaDataAccess kickAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { + if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse(false)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.exit.denied") + ); + this.tmpTeleport = false; + if (lastPlot.equals(BukkitUtil.adapt(from).getPlot())) { + player.teleport(from); + } else { + player.teleport(player.getWorld().getSpawnLocation()); + } + this.tmpTeleport = true; + event.setCancelled(true); + return;} + } + } else if (now.equals(lastPlot)) { + ForceFieldListener.handleForcefield(player, pp, now); + } else if (!plotEntry(pp, now) && this.tmpTeleport) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.entry.denied") + ); + this.tmpTeleport = false; + player.teleport(from); + to.setX(from.getBlockX()); + to.setY(from.getBlockY()); + to.setZ(from.getBlockZ()); + player.teleport(event.getTo()); + this.tmpTeleport = true; + return; + } + int border = area.getBorder(); + if (z2 > border && this.tmpTeleport) { + to.setZ(border - 1); + this.tmpTeleport = false; + player.teleport(event.getTo()); + this.tmpTeleport = true; + pp.sendMessage(TranslatableCaption.of("border.border")); + } else if (z2 < -border && this.tmpTeleport) { + to.setZ(-border + 1); + this.tmpTeleport = false; + player.teleport(event.getTo()); + this.tmpTeleport = true; + pp.sendMessage(TranslatableCaption.of("border.border")); + } + } + } + + @EventHandler(priority = EventPriority.LOW) public void onChat(AsyncPlayerChatEvent event) { + if (event.isCancelled()) { + return; + } + + BukkitPlayer plotPlayer = BukkitUtil.adapt(event.getPlayer()); + Location location = plotPlayer.getLocation(); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getPlot(location); + if (plot == null) { + return; + } + if (!((plot.getFlag(ChatFlag.class) && area.isPlotChat() && plotPlayer.getAttribute("chat")) + || area.isForcingPlotChat())) { + return; + } + if (plot.isDenied(plotPlayer.getUUID()) && !Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_CHAT_BYPASS)) { + return; + } + event.setCancelled(true); + Set recipients = event.getRecipients(); + recipients.clear(); + Set> spies = new HashSet<>(); + Set> plotRecipients = new HashSet<>(); + for (final PlotPlayer pp : PlotSquared.platform().getPlayerManager().getPlayers()) { + if (pp.getAttribute("chatspy")) { + spies.add(pp); + } else { + Plot current = pp.getCurrentPlot(); + if (current != null && current.getBasePlot(false).equals(plot)) { + plotRecipients.add(pp); + } + } + } + String message = event.getMessage(); + String sender = event.getPlayer().getDisplayName(); + PlotId id = plot.getId(); + Caption msg = TranslatableCaption.of("chat.plot_chat_format"); + Template msgTemplate; + Template plotTemplate = Template.of("plot_id", id.toString()); + Template senderTemplate = Template.of("sender", sender); + // If we do/don't want colour, we need to be careful about how to go about it, as players could attempt either or &6 etc. + // In both cases, we want to use a Component Template to ensure that the player cannot use any placeholders in their message on purpose + // or accidentally, as component templates are done at the end. We also need to deserialize from legacy color codes to a Component if + // allowing colour. + if (plotPlayer.hasPermission("plots.chat.color")) { + msgTemplate = Template + .of("msg", BukkitUtil.LEGACY_COMPONENT_SERIALIZER.deserialize(ChatColor.translateAlternateColorCodes('&', message))); + } else { + msgTemplate = Template.of("msg", BukkitUtil.MINI_MESSAGE.deserialize( + ChatColor.stripColor(BukkitUtil.LEGACY_COMPONENT_SERIALIZER.serialize(TextComponent.builder(message).build())))); + } + for (PlotPlayer receiver : plotRecipients) { + receiver.sendMessage(msg, msgTemplate, plotTemplate, senderTemplate); + } + if (!spies.isEmpty()) { + Caption spymsg = TranslatableCaption.of("chat.plot_chat_spy_format"); + Template plotidTemplate = Template.of("plot_id", id.getX() + ";" + id.getY()); + Template spysenderTemplate = Template.of("sender", sender); + Template spymessageTemplate = Template.of("msg", TextComponent.builder(message).build()); + for (PlotPlayer player : spies) { + player.sendMessage(spymsg, plotidTemplate, spysenderTemplate, spymessageTemplate); + } + } + // TODO: Re-implement + // PlotSquared.debug(full); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onWorldChanged(PlayerChangedWorldEvent event) { + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(player); + // Delete last location + Plot plot; + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + plot = lastPlotAccess.remove(); + } + try (final MetaDataAccess lastLocationAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + lastLocationAccess.remove(); + } + if (plot != null) { + plotExit(pp, plot); + } + if (this.worldEdit != null) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_WORLDEDIT_BYPASS)) { + if (pp.getAttribute("worldedit")) { + pp.removeAttribute("worldedit"); + } + } + } + Location location = pp.getLocation(); + PlotArea area = location.getPlotArea(); + if (location.isPlotArea()) { + plot = location.getPlot(); + if (plot != null) { + plotEntry(pp, plot); + } + } + } + + @SuppressWarnings("deprecation") @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onInventoryClick(InventoryClickEvent event) { + /*if (!event.isLeftClick() || (event.getAction() != InventoryAction.PLACE_ALL) || event + .isShiftClick()) { + return; + }*/ + HumanEntity entity = event.getWhoClicked(); + if (!(entity instanceof Player) || !this.plotAreaManager + .hasPlotArea(entity.getWorld().getName())) { + return; + } + + HumanEntity clicker = event.getWhoClicked(); + if (!(clicker instanceof Player)) { + return; + } + Player player = (Player) clicker; + BukkitPlayer pp = BukkitUtil.adapt(player); + final PlotInventory inventory = PlotInventory.getOpenPlotInventory(pp); + if (inventory != null && event.getRawSlot() == event.getSlot()) { + if (!inventory.onClick(event.getSlot())) { + event.setResult(Event.Result.DENY); + event.setCancelled(true); + inventory.close(); + } + } + PlayerInventory inv = player.getInventory(); + int slot = inv.getHeldItemSlot(); + if ((slot > 8) || !event.getEventName().equals("InventoryCreativeEvent")) { + return; + } + ItemStack current = inv.getItemInHand(); + ItemStack newItem = event.getCursor(); + ItemMeta newMeta = newItem.getItemMeta(); + ItemMeta oldMeta = newItem.getItemMeta(); + + if (event.getClick() == ClickType.CREATIVE) { + final Plot plot = pp.getCurrentPlot(); + if (plot != null) { + if (plot.getFlag(PreventCreativeCopyFlag.class) && !plot + .isAdded(player.getUniqueId()) && !Permissions + .hasPermission(pp, Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { + final ItemStack newStack = + new ItemStack(newItem.getType(), newItem.getAmount()); + event.setCursor(newStack); + plot.debug(player.getName() + + " could not creative-copy an item because prevent-creative-copy = true"); + } + } else { + PlotArea area = pp.getPlotAreaAbs(); + if (area != null && area.isRoadFlags() && area + .getRoadFlag(PreventCreativeCopyFlag.class)) { + final ItemStack newStack = + new ItemStack(newItem.getType(), newItem.getAmount()); + event.setCursor(newStack); + } + } + return; + } + + String newLore = ""; + if (newMeta != null) { + List lore = newMeta.getLore(); + if (lore != null) { + newLore = lore.toString(); + } + } + String oldLore = ""; + if (oldMeta != null) { + List lore = oldMeta.getLore(); + if (lore != null) { + oldLore = lore.toString(); + } + } + if (!"[(+NBT)]".equals(newLore) || (current.equals(newItem) && newLore.equals(oldLore))) { + switch (newItem.getType()) { + case LEGACY_BANNER: + case PLAYER_HEAD: + if (newMeta != null) { + break; + } + default: + return; + } + } + Block block = player.getTargetBlock(null, 7); + org.bukkit.block.BlockState state = block.getState(); + Material stateType = state.getType(); + Material itemType = newItem.getType(); + if (stateType != itemType) { + switch (stateType) { + case LEGACY_STANDING_BANNER: + case LEGACY_WALL_BANNER: + if (itemType == Material.LEGACY_BANNER) { + break; + } + case LEGACY_SKULL: + if (itemType == Material.LEGACY_SKULL_ITEM) { + break; + } + default: + return; + } + } + Location location = BukkitUtil.adapt(state.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getPlotAbs(location); + boolean cancelled = false; + if (plot == null) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.interact.road") + ); + cancelled = true; + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.unowned") + ); + cancelled = true; + } + } else { + UUID uuid = pp.getUUID(); + if (!plot.isAdded(uuid)) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.interact.other") + ); + cancelled = true; + } + } + } + if (cancelled) { + if ((current.getType() == newItem.getType()) && (current.getDurability() == newItem + .getDurability())) { + event.setCursor( + new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); + event.setCancelled(true); + return; + } + event.setCursor( + new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onInteract(PlayerInteractAtEntityEvent e) { + Entity entity = e.getRightClicked(); + if (!(entity instanceof ArmorStand) && !(entity instanceof ItemFrame)) { + return; + } + Location location = BukkitUtil.adapt(e.getRightClicked().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + EntitySpawnListener.testNether(entity); + Plot plot = location.getPlotAbs(); + BukkitPlayer pp = BukkitUtil.adapt(e.getPlayer()); + if (plot == null) { + if (!area.isRoadFlags() && !area.getRoadFlag(MiscInteractFlag.class) && !Permissions + .hasPermission(pp, "plots.admin.interact.road")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.interact.road") + ); + e.setCancelled(true); + } + } else { + if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + e.setCancelled(true); + return; + } + } + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.interact.unowned") + ); + e.setCancelled(true); + } + } else { + UUID uuid = pp.getUUID(); + if (plot.isAdded(uuid)) { + return; + } + if (plot.getFlag(MiscInteractFlag.class)) { + return; + } + if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.interact.other") + ); + e.setCancelled(true); + plot.debug(pp.getName() + " could not interact with " + entity.getType() + + " because misc-interact = false"); + } + } + } + } + + @EventHandler(priority = EventPriority.LOW) public void onCancelledInteract(PlayerInteractEvent event) { + if (event.isCancelled() && event.getAction() == Action.RIGHT_CLICK_AIR) { + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(player); + PlotArea area = pp.getPlotAreaAbs(); + if (area == null) { + return; + } + if (event.getAction() == Action.RIGHT_CLICK_AIR) { + Material item = event.getMaterial(); + if (item.toString().toLowerCase().endsWith("_egg")) { + event.setCancelled(true); + event.setUseItemInHand(Event.Result.DENY); + } + } + ItemStack hand = player.getInventory().getItemInMainHand(); + ItemStack offHand = player.getInventory().getItemInOffHand(); + Material type = hand.getType(); + Material offType = offHand.getType(); + if (type == Material.AIR) { + type = offType; + } + if (type.toString().toLowerCase().endsWith("_egg")) { + Block block = player.getTargetBlockExact(5, FluidCollisionMode.SOURCE_ONLY); + if (block != null && block.getType() != Material.AIR) { + Location location = BukkitUtil.adapt(block.getLocation()); + if (!this.eventDispatcher.checkPlayerBlockEvent(pp, PlayerBlockEventType.SPAWN_MOB, location, null, true)) { + event.setCancelled(true); + event.setUseItemInHand(Event.Result.DENY); + } + } + } + } + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(player); + PlotArea area = pp.getPlotAreaAbs(); + if (area == null) { + return; + } + PlayerBlockEventType eventType = null; + BlockType blocktype1; + Block block = event.getClickedBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + Action action = event.getAction(); + outer: + switch (action) { + case PHYSICAL: { + eventType = PlayerBlockEventType.TRIGGER_PHYSICAL; + blocktype1 = BukkitAdapter.asBlockType(block.getType()); + break; + } + //todo rearrange the right click code. it is all over the place. + case RIGHT_CLICK_BLOCK: { + Material blockType = block.getType(); + eventType = PlayerBlockEventType.INTERACT_BLOCK; + blocktype1 = BukkitAdapter.asBlockType(block.getType()); + + if (blockType.isInteractable()) { + if (!player.isSneaking()) { + break; + } + ItemStack hand = player.getInventory().getItemInMainHand(); + ItemStack offHand = player.getInventory().getItemInOffHand(); + + // sneaking players interact with blocks if both hands are empty + if (hand.getType() == Material.AIR && offHand.getType() == Material.AIR) { + break; + } + } + + Material type = event.getMaterial(); + + // in the following, lb needs to have the material of the item in hand i.e. type + switch (type) { + case REDSTONE: + case STRING: + case PUMPKIN_SEEDS: + case MELON_SEEDS: + case COCOA_BEANS: + case WHEAT_SEEDS: + case BEETROOT_SEEDS: + case SWEET_BERRIES: + return; + default: + //eventType = PlayerBlockEventType.PLACE_BLOCK; + if (type.isBlock()) { + return; + } + } + if (PaperLib.isPaper()) { + if (MaterialTags.SPAWN_EGGS.isTagged(type) || Material.EGG.equals(type)) { + eventType = PlayerBlockEventType.SPAWN_MOB; + break outer; + } + } else { + if (type.toString().toLowerCase().endsWith("egg")) { + eventType = PlayerBlockEventType.SPAWN_MOB; + break outer; + } + } + if (type.isEdible()) { + //Allow all players to eat while also allowing the block place event ot be fired + return; + } + switch (type) { + case ACACIA_BOAT: + case BIRCH_BOAT: + case CHEST_MINECART: + case COMMAND_BLOCK_MINECART: + case DARK_OAK_BOAT: + case FURNACE_MINECART: + case HOPPER_MINECART: + case JUNGLE_BOAT: + case MINECART: + case OAK_BOAT: + case SPRUCE_BOAT: + case TNT_MINECART: + eventType = PlayerBlockEventType.PLACE_VEHICLE; + break outer; + case FIREWORK_ROCKET: + case FIREWORK_STAR: + eventType = PlayerBlockEventType.SPAWN_MOB; + break outer; + case BOOK: + case KNOWLEDGE_BOOK: + case WRITABLE_BOOK: + case WRITTEN_BOOK: + eventType = PlayerBlockEventType.READ; + break outer; + case ARMOR_STAND: + location = BukkitUtil.adapt(block.getRelative(event.getBlockFace()).getLocation()); + eventType = PlayerBlockEventType.PLACE_MISC; + break outer; + } + break; + } + case LEFT_CLICK_BLOCK: { + location = BukkitUtil.adapt(block.getLocation()); + //eventType = PlayerBlockEventType.BREAK_BLOCK; + blocktype1 = BukkitAdapter.asBlockType(block.getType()); + if (block.getType() == Material.DRAGON_EGG) { + eventType = PlayerBlockEventType.TELEPORT_OBJECT; + break; + } + + return; + } + default: + return; + } + if (this.worldEdit != null && pp.getAttribute("worldedit")) { + if (event.getMaterial() == Material.getMaterial(this.worldEdit.getConfiguration().wandItem)) { + return; + } + } + if (!this.eventDispatcher.checkPlayerBlockEvent(pp, eventType, location, blocktype1, true)) { + event.setCancelled(true); + event.setUseInteractedBlock(Event.Result.DENY); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBucketEmpty(PlayerBucketEmptyEvent event) { + BlockFace bf = event.getBlockFace(); + Block block = + event.getBlockClicked().getLocation().add(bf.getModX(), bf.getModY(), bf.getModZ()) + .getBlock(); + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); + Plot plot = area.getPlot(location); + if (plot == null) { + if (Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_ROAD)) { + return; + } + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.road") + ); + event.setCancelled(true); + } else if (!plot.hasOwner()) { + if (Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { + return; + } + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.unowned") + ); + event.setCancelled(true); + } else if (!plot.isAdded(pp.getUUID())) { + List use = plot.getFlag(UseFlag.class); + final BlockType blockType = BukkitAdapter.asBlockType(block.getType()); + for (final BlockTypeWrapper blockTypeWrapper : use) { + if (blockTypeWrapper.accepts(blockType)) { + return; + } + } + if (Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + return; + } + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST) public void onInventoryClose(InventoryCloseEvent event) { + HumanEntity closer = event.getPlayer(); + if (!(closer instanceof Player)) { + return; + } + Player player = (Player) closer; + PlotInventory.removePlotInventoryOpen(BukkitUtil.adapt(player)); + } + + @EventHandler(priority = EventPriority.MONITOR) public void onLeave(PlayerQuitEvent event) { + TaskManager.removeFromTeleportQueue(event.getPlayer().getName()); + BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer()); + pp.unregister(); + this.logout(pp.getUUID()); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBucketFill(PlayerBucketFillEvent event) { + Block blockClicked = event.getBlockClicked(); + Location location = BukkitUtil.adapt(blockClicked.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player player = event.getPlayer(); + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + Plot plot = area.getPlot(location); + if (plot == null) { + if (Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_ROAD)) { + return; + } + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.road") + ); + event.setCancelled(true); + } else if (!plot.hasOwner()) { + if (Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { + return; + } + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.unowned") + ); + event.setCancelled(true); + } else if (!plot.isAdded(plotPlayer.getUUID())) { + List use = plot.getFlag(UseFlag.class); + Block block = event.getBlockClicked(); + final BlockType blockType = BukkitAdapter.asBlockType(block.getType()); + for (final BlockTypeWrapper blockTypeWrapper : use) { + if (blockTypeWrapper.accepts(blockType)) { + return; + } + } + if (Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + return; + } + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + if (!Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onHangingPlace(HangingPlaceEvent event) { + Block block = event.getBlock().getRelative(event.getBlockFace()); + Location location = BukkitUtil.adapt(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player p = event.getPlayer(); + if (p == null) { + event.setCancelled(true); + return; + } + BukkitPlayer pp = BukkitUtil.adapt(p); + Plot plot = area.getPlot(location); + if (plot == null) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_ROAD)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.road") + ); + event.setCancelled(true); + } + } else { + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_UNOWNED)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.unwoned") + ); + event.setCancelled(true); + } + return; + } + if (!plot.isAdded(pp.getUUID())) { + if (!plot.getFlag(HangingPlaceFlag.class)) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + event.setCancelled(true); + } + return; + } + } + if (BukkitEntityUtil.checkEntity(event.getEntity(), plot)) { + event.setCancelled(true); + } + + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onHangingBreakByEntity(HangingBreakByEntityEvent event) { + Entity remover = event.getRemover(); + if (remover instanceof Player) { + Player p = (Player) remover; + Location location = BukkitUtil.adapt(event.getEntity().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + BukkitPlayer pp = BukkitUtil.adapt(p); + Plot plot = area.getPlot(location); + if (plot == null) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_DESTROY_ROAD)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.road") + ); + event.setCancelled(true); + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_DESTROY_UNOWNED)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.unowned") + ); + event.setCancelled(true); + } + } else if (!plot.isAdded(pp.getUUID())) { + if (plot.getFlag(HangingBreakFlag.class)) { + return; + } + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_DESTROY_OTHER)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.other") + ); + event.setCancelled(true); + plot.debug(p.getName() + + " could not break hanging entity because hanging-break = false"); + } + } + } else if (remover instanceof Projectile) { + Projectile p = (Projectile) remover; + if (p.getShooter() instanceof Player) { + Player shooter = (Player) p.getShooter(); + Location location = BukkitUtil.adapt(event.getEntity().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + BukkitPlayer player = BukkitUtil.adapt(shooter); + Plot plot = area.getPlot(BukkitUtil.adapt(event.getEntity().getLocation())); + if (plot != null) { + if (!plot.hasOwner()) { + if (!Permissions + .hasPermission(player, Permission.PERMISSION_ADMIN_DESTROY_UNOWNED)) { + player.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.unowned") + ); + event.setCancelled(true); + } + } else if (!plot.isAdded(player.getUUID())) { + if (!plot.getFlag(HangingBreakFlag.class)) { + if (!Permissions + .hasPermission(player, Permission.PERMISSION_ADMIN_DESTROY_OTHER)) { + player.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy.other") + ); + event.setCancelled(true); + plot.debug(player.getName() + + " could not break hanging entity because hanging-break = false"); + } + } + } + } + } + } else { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + Location location = BukkitUtil.adapt(event.getRightClicked().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player p = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(p); + Plot plot = area.getPlot(location); + if (plot == null && !area.isRoadFlags()) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_INTERACT_ROAD)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.interact.road") + ); + event.setCancelled(true); + } + } else if (plot != null && !plot.hasOwner()) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_INTERACT_UNOWNED)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.interact.unowned") + ); + event.setCancelled(true); + } + } else if ((plot != null && !plot.isAdded(pp.getUUID())) || (plot == null && area + .isRoadFlags())) { + final Entity entity = event.getRightClicked(); + final com.sk89q.worldedit.world.entity.EntityType entityType = + BukkitAdapter.adapt(entity.getType()); + + FlagContainer flagContainer; + if (plot == null) { + flagContainer = area.getRoadFlagContainer(); + } else { + flagContainer = plot.getFlagContainer(); + } + + if (EntityCategories.HOSTILE.contains(entityType) && flagContainer + .getFlag(HostileInteractFlag.class).getValue()) { + return; + } + + if (EntityCategories.ANIMAL.contains(entityType) && flagContainer + .getFlag(AnimalInteractFlag.class).getValue()) { + return; + } + + // This actually makes use of the interface, so we don't use the + // category + if (entity instanceof Tameable && ((Tameable) entity).isTamed() && flagContainer + .getFlag(TamedInteractFlag.class).getValue()) { + return; + } + + if (EntityCategories.VEHICLE.contains(entityType) && flagContainer + .getFlag(VehicleUseFlag.class).getValue()) { + return; + } + + if (EntityCategories.PLAYER.contains(entityType) && flagContainer + .getFlag(PlayerInteractFlag.class).getValue()) { + return; + } + + if (EntityCategories.VILLAGER.contains(entityType) && flagContainer + .getFlag(VillagerInteractFlag.class).getValue()) { + return; + } + + if ((EntityCategories.HANGING.contains(entityType) || EntityCategories.OTHER + .contains(entityType)) && flagContainer.getFlag(MiscInteractFlag.class) + .getValue()) { + return; + } + + if (!Permissions.hasPermission(pp, Permission.PERMISSION_ADMIN_INTERACT_OTHER)) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.interact.other") + ); + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onVehicleDestroy(VehicleDestroyEvent event) { + Location location = BukkitUtil.adapt(event.getVehicle().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Entity attacker = event.getAttacker(); + if (attacker instanceof Player) { + Player p = (Player) attacker; + BukkitPlayer pp = BukkitUtil.adapt(p); + Plot plot = area.getPlot(location); + if (plot == null) { + if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.road")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.vehicle.break.road") + ); + event.setCancelled(true); + } + } else { + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.unowned")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.vehicle.break.unowned") + ); + event.setCancelled(true); + return; + } + return; + } + if (!plot.isAdded(pp.getUUID())) { + if (plot.getFlag(VehicleBreakFlag.class)) { + return; + } + if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.other")) { + pp.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.vehicle.break.other") + ); + event.setCancelled(true); + plot.debug(pp.getName() + + " could not break vehicle because vehicle-break = false"); + } + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlayerEggThrow(PlayerEggThrowEvent event) { + Location location = BukkitUtil.adapt(event.getEgg().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player player = event.getPlayer(); + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + Plot plot = area.getPlot(location); + if (plot == null) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.road")) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.projectile.road") + ); + event.setHatching(false); + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.unowned")) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.projective.unowned") + ); + event.setHatching(false); + } + } else if (!plot.isAdded(plotPlayer.getUUID())) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.other")) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.projectile.other") + ); + event.setHatching(false); + } + } + } + + @EventHandler public void onItemDrop(PlayerDropItemEvent event) { + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.adapt(player); + Location location = pp.getLocation(); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = location.getOwnedPlot(); + if (plot == null) { + if (area.isRoadFlags() && !area.getRoadFlag(ItemDropFlag.class)) { + event.setCancelled(true); + } + return; + } + UUID uuid = pp.getUUID(); + if (!plot.isAdded(uuid)) { + if (!plot.getFlag(ItemDropFlag.class)) { + plot.debug(player.getName() + " could not drop item because of item-drop = false"); + event.setCancelled(true); + } + } + } + + @EventHandler public void onItemPickup(EntityPickupItemEvent event) { + LivingEntity ent = event.getEntity(); + if (ent instanceof Player) { + Player player = (Player) ent; + BukkitPlayer pp = BukkitUtil.adapt(player); + Location location = pp.getLocation(); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = location.getOwnedPlot(); + if (plot == null) { + if (area.isRoadFlags() && area.getRoadFlag(DropProtectionFlag.class)) { + event.setCancelled(true); + } + return; + } + UUID uuid = pp.getUUID(); + if (!plot.isAdded(uuid) && plot.getFlag(DropProtectionFlag.class)) { + plot.debug(player.getName() + " could not pick up item because of drop-protection = true"); + event.setCancelled(true); + } + } + } + + @EventHandler public void onDeath(final PlayerDeathEvent event) { + Location location = BukkitUtil.adapt(event.getEntity().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = location.getOwnedPlot(); + if (plot == null) { + if (area.isRoadFlags() && area.getRoadFlag(KeepInventoryFlag.class)) { + event.setCancelled(true); + } + return; + } + if (plot.getFlag(KeepInventoryFlag.class)) { + if (plot.getFlag(KeepInventoryFlag.class)) { + plot.debug(event.getEntity().getName() + " kept their inventory because of keep-inventory = true"); + event.setKeepInventory(true); + } + } + } +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ProjectileEventListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ProjectileEventListener.java new file mode 100644 index 000000000..4f16b390a --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ProjectileEventListener.java @@ -0,0 +1,163 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.listener; + +import com.plotsquared.bukkit.util.BukkitEntityUtil; +import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.Permission; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotHandler; +import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.util.Permissions; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.ThrownPotion; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.LingeringPotionSplashEvent; +import org.bukkit.event.entity.PotionSplashEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.projectiles.BlockProjectileSource; +import org.bukkit.projectiles.ProjectileSource; + +import javax.annotation.Nonnull; +import javax.inject.Inject; + +@SuppressWarnings("unused") +public class ProjectileEventListener implements Listener { + + private final PlotAreaManager plotAreaManager; + + @Inject public ProjectileEventListener(@Nonnull final PlotAreaManager plotAreaManager) { + this.plotAreaManager = plotAreaManager; + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPotionSplash(LingeringPotionSplashEvent event) { + Projectile entity = event.getEntity(); + Location location = BukkitUtil.adapt(entity.getLocation()); + if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) { + return; + } + if (!this.onProjectileHit(event)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPotionSplash(PotionSplashEvent event) { + ThrownPotion damager = event.getPotion(); + Location location = BukkitUtil.adapt(damager.getLocation()); + if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) { + return; + } + int count = 0; + for (LivingEntity victim : event.getAffectedEntities()) { + if (!BukkitEntityUtil.entityDamage(damager, victim)) { + event.setIntensity(victim, 0); + count++; + } + } + if ((count > 0 && count == event.getAffectedEntities().size()) || !onProjectileHit(event)) { + event.setCancelled(true); + } + } + + @EventHandler public void onProjectileLaunch(ProjectileLaunchEvent event) { + Projectile entity = event.getEntity(); + if (!(entity instanceof ThrownPotion)) { + return; + } + ProjectileSource shooter = entity.getShooter(); + if (!(shooter instanceof Player)) { + return; + } + Location location = BukkitUtil.adapt(entity.getLocation()); + if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) { + return; + } + PlotPlayer pp = BukkitUtil.adapt((Player) shooter); + Plot plot = location.getOwnedPlot(); + if (plot != null && !plot.isAdded(pp.getUUID())) { + entity.remove(); + event.setCancelled(true); + } + } + + @SuppressWarnings({"BooleanMethodIsAlwaysInverted", "cos it's not... dum IntelliJ"}) @EventHandler + public boolean onProjectileHit(ProjectileHitEvent event) { + Projectile entity = event.getEntity(); + Location location = BukkitUtil.adapt(entity.getLocation()); + if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) { + return true; + } + PlotArea area = location.getPlotArea(); + if (area == null) { + return true; + } + Plot plot = area.getPlot(location); + ProjectileSource shooter = entity.getShooter(); + if (shooter instanceof Player) { + PlotPlayer pp = BukkitUtil.adapt((Player) shooter); + if (plot == null) { + if (!Permissions.hasPermission(pp, Permission.PERMISSION_PROJECTILE_UNOWNED)) { + entity.remove(); + return false; + } + return true; + } + if (plot.isAdded(pp.getUUID()) || Permissions + .hasPermission(pp, Permission.PERMISSION_PROJECTILE_OTHER)) { + return true; + } + entity.remove(); + return false; + } + if (!(shooter instanceof Entity) && shooter != null) { + if (plot == null) { + entity.remove(); + return false; + } + Location sLoc = + BukkitUtil.adapt(((BlockProjectileSource) shooter).getBlock().getLocation()); + if (!area.contains(sLoc.getX(), sLoc.getZ())) { + entity.remove(); + return false; + } + Plot sPlot = area.getOwnedPlotAbs(sLoc); + if (sPlot == null || !PlotHandler.sameOwners(plot, sPlot)) { + entity.remove(); + return false; + } + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ServerListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ServerListener.java new file mode 100644 index 000000000..ee824795e --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/ServerListener.java @@ -0,0 +1,52 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.listener; + +import com.plotsquared.bukkit.BukkitPlatform; +import com.plotsquared.bukkit.placeholder.MVdWPlaceholders; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.player.ConsolePlayer; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.server.ServerLoadEvent; + +public class ServerListener implements Listener { + + private final BukkitPlatform plugin; + + public ServerListener(BukkitPlatform plugin) { + this.plugin = plugin; + } + + @EventHandler public void onServerLoad(ServerLoadEvent event) { + if (Bukkit.getPluginManager().getPlugin("MVdWPlaceholderAPI") != null) { + new MVdWPlaceholders(this.plugin, PlotSquared.get().getPlaceholderRegistry()); + ConsolePlayer.getConsole().sendMessage(TranslatableCaption.of("placeholder.hooked")); + } + } +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/MVdWPlaceholders.java b/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/MVdWPlaceholders.java new file mode 100644 index 000000000..66fcbf679 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/MVdWPlaceholders.java @@ -0,0 +1,73 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.placeholder; + +import be.maximvdw.placeholderapi.PlaceholderAPI; +import com.google.common.eventbus.Subscribe; +import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.util.placeholders.Placeholder; +import com.plotsquared.core.util.placeholders.PlaceholderRegistry; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import javax.annotation.Nonnull; + +/** + * Placeholder support for MVdWPlaceholderAPI + */ +public class MVdWPlaceholders { + + private static final String PREFIX = "plotsquared_"; + private final Plugin plugin; + private final PlaceholderRegistry registry; + + public MVdWPlaceholders(@Nonnull final Plugin plugin, @Nonnull final PlaceholderRegistry registry) { + this.plugin = plugin; + this.registry = registry; + for (final Placeholder placeholder : registry.getPlaceholders()) { + this.addPlaceholder(placeholder); + } + PlotSquared.get().getEventDispatcher().registerListener(this); + } + + @Subscribe public void onNewPlaceholder(@Nonnull final PlaceholderRegistry.PlaceholderAddedEvent event) { + this.addPlaceholder(event.getPlaceholder()); + } + + private void addPlaceholder(@Nonnull final Placeholder placeholder) { + PlaceholderAPI.registerPlaceholder(plugin, PREFIX + String.format("%s", placeholder.getKey()), placeholderReplaceEvent -> { + if (!placeholderReplaceEvent.isOnline() || placeholderReplaceEvent.getPlayer() == null) { + return ""; + } + final PlotPlayer player = BukkitUtil.adapt(placeholderReplaceEvent.getPlayer()); + String key = placeholderReplaceEvent.getPlaceholder().substring(PREFIX.length()); + return registry.getPlaceholderValue(key, player); + }); + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/PAPIPlaceholders.java b/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/PAPIPlaceholders.java new file mode 100644 index 000000000..9a5ebdb82 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/PAPIPlaceholders.java @@ -0,0 +1,89 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.placeholder; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.player.PlotPlayer; +import me.clip.placeholderapi.PlaceholderAPIPlugin; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.entity.Player; + +public class PAPIPlaceholders extends PlaceholderExpansion { + + public PAPIPlaceholders() { + } + + @Override public boolean persist() { + return true; + } + + @Override public boolean canRegister() { + return true; + } + + @Override public String getAuthor() { + return "IntellectualSites"; + } + + @Override public String getIdentifier() { + return "plotsquared"; + } + + @Override public String getVersion() { + return "3"; + } + + @Override public String onPlaceholderRequest(Player p, String identifier) { + final PlotPlayer pl = PlotSquared.platform().getPlayerManager().getPlayerIfExists(p.getUniqueId()); + + if (pl == null) { + return ""; + } + + // PAPI specific ones that don't translate well over into other placeholder APIs + if (identifier.startsWith("has_plot_")) { + identifier = identifier.substring("has_plot_".length()); + if (identifier.isEmpty()) + return ""; + + return pl.getPlotCount(identifier) > 0 ? + PlaceholderAPIPlugin.booleanTrue() : + PlaceholderAPIPlugin.booleanFalse(); + } + + if (identifier.startsWith("plot_count_")) { + identifier = identifier.substring("plot_count_".length()); + if (identifier.isEmpty()) + return ""; + + return String.valueOf(pl.getPlotCount(identifier)); + } + + // PlotSquared placeholders + return PlotSquared.get().getPlaceholderRegistry().getPlaceholderValue(identifier, pl); + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java b/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java deleted file mode 100644 index d79a7b4fb..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * 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 . - */ -package com.plotsquared.bukkit.placeholder; - -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.flag.GlobalFlagContainer; -import com.plotsquared.core.plot.flag.PlotFlag; -import com.plotsquared.core.util.PlayerManager; -import me.clip.placeholderapi.PlaceholderAPIPlugin; -import me.clip.placeholderapi.expansion.PlaceholderExpansion; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -import java.util.UUID; - -public class Placeholders extends PlaceholderExpansion { - - public Placeholders() { - } - - @Override public boolean persist() { - return true; - } - - @Override public boolean canRegister() { - return true; - } - - @Override public String getAuthor() { - return "NotMyFault"; - } - - @Override public String getIdentifier() { - return "plotsquared"; - } - - @Override public String getVersion() { - return "2.5"; - } - - @Override public String onPlaceholderRequest(Player p, String identifier) { - final PlotPlayer pl = PlotSquared.platform().getPlayerManager().getPlayerIfExists(p.getUniqueId()); - - if (pl == null) { - return ""; - } - - if (identifier.startsWith("has_plot_")) { - identifier = identifier.substring("has_plot_".length()); - if (identifier.isEmpty()) - return ""; - - return pl.getPlotCount(identifier) > 0 ? - PlaceholderAPIPlugin.booleanTrue() : - PlaceholderAPIPlugin.booleanFalse(); - } - - if (identifier.startsWith("plot_count_")) { - identifier = identifier.substring("plot_count_".length()); - if (identifier.isEmpty()) - return ""; - - return String.valueOf(pl.getPlotCount(identifier)); - } - - switch (identifier) { - case "currentplot_world": { - return p.getWorld().getName(); - } - case "has_plot": { - return (pl.getPlotCount() > 0) ? - PlaceholderAPIPlugin.booleanTrue() : - PlaceholderAPIPlugin.booleanFalse(); - } - case "allowed_plot_count": { - return String.valueOf(pl.getAllowedPlots()); - } - case "plot_count": { - return String.valueOf(pl.getPlotCount()); - } - } - - Plot plot = pl.getCurrentPlot(); - - if (plot == null) { - return ""; - } - - switch (identifier) { - case "currentplot_alias": { - return plot.getAlias(); - } - case "currentplot_owner": { - final UUID plotOwner = plot.getOwnerAbs(); - if (plotOwner == null) { - return ""; - } - - try { - return PlayerManager.getName(plotOwner, false); - } catch (final Exception ignored) {} - - final String name = Bukkit.getOfflinePlayer(plotOwner).getName(); - return name != null ? name : "unknown"; - } - case "currentplot_members": { - if (plot.getMembers() == null && plot.getTrusted() == null) { - return "0"; - } - return String.valueOf(plot.getMembers().size() + plot.getTrusted().size()); - } - case "currentplot_members_added": { - if (plot.getMembers() == null) { - return "0"; - } - return String.valueOf(plot.getMembers().size()); - } - case "currentplot_members_trusted": { - if (plot.getTrusted() == null) { - return "0"; - } - return String.valueOf(plot.getTrusted().size()); - } - case "currentplot_members_denied": { - if (plot.getDenied() == null) { - return "0"; - } - return String.valueOf(plot.getDenied().size()); - } - case "has_build_rights": { - return plot.isAdded(pl.getUUID()) ? - PlaceholderAPIPlugin.booleanTrue() : - PlaceholderAPIPlugin.booleanFalse(); - } - case "currentplot_x": { - return String.valueOf(plot.getId().getX()); - } - case "currentplot_y": { - return String.valueOf(plot.getId().getY()); - } - case "currentplot_xy": { - return plot.getId().getX() + ";" + plot.getId().getY(); - } - case "currentplot_rating": { - return String.valueOf(plot.getAverageRating()); - } - case "currentplot_biome": { - return plot.getBiomeSynchronous() + ""; - } - default: - break; - } - if (identifier.startsWith("currentplot_localflag_")) { - return getFlagValue(plot, identifier.substring("currentplot_localflag_".length()), - false); - } - if (identifier.startsWith("currentplot_flag_")) { - return getFlagValue(plot, identifier.substring("currentplot_flag_".length()), true); - } - return ""; - } - - /** - * Return the flag value from its name on the current plot. - * If the flag doesn't exist it returns an empty string. - * If the flag exists but it is not set on current plot and the parameter inherit is set to true, - * it returns the default value. - * - * @param plot Current plot where the player is - * @param flagName Name of flag to get from current plot - * @param inherit Define if it returns only the flag set on currentplot or also inherited flag - * @return The value of flag serialized in string - */ - private String getFlagValue(final Plot plot, final String flagName, final boolean inherit) { - if (flagName.isEmpty()) - return ""; - final PlotFlag flag = GlobalFlagContainer.getInstance().getFlagFromString(flagName); - if (flag == null) - return ""; - - if (inherit) { - return plot.getFlag(flag).toString(); - } else { - final PlotFlag plotFlag = plot.getFlagContainer().queryLocal(flag.getClass()); - return (plotFlag != null) ? plotFlag.getValue().toString() : ""; - } - } -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java index 86ccc7fc0..4f526bc11 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java @@ -73,10 +73,7 @@ public class BukkitPlayer extends PlotPlayer { private static boolean CHECK_EFFECTIVE = true; public final Player player; - private final EconHandler econHandler; private String name; - private String lastMessage = ""; - private long lastMessageTime = 0L; /** *

Please do not use this method. Instead use * BukkitUtil.getPlayer(Player), as it caches player objects.

@@ -94,7 +91,6 @@ public class BukkitPlayer extends PlotPlayer { @Nonnull final PermissionHandler permissionHandler) { super(plotAreaManager, eventDispatcher, econHandler, permissionHandler); this.player = player; - this.econHandler = econHandler; this.setupPermissionProfile(); if (realPlayer) { super.populatePersistentMetaMap(); @@ -153,13 +149,6 @@ public class BukkitPlayer extends PlotPlayer { } } - @Override public boolean hasPermission(@Nonnull final String permission) { - if (this.offline && this.econHandler != null) { - return this.econHandler.hasPermission(getName(), permission); - } - return this.player.hasPermission(permission); - } - @Override @Nonnegative public int hasPermissionRange(@Nonnull final String stub, @Nonnegative final int range) { if (hasPermission(Permission.PERMISSION_ADMIN.toString())) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java new file mode 100644 index 000000000..3ab6e31c0 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitChunkCoordinator.java @@ -0,0 +1,225 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.queue; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.plotsquared.bukkit.BukkitPlatform; +import com.plotsquared.core.queue.ChunkCoordinator; +import com.plotsquared.core.util.task.TaskManager; +import com.plotsquared.core.util.task.TaskTime; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.World; +import io.papermc.lib.PaperLib; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; + +/** + * Utility that allows for the loading and coordination of chunk actions + *

+ * The coordinator takes in collection of chunk coordinates, loads them + * and allows the caller to specify a sink for the loaded chunks. The + * coordinator will prevent the chunks from being unloaded until the sink + * has fully consumed the chunk + *

+ **/ +public final class BukkitChunkCoordinator extends ChunkCoordinator { + + private final List progressSubscribers = new LinkedList<>(); + + private final Queue requestedChunks; + private final Queue availableChunks; + private final long maxIterationTime; + private final Plugin plugin; + private final Consumer chunkConsumer; + private final org.bukkit.World bukkitWorld; + private final Runnable whenDone; + private final Consumer throwableConsumer; + private final boolean unloadAfter; + private final int totalSize; + + private final AtomicInteger expectedSize; + private int batchSize; + + @Inject private BukkitChunkCoordinator(@Assisted final long maxIterationTime, + @Assisted final int initialBatchSize, + @Assisted @Nonnull final Consumer chunkConsumer, + @Assisted @Nonnull final World world, + @Assisted @Nonnull final Collection requestedChunks, + @Assisted @Nonnull final Runnable whenDone, + @Assisted @Nonnull final Consumer throwableConsumer, + @Assisted final boolean unloadAfter) { + this.requestedChunks = new LinkedBlockingQueue<>(requestedChunks); + this.availableChunks = new LinkedBlockingQueue<>(); + this.totalSize = requestedChunks.size(); + this.expectedSize = new AtomicInteger(this.totalSize); + this.batchSize = initialBatchSize; + this.chunkConsumer = chunkConsumer; + this.maxIterationTime = maxIterationTime; + this.whenDone = whenDone; + this.throwableConsumer = throwableConsumer; + this.unloadAfter = unloadAfter; + this.plugin = JavaPlugin.getPlugin(BukkitPlatform.class); + this.bukkitWorld = Bukkit.getWorld(world.getName()); + } + + @Override public void start() { + // Request initial batch + this.requestBatch(); + // Wait until next tick to give the chunks a chance to be loaded + TaskManager.runTaskLater(() -> TaskManager.runTaskRepeat(this, TaskTime.ticks(1)), TaskTime.ticks(1)); + } + + @Override public void runTask() { + Chunk chunk = this.availableChunks.poll(); + if (chunk == null) { + return; + } + long iterationTime; + int processedChunks = 0; + do { + final long start = System.currentTimeMillis(); + try { + this.chunkConsumer.accept(BlockVector2.at(chunk.getX(), chunk.getZ())); + } catch (final Throwable throwable) { + this.throwableConsumer.accept(throwable); + } + if (unloadAfter) { + this.freeChunk(chunk); + } + processedChunks++; + final long end = System.currentTimeMillis(); + // Update iteration time + iterationTime = end - start; + } while (2 * iterationTime /* last chunk + next chunk */ < this.maxIterationTime && (chunk = availableChunks.poll()) != null); + if (processedChunks < this.batchSize) { + // Adjust batch size based on the amount of processed chunks per tick + this.batchSize = processedChunks; + } + + final int expected = this.expectedSize.addAndGet(-processedChunks); + + final float progress = ((float) totalSize - (float) expected) / (float) totalSize; + for (final ProgressSubscriber subscriber : this.progressSubscribers) { + subscriber.notifyProgress(this, progress); + } + + if (expected <= 0) { + try { + this.whenDone.run(); + } catch (final Throwable throwable) { + this.throwableConsumer.accept(throwable); + } + this.cancel(); + } else { + if (this.availableChunks.size() < processedChunks) { + this.requestBatch(); + } + } + } + + /** + * Requests a batch of chunks to be loaded + */ + private void requestBatch() { + BlockVector2 chunk; + for (int i = 0; i < this.batchSize && (chunk = this.requestedChunks.poll()) != null; i++) { + // This required PaperLib to be bumped to version 1.0.4 to mark the request as urgent + PaperLib.getChunkAtAsync(this.bukkitWorld, chunk.getX(), chunk.getZ(), true, true).whenComplete((chunkObject, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + // We want one less because this couldn't be processed + this.expectedSize.decrementAndGet(); + } else { + this.processChunk(chunkObject); + } + }); + } + } + + /** + * Once a chunk has been loaded, process it (add a plugin ticket and add to available chunks list) + */ + private void processChunk(@Nonnull final Chunk chunk) { + if (!chunk.isLoaded()) { + throw new IllegalArgumentException(String.format("Chunk %d;%d is is not loaded", chunk.getX(), chunk.getZ())); + } + chunk.addPluginChunkTicket(this.plugin); + this.availableChunks.add(chunk); + } + + /** + * Once a chunk has been used, free it up for unload by removing the plugin ticket + */ + private void freeChunk(@Nonnull final Chunk chunk) { + if (!chunk.isLoaded()) { + throw new IllegalArgumentException(String.format("Chunk %d;%d is is not loaded", chunk.getX(), chunk.getZ())); + } + chunk.removePluginChunkTicket(this.plugin); + } + + @Override public int getRemainingChunks() { + return this.expectedSize.get(); + } + + @Override public int getTotalChunks() { + return this.totalSize; + } + + /** + * Subscribe to coordinator progress updates + * + * @param subscriber Subscriber + */ + public void subscribeToProgress(@Nonnull final BukkitChunkCoordinator.ProgressSubscriber subscriber) { + this.progressSubscribers.add(subscriber); + } + + @FunctionalInterface + public interface ProgressSubscriber { + + /** + * Notify about a progress update in the coordinator + * + * @param coordinator Coordinator instance that triggered the notification + * @param progress Progress in the range [0, 1] + */ + void notifyProgress(@Nonnull final BukkitChunkCoordinator coordinator, final float progress); + + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java deleted file mode 100644 index a1bf7bee7..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * 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 . - */ -package com.plotsquared.bukkit.queue; - -import com.plotsquared.bukkit.schematic.StateWrapper; -import com.plotsquared.bukkit.util.BukkitBlockUtil; -import com.plotsquared.core.queue.BasicLocalBlockQueue; -import com.plotsquared.core.util.BlockUtil; -import com.plotsquared.core.util.ChunkUtil; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import io.papermc.lib.PaperLib; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.block.Block; -import org.bukkit.block.Container; -import org.bukkit.block.data.BlockData; - -import javax.annotation.Nonnull; -import java.util.concurrent.ExecutionException; -import java.util.function.Consumer; - -public class BukkitLocalQueue extends BasicLocalBlockQueue { - - public BukkitLocalQueue(String world) { - super(world); - } - - @Override public LocalChunk getLocalChunk(int x, int z) { - return new BasicLocalChunk(this, x, z) { - // Custom stuff? - }; - } - - @Override public void optimize() { - - } - - @Override public BlockState getBlock(int x, int y, int z) { - World worldObj = Bukkit.getWorld(getWorld()); - if (worldObj != null) { - Block block = worldObj.getBlockAt(x, y, z); - return BukkitBlockUtil.get(block); - } else { - return BlockUtil.get(0, 0); - } - } - - @Override public void refreshChunk(int x, int z) { - World worldObj = Bukkit.getWorld(getWorld()); - if (worldObj != null) { - worldObj.refreshChunk(x, z); - } - } - - @Override public void fixChunkLighting(int x, int z) { - // Do nothing - } - - @Override public final void regenChunk(int x, int z) { - World worldObj = Bukkit.getWorld(getWorld()); - if (worldObj != null) { - try { - worldObj.regenerateChunk(x, z); - } catch (UnsupportedOperationException e) { - com.sk89q.worldedit.world.World world = BukkitAdapter.adapt(worldObj); - try (EditSession editSession = WorldEdit.getInstance().getEditSessionFactory() - .getEditSession(world, -1);) { - CuboidRegion region = - new CuboidRegion(world, BlockVector3.at((x << 4), 0, (z << 4)), - BlockVector3.at((x << 4) + 15, 255, (z << 4) + 15)); - world.regenerate(region, editSession); - } - } - } - } - - @Override public final void setComponents(LocalChunk lc) - throws ExecutionException, InterruptedException { - setBaseBlocks(lc); - } - - public void setBaseBlocks(LocalChunk localChunk) { - World worldObj = Bukkit.getWorld(getWorld()); - if (worldObj == null) { - throw new NullPointerException("World cannot be null."); - } - final Consumer chunkConsumer = chunk -> { - for (int layer = 0; layer < localChunk.baseblocks.length; layer++) { - BaseBlock[] blocksLayer = localChunk.baseblocks[layer]; - if (blocksLayer != null) { - for (int j = 0; j < blocksLayer.length; j++) { - if (blocksLayer[j] != null) { - BaseBlock block = blocksLayer[j]; - int x = ChunkUtil.getX(j); - int y = ChunkUtil.getY(layer, j); - int z = ChunkUtil.getZ(j); - - BlockData blockData = BukkitAdapter.adapt(block); - - Block existing = chunk.getBlock(x, y, z); - final BlockState existingBaseBlock = - BukkitAdapter.adapt(existing.getBlockData()); - if (BukkitBlockUtil.get(existing).equals(existingBaseBlock) && existing - .getBlockData().matches(blockData)) { - continue; - } - - if (existing.getState() instanceof Container) { - ((Container) existing.getState()).getInventory().clear(); - } - - existing.setType(BukkitAdapter.adapt(block.getBlockType()), false); - existing.setBlockData(blockData, false); - if (block.hasNbtData()) { - CompoundTag tag = block.getNbtData(); - StateWrapper sw = new StateWrapper(tag); - - sw.restoreTag(worldObj.getName(), existing.getX(), existing.getY(), - existing.getZ()); - } - } - } - } - } - if (setBiome() && localChunk.biomes != null) { - for (int x = 0; x < localChunk.biomes.length; x++) { - BiomeType[] biomeZ = localChunk.biomes[x]; - if (biomeZ != null) { - for (int z = 0; z < biomeZ.length; z++) { - if (biomeZ[z] != null) { - BiomeType biomeType = biomeZ[z]; - - Biome biome = BukkitAdapter.adapt(biomeType); - worldObj.setBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, - biome); - } - } - } - } - } - }; - if (isForceSync()) { - chunkConsumer.accept(getChunk(worldObj, localChunk)); - } else { - PaperLib.getChunkAtAsync(worldObj, localChunk.getX(), localChunk.getZ(), true) - .thenAccept(chunkConsumer); - } - } - - private Chunk getChunk(final World world, final LocalChunk localChunk) { - Chunk chunk = null; - if (this.getChunkObject() != null && this.getChunkObject() instanceof Chunk) { - chunk = (Chunk) this.getChunkObject(); - } - if (chunk == null) { - chunk = world.getChunkAt(localChunk.getX(), localChunk.getZ()); - } - if (!chunk.isLoaded()) { - chunk.load(true); - } - return chunk; - } - - private void setMaterial(@Nonnull final BlockState plotBlock, @Nonnull final Block block) { - Material material = BukkitAdapter.adapt(plotBlock.getBlockType()); - block.setType(material, false); - } - - private boolean equals(@Nonnull final BlockState plotBlock, @Nonnull final Block block) { - return plotBlock.equals(BukkitBlockUtil.get(block)); - } - - public void setBiomes(LocalChunk lc) { - World worldObj = Bukkit.getWorld(getWorld()); - if (worldObj == null) { - throw new NullPointerException("World cannot be null."); - } - if (lc.biomes == null) { - throw new NullPointerException("Biomes cannot be null."); - } - final Consumer chunkConsumer = chunk -> { - for (int x = 0; x < lc.biomes.length; x++) { - BiomeType[] biomeZ = lc.biomes[x]; - if (biomeZ != null) { - for (int z = 0; z < biomeZ.length; z++) { - if (biomeZ[z] != null) { - BiomeType biomeType = biomeZ[z]; - - Biome biome = BukkitAdapter.adapt(biomeType); - worldObj - .setBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, biome); - } - } - } - } - }; - if (this.isForceSync()) { - chunkConsumer.accept(getChunk(worldObj, lc)); - } else { - PaperLib.getChunkAtAsync(worldObj, lc.getX(), lc.getZ(), true) - .thenAccept(chunkConsumer); - } - } - -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java new file mode 100644 index 000000000..460d6ac1e --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java @@ -0,0 +1,241 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.queue; + +import com.google.inject.Inject; +import com.plotsquared.bukkit.schematic.StateWrapper; +import com.plotsquared.bukkit.util.BukkitBlockUtil; +import com.plotsquared.core.inject.factory.ChunkCoordinatorBuilderFactory; +import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory; +import com.plotsquared.core.queue.BasicQueueCoordinator; +import com.plotsquared.core.queue.ChunkCoordinator; +import com.plotsquared.core.queue.LocalChunk; +import com.plotsquared.core.util.BlockUtil; +import com.plotsquared.core.util.ChunkUtil; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.block.Block; +import org.bukkit.block.Container; +import org.bukkit.block.data.BlockData; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.Consumer; + +public class BukkitQueueCoordinator extends BasicQueueCoordinator { + + private final SideEffectSet sideEffectSet; + private org.bukkit.World bukkitWorld; + @Inject private ChunkCoordinatorBuilderFactory chunkCoordinatorBuilderFactory; + @Inject private ChunkCoordinatorFactory chunkCoordinatorFactory; + private ChunkCoordinator chunkCoordinator; + + @Inject public BukkitQueueCoordinator(@Nonnull World world) { + super(world); + sideEffectSet = SideEffectSet.none().with(SideEffect.LIGHTING, SideEffect.State.OFF).with(SideEffect.NEIGHBORS, SideEffect.State.OFF); + } + + @Override public BlockState getBlock(int x, int y, int z) { + org.bukkit.World worldObj = BukkitAdapter.adapt(getWorld()); + if (worldObj != null) { + Block block = worldObj.getBlockAt(x, y, z); + return BukkitBlockUtil.get(block); + } else { + return BlockUtil.get(0, 0); + } + } + + @Override public void start() { + chunkCoordinator.start(); + } + + //TODO: implement cancellation + @Override public void cancel() { + chunkCoordinator.cancel(); + } + + @Override public boolean enqueue() { + final Clipboard regenClipboard; + if (isRegen()) { + BlockVector3 start = BlockVector3.at(getRegenStart()[0] << 4, 0, getRegenStart()[1] << 4); + BlockVector3 end = BlockVector3.at((getRegenEnd()[0] << 4) + 15, 255, (getRegenEnd()[1] << 4) + 15); + Region region = new CuboidRegion(start, end); + regenClipboard = new BlockArrayClipboard(region); + regenClipboard.setOrigin(start); + getWorld().regenerate(region, regenClipboard); + } else if (getRegenRegion() != null) { + regenClipboard = new BlockArrayClipboard(getRegenRegion()); + regenClipboard.setOrigin(getRegenRegion().getMinimumPoint()); + getWorld().regenerate(getRegenRegion(), regenClipboard); + } else { + regenClipboard = null; + } + Consumer consumer = getChunkConsumer(); + if (consumer == null) { + consumer = blockVector2 -> { + LocalChunk localChunk = getBlockChunks().get(blockVector2); + boolean isRegenChunk = + regenClipboard != null && blockVector2.getBlockX() > getRegenStart()[0] && blockVector2.getBlockZ() > getRegenStart()[1] + && blockVector2.getBlockX() < getRegenEnd()[0] && blockVector2.getBlockZ() < getRegenEnd()[1]; + if (isRegenChunk) { + for (int layer = 0; layer < 16; layer++) { + for (int y = layer << 4; y < 16; y++) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + BaseBlock block = regenClipboard.getFullBlock(BlockVector3.at(x, y, z)); + if (block != null) { + setWorldBlock(x, y, z, block, blockVector2); + } + } + } + } + } + } + // Allow regen and then blocks to be placed (plot schematic etc) + if (localChunk == null) { + return; + } + int sx = blockVector2.getX() << 4; + int sz = blockVector2.getZ() << 4; + for (int layer = 0; layer < localChunk.getBaseblocks().length; layer++) { + BaseBlock[] blocksLayer = localChunk.getBaseblocks()[layer]; + if (blocksLayer == null) { + continue; + } + for (int j = 0; j < blocksLayer.length; j++) { + if (blocksLayer[j] == null) { + continue; + } + BaseBlock block = blocksLayer[j]; + + if (block != null) { + int x = sx + ChunkUtil.getX(j); + int y = ChunkUtil.getY(layer, j); + int z = sz + ChunkUtil.getZ(j); + setWorldBlock(x, y, z, block, blockVector2); + } + } + } + for (int layer = 0; layer < localChunk.getBaseblocks().length; layer++) { + BiomeType[] biomesLayer = localChunk.getBiomes()[layer]; + if (biomesLayer == null) { + continue; + } + for (int j = 0; j < biomesLayer.length; j++) { + if (biomesLayer[j] == null) { + continue; + } + BiomeType biome = biomesLayer[j]; + if (biome != null) { + int x = sx + ChunkUtil.getX(j); + int y = ChunkUtil.getY(layer, j); + int z = sz + ChunkUtil.getZ(j); + getWorld().setBiome(BlockVector3.at(x, y, z), biome); + } + } + } + if (localChunk.getTiles().size() > 0) { + localChunk.getTiles().forEach(((blockVector3, tag) -> { + try { + BaseBlock block = getWorld().getBlock(blockVector3).toBaseBlock(tag); + getWorld().setBlock(blockVector3, block, sideEffectSet); + } catch (WorldEditException ignored) { + StateWrapper sw = new StateWrapper(tag); + sw.restoreTag(getWorld().getName(), blockVector3.getX(), blockVector3.getY(), blockVector3.getZ()); + } + })); + } + if (localChunk.getEntities().size() > 0) { + localChunk.getEntities().forEach((location, entity) -> { + getWorld().createEntity(location, entity); + }); + } + }; + } + Collection read = new ArrayList<>(); + if (getReadChunks().size() > 0) { + read.addAll(getReadChunks()); + } + chunkCoordinator = + chunkCoordinatorBuilderFactory.create(chunkCoordinatorFactory).inWorld(getWorld()).withChunks(getBlockChunks().keySet()).withChunks(read) + .withInitialBatchSize(3).withMaxIterationTime(40).withThrowableConsumer(Throwable::printStackTrace).withFinalAction(getCompleteTask()) + .withConsumer(consumer).unloadAfter(isUnloadAfter()).build(); + return super.enqueue(); + } + + /** + * Set a block to the world. First tries WNA but defaults to normal block setting methods if that fails + */ + private void setWorldBlock(int x, int y, int z, @Nonnull BaseBlock block, @Nonnull BlockVector2 blockVector2) { + try { + getWorld().setBlock(BlockVector3.at(x, y, z), block, sideEffectSet); + } catch (WorldEditException ignored) { + // Fallback to not so nice method + BlockData blockData = BukkitAdapter.adapt(block); + + if (bukkitWorld == null) { + bukkitWorld = Bukkit.getWorld(getWorld().getName()); + } + Chunk chunk = bukkitWorld.getChunkAt(blockVector2.getX(), blockVector2.getZ()); + + Block existing = chunk.getBlock(x, y, z); + final BlockState existingBaseBlock = BukkitAdapter.adapt(existing.getBlockData()); + if (BukkitBlockUtil.get(existing).equals(existingBaseBlock) && existing.getBlockData().matches(blockData)) { + return; + } + + if (existing.getState() instanceof Container) { + ((Container) existing.getState()).getInventory().clear(); + } + + existing.setType(BukkitAdapter.adapt(block.getBlockType()), false); + existing.setBlockData(blockData, false); + if (block.hasNbtData()) { + CompoundTag tag = block.getNbtData(); + StateWrapper sw = new StateWrapper(tag); + + sw.restoreTag(getWorld().getName(), existing.getX(), existing.getY(), existing.getZ()); + } + } + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/GenChunk.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/GenChunk.java index 9586ff7a6..ea22947dd 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/GenChunk.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/GenChunk.java @@ -30,7 +30,7 @@ import com.plotsquared.bukkit.util.BukkitBlockUtil; import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.location.ChunkWrapper; import com.plotsquared.core.location.Location; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.ChunkUtil; import com.plotsquared.core.util.PatternUtil; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -39,16 +39,17 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; +import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.generator.ChunkGenerator.BiomeGrid; import org.bukkit.generator.ChunkGenerator.ChunkData; - import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Arrays; -public class GenChunk extends ScopedLocalBlockQueue { +public class GenChunk extends ScopedQueueCoordinator { public final Biome[] biomes; public BlockState[][] result; @@ -64,7 +65,18 @@ public class GenChunk extends ScopedLocalBlockQueue { this.biomes = Biome.values(); } - public Chunk getChunk() { + @Nullable public ChunkData getChunkData() { + return this.chunkData; + } + + /** + * Set the internal Bukkit chunk data + */ + public void setChunkData(@Nonnull ChunkData chunkData) { + this.chunkData = chunkData; + } + + @Nonnull public Chunk getChunk() { if (chunk == null) { World worldObj = BukkitUtil.getWorld(world); if (worldObj != null) { @@ -74,32 +86,40 @@ public class GenChunk extends ScopedLocalBlockQueue { return chunk; } - public void setChunk(Chunk chunk) { + /** + * Set the chunk being represented + */ + public void setChunk(@Nonnull Chunk chunk) { this.chunk = chunk; } - public void setChunk(ChunkWrapper wrap) { + + /** + * Set the world and XZ of the chunk being represented via {@link ChunkWrapper} + */ + public void setChunk(@Nonnull ChunkWrapper wrap) { chunk = null; world = wrap.world; chunkX = wrap.x; chunkZ = wrap.z; } - @Override public void fillBiome(BiomeType biomeType) { + @Override public void fillBiome(@Nonnull BiomeType biomeType) { if (biomeGrid == null) { return; } Biome biome = BukkitAdapter.adapt(biomeType); - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - this.biomeGrid.setBiome(x, z, biome); + for (int y = 0; y < 256; y++) { + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + this.biomeGrid.setBiome(x, y, z, biome); + } } } } - @Override public void setCuboid(Location pos1, Location pos2, BlockState block) { - if (result != null && pos1.getX() == 0 && pos1.getZ() == 0 && pos2.getX() == 15 - && pos2.getZ() == 15) { + @Override public void setCuboid(@Nonnull Location pos1, @Nonnull Location pos2, @Nonnull BlockState block) { + if (result != null && pos1.getX() == 0 && pos1.getZ() == 0 && pos2.getX() == 15 && pos2.getZ() == 15) { for (int y = pos1.getY(); y <= pos2.getY(); y++) { int layer = y >> 4; BlockState[] data = result[layer]; @@ -117,28 +137,39 @@ public class GenChunk extends ScopedLocalBlockQueue { int maxX = Math.max(pos1.getX(), pos2.getX()); int maxY = Math.max(pos1.getY(), pos2.getY()); int maxZ = Math.max(pos1.getZ(), pos2.getZ()); - chunkData - .setRegion(minX, minY, minZ, maxX + 1, maxY + 1, maxZ + 1, BukkitAdapter.adapt(block)); + chunkData.setRegion(minX, minY, minZ, maxX + 1, maxY + 1, maxZ + 1, BukkitAdapter.adapt(block)); } - @Override public boolean setBiome(int x, int z, BiomeType biomeType) { + @Override public boolean setBiome(int x, int z, @Nonnull BiomeType biomeType) { return setBiome(x, z, BukkitAdapter.adapt(biomeType)); } - public boolean setBiome(int x, int z, Biome biome) { + /** + * Set the in the whole column of XZ + */ + public boolean setBiome(int x, int z, @Nonnull Biome biome) { if (this.biomeGrid != null) { - this.biomeGrid.setBiome(x, z, biome); + for (int y = 0; y < 256; y++) { + this.setBiome(x, y, z, biome); + } + return true; + } + return false; + } + + public boolean setBiome(int x, int y, int z, @Nonnull Biome biome) { + if (this.biomeGrid != null) { + this.biomeGrid.setBiome(x, y, z, biome); return true; } return false; } @Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) { - return setBlock(x, y, z, PatternUtil - .apply(Preconditions.checkNotNull(pattern, "Pattern may not be null"), x, y, z)); + return setBlock(x, y, z, PatternUtil.apply(Preconditions.checkNotNull(pattern, "Pattern may not be null"), x, y, z)); } - @Override public boolean setBlock(int x, int y, int z, BlockState id) { + @Override public boolean setBlock(int x, int y, int z, @Nonnull BlockState id) { if (this.result == null) { this.chunkData.setBlock(x, y, z, BukkitAdapter.adapt(id)); return true; @@ -148,7 +179,7 @@ public class GenChunk extends ScopedLocalBlockQueue { return true; } - private void storeCache(final int x, final int y, final int z, final BlockState id) { + private void storeCache(final int x, final int y, final int z, @Nonnull final BlockState id) { int i = y >> 4; BlockState[] v = this.result[i]; if (v == null) { @@ -158,7 +189,7 @@ public class GenChunk extends ScopedLocalBlockQueue { v[j] = id; } - @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { + @Override public boolean setBlock(int x, int y, int z, @Nonnull BaseBlock id) { if (this.result == null) { this.chunkData.setBlock(x, y, z, BukkitAdapter.adapt(id)); return true; @@ -168,7 +199,7 @@ public class GenChunk extends ScopedLocalBlockQueue { return true; } - @Override public BlockState getBlock(int x, int y, int z) { + @Override @Nullable public BlockState getBlock(int x, int y, int z) { int i = y >> 4; if (result == null) { return BukkitBlockUtil.get(chunkData.getType(x, y, z)); @@ -189,19 +220,19 @@ public class GenChunk extends ScopedLocalBlockQueue { return chunk == null ? chunkZ : chunk.getZ(); } - @Override public String getWorld() { - return chunk == null ? world : chunk.getWorld().getName(); + @Override @Nonnull public com.sk89q.worldedit.world.World getWorld() { + return chunk == null ? BukkitAdapter.adapt(Bukkit.getWorld(world)) : BukkitAdapter.adapt(chunk.getWorld()); } - @Override public Location getMax() { - return Location.at(getWorld(), 15 + (getX() << 4), 255, 15 + (getZ() << 4)); + @Override @Nonnull public Location getMax() { + return Location.at(getWorld().getName(), 15 + (getX() << 4), 255, 15 + (getZ() << 4)); } - @Override public Location getMin() { - return Location.at(getWorld(), getX() << 4, 0, getZ() << 4); + @Override @Nonnull public Location getMin() { + return Location.at(getWorld().getName(), getX() << 4, 0, getZ() << 4); } - public GenChunk clone() { + @Nonnull public GenChunk clone() { GenChunk toReturn = new GenChunk(); if (this.result != null) { for (int i = 0; i < this.result.length; i++) { @@ -215,12 +246,4 @@ public class GenChunk extends ScopedLocalBlockQueue { toReturn.chunkData = this.chunkData; return toReturn; } - - public ChunkData getChunkData() { - return this.chunkData; - } - - public void setChunkData(ChunkData chunkData) { - this.chunkData = chunkData; - } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/schematic/BukkitSchematicHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/schematic/BukkitSchematicHandler.java index e6e8d625c..f03428726 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/schematic/BukkitSchematicHandler.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/schematic/BukkitSchematicHandler.java @@ -27,7 +27,7 @@ package com.plotsquared.bukkit.schematic; import com.google.inject.Inject; import com.google.inject.Singleton; -import com.plotsquared.core.queue.LocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.SchematicHandler; import com.plotsquared.core.util.WorldUtil; import com.sk89q.jnbt.CompoundTag; @@ -44,7 +44,7 @@ import javax.annotation.Nonnull; } @Override - public boolean restoreTile(LocalBlockQueue queue, CompoundTag ct, int x, int y, int z) { - return new StateWrapper(ct).restoreTag(queue.getWorld(), x, y, z); + public boolean restoreTile(QueueCoordinator queue, CompoundTag ct, int x, int y, int z) { + return new StateWrapper(ct).restoreTag(queue.getWorld().getName(), x, y, z); } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitChunkManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitChunkManager.java index 325d47544..8086d805a 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitChunkManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitChunkManager.java @@ -26,140 +26,23 @@ package com.plotsquared.bukkit.util; import com.google.inject.Singleton; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.listener.WEExtent; -import com.plotsquared.core.queue.LocalBlockQueue; import com.plotsquared.core.util.ChunkManager; -import com.plotsquared.core.util.entity.EntityCategories; -import com.plotsquared.core.util.task.TaskManager; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.block.BaseBlock; import io.papermc.lib.PaperLib; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Entity; import java.util.concurrent.CompletableFuture; -import static com.plotsquared.core.util.entity.EntityCategories.CAP_ANIMAL; -import static com.plotsquared.core.util.entity.EntityCategories.CAP_ENTITY; -import static com.plotsquared.core.util.entity.EntityCategories.CAP_MISC; -import static com.plotsquared.core.util.entity.EntityCategories.CAP_MOB; -import static com.plotsquared.core.util.entity.EntityCategories.CAP_MONSTER; -import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; - -@Singleton public class BukkitChunkManager extends ChunkManager { +@Singleton +public class BukkitChunkManager extends ChunkManager { public static boolean isIn(CuboidRegion region, int x, int z) { - return x >= region.getMinimumPoint().getX() && x <= region.getMaximumPoint().getX() - && z >= region.getMinimumPoint().getZ() && z <= region.getMaximumPoint().getZ(); + return x >= region.getMinimumPoint().getX() && x <= region.getMaximumPoint().getX() && z >= region.getMinimumPoint().getZ() && z <= region + .getMaximumPoint().getZ(); } - public static ContentMap swapChunk(World world1, World world2, Chunk pos1, Chunk pos2, - CuboidRegion r1, CuboidRegion r2) { - ContentMap map = new ContentMap(); - int relX = r2.getMinimumPoint().getX() - r1.getMinimumPoint().getX(); - int relZ = r2.getMinimumPoint().getZ() - r1.getMinimumPoint().getZ(); - - map.saveEntitiesIn(pos1, r1, relX, relZ, true); - map.saveEntitiesIn(pos2, r2, -relX, -relZ, true); - - int sx = pos1.getX() << 4; - int sz = pos1.getZ() << 4; - - String worldName1 = world1.getName(); - String worldName2 = world2.getName(); - - BukkitWorld bukkitWorld1 = new BukkitWorld(world1); - BukkitWorld bukkitWorld2 = new BukkitWorld(world2); - - LocalBlockQueue queue1 = PlotSquared.platform().getGlobalBlockQueue().getNewQueue(worldName1, false); - LocalBlockQueue queue2 = PlotSquared.platform().getGlobalBlockQueue().getNewQueue(worldName2, false); - - for (int x = Math.max(r1.getMinimumPoint().getX(), sx); - x <= Math.min(r1.getMaximumPoint().getX(), sx + 15); x++) { - for (int z = Math.max(r1.getMinimumPoint().getZ(), sz); - z <= Math.min(r1.getMaximumPoint().getZ(), sz + 15); z++) { - for (int y = 0; y < 256; y++) { - Block block1 = world1.getBlockAt(x, y, z); - BaseBlock baseBlock1 = bukkitWorld1.getFullBlock(BlockVector3.at(x, y, z)); - BlockData data1 = block1.getBlockData(); - - int xx = x + relX; - int zz = z + relZ; - - Block block2 = world2.getBlockAt(xx, y, zz); - BaseBlock baseBlock2 = bukkitWorld2.getFullBlock(BlockVector3.at(xx, y, zz)); - BlockData data2 = block2.getBlockData(); - - if (block1.isEmpty()) { - if (!block2.isEmpty()) { - queue1.setBlock(x, y, z, baseBlock2); - queue2.setBlock(xx, y, zz, WEExtent.AIRBASE); - } - } else if (block2.isEmpty()) { - queue1.setBlock(x, y, z, WEExtent.AIRBASE); - queue2.setBlock(xx, y, zz, baseBlock1); - } else if (block1.equals(block2)) { - if (!data1.matches(data2)) { - block1.setBlockData(data2); - block2.setBlockData(data1); - } - } else { - queue1.setBlock(x, y, z, baseBlock2); - queue2.setBlock(xx, y, zz, baseBlock1); - } - } - } - } - queue1.enqueue(); - queue2.enqueue(); - return map; + @Override public CompletableFuture loadChunk(String world, BlockVector2 chunkLoc, boolean force) { + return PaperLib.getChunkAtAsync(BukkitUtil.getWorld(world), chunkLoc.getX(), chunkLoc.getZ(), force); } - @Override - public CompletableFuture loadChunk(String world, BlockVector2 chunkLoc, boolean force) { - return PaperLib - .getChunkAtAsync(BukkitUtil.getWorld(world), chunkLoc.getX(), chunkLoc.getZ(), force); - } - - @Override - public void unloadChunk(final String world, final BlockVector2 chunkLoc, final boolean save) { - if (!PlotSquared.get().isMainThread(Thread.currentThread())) { - TaskManager.runTask(() -> BukkitUtil.getWorld(world) - .unloadChunk(chunkLoc.getX(), chunkLoc.getZ(), save)); - } else { - BukkitUtil.getWorld(world).unloadChunk(chunkLoc.getX(), chunkLoc.getZ(), save); - } - } - - private void count(int[] count, Entity entity) { - final com.sk89q.worldedit.world.entity.EntityType entityType = - BukkitAdapter.adapt(entity.getType()); - - if (EntityCategories.PLAYER.contains(entityType)) { - return; - } else if (EntityCategories.PROJECTILE.contains(entityType) || EntityCategories.OTHER - .contains(entityType) || EntityCategories.HANGING.contains(entityType)) { - count[CAP_MISC]++; - } else if (EntityCategories.ANIMAL.contains(entityType) || EntityCategories.VILLAGER - .contains(entityType) || EntityCategories.TAMEABLE.contains(entityType)) { - count[CAP_MOB]++; - count[CAP_ANIMAL]++; - } else if (EntityCategories.VEHICLE.contains(entityType)) { - count[CAP_VEHICLE]++; - } else if (EntityCategories.HOSTILE.contains(entityType)) { - count[CAP_MOB]++; - count[CAP_MONSTER]++; - } - count[CAP_ENTITY]++; - } - - } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEntityUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEntityUtil.java new file mode 100644 index 000000000..d080d53f6 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEntityUtil.java @@ -0,0 +1,381 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.bukkit.util; + +import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.Permission; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.flag.implementations.AnimalAttackFlag; +import com.plotsquared.core.plot.flag.implementations.AnimalCapFlag; +import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.plot.flag.implementations.EntityCapFlag; +import com.plotsquared.core.plot.flag.implementations.HangingBreakFlag; +import com.plotsquared.core.plot.flag.implementations.HostileAttackFlag; +import com.plotsquared.core.plot.flag.implementations.HostileCapFlag; +import com.plotsquared.core.plot.flag.implementations.MiscBreakFlag; +import com.plotsquared.core.plot.flag.implementations.MiscCapFlag; +import com.plotsquared.core.plot.flag.implementations.MobCapFlag; +import com.plotsquared.core.plot.flag.implementations.PveFlag; +import com.plotsquared.core.plot.flag.implementations.PvpFlag; +import com.plotsquared.core.plot.flag.implementations.TamedAttackFlag; +import com.plotsquared.core.plot.flag.implementations.VehicleCapFlag; +import com.plotsquared.core.util.EntityUtil; +import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.entity.EntityCategories; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.projectiles.BlockProjectileSource; +import org.bukkit.projectiles.ProjectileSource; + +import java.util.Objects; + +public class BukkitEntityUtil { + + public static final com.sk89q.worldedit.world.entity.EntityType FAKE_ENTITY_TYPE = + new com.sk89q.worldedit.world.entity.EntityType("plotsquared:fake"); + + public static boolean entityDamage(Entity damager, Entity victim) { + return entityDamage(damager, victim, null); + } + + public static boolean entityDamage(Entity damager, Entity victim, EntityDamageEvent.DamageCause cause) { + Location dloc = BukkitUtil.adapt(damager.getLocation()); + Location vloc = BukkitUtil.adapt(victim.getLocation()); + PlotArea dArea = dloc.getPlotArea(); + PlotArea vArea; + if (dArea != null && dArea.contains(vloc.getX(), vloc.getZ())) { + vArea = dArea; + } else { + vArea = vloc.getPlotArea(); + } + if (dArea == null && vArea == null) { + return true; + } + + Plot dplot; + if (dArea != null) { + dplot = dArea.getPlot(dloc); + } else { + dplot = null; + } + Plot vplot; + if (vArea != null) { + vplot = vArea.getPlot(vloc); + } else { + vplot = null; + } + + Plot plot; + String stub; + boolean isPlot = true; + if (dplot == null && vplot == null) { + if (dArea == null) { + return true; + } + plot = null; + stub = "road"; + isPlot = false; + } else { + // Prioritize plots for close to seamless pvp zones + if (victim.getTicksLived() > damager.getTicksLived()) { + if (dplot == null || !(victim instanceof Player)) { + if (vplot == null) { + plot = dplot; + } else { + plot = vplot; + } + } else { + plot = dplot; + } + } else if (dplot == null || !(victim instanceof Player)) { + if (vplot == null) { + plot = dplot; + } else { + plot = vplot; + } + } else if (vplot == null) { + plot = dplot; + } else { + plot = vplot; + } + if (plot.hasOwner()) { + stub = "other"; + } else { + stub = "unowned"; + } + } + boolean roadFlags = vArea != null ? vArea.isRoadFlags() : dArea.isRoadFlags(); + PlotArea area = vArea != null ? vArea : dArea; + + Player player; + if (damager instanceof Player) { // attacker is player + player = (Player) damager; + } else if (damager instanceof Projectile) { + Projectile projectile = (Projectile) damager; + ProjectileSource shooter = projectile.getShooter(); + if (shooter instanceof Player) { // shooter is player + player = (Player) shooter; + } else { // shooter is not player + if (shooter instanceof BlockProjectileSource) { + Location sLoc = BukkitUtil + .adapt(((BlockProjectileSource) shooter).getBlock().getLocation()); + dplot = dArea.getPlot(sLoc); + } + player = null; + } + } else { // Attacker is not player + player = null; + } + if (player != null) { + BukkitPlayer plotPlayer = BukkitUtil.adapt(player); + + final com.sk89q.worldedit.world.entity.EntityType entityType; + + // Create a fake entity type if the type does not have a name + if (victim.getType().getName() == null) { + entityType = FAKE_ENTITY_TYPE; + } else { + entityType = BukkitAdapter.adapt(victim.getType()); + } + + if (EntityCategories.HANGING.contains(entityType)) { // hanging + if (plot != null && (plot.getFlag(HangingBreakFlag.class) || plot + .isAdded(plotPlayer.getUUID()))) { + if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + if (!Permissions + .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_OTHER)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.build.other") + ); + return false; + } + } + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.destroy." + stub)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy." + stub) + ); + return false; + } + } else if (victim.getType() == EntityType.ARMOR_STAND) { + if (plot != null && (plot.getFlag(MiscBreakFlag.class) || plot + .isAdded(plotPlayer.getUUID()))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.destroy." + stub)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.destroy." + stub) + ); + if (plot != null) { + plot.debug(player.getName() + + " could not break armor stand because misc-break = false"); + } + return false; + } + } else if (EntityCategories.HOSTILE.contains(entityType)) { + if (isPlot) { + if (plot.getFlag(HostileAttackFlag.class) || plot.getFlag(PveFlag.class) || plot + .isAdded(plotPlayer.getUUID())) { + return true; + } + } else if (roadFlags && (area.getRoadFlag(HostileAttackFlag.class) || area + .getFlag(PveFlag.class))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.pve." + stub) + ); + if (plot != null) { + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false OR hostile-attack = false"); + } + return false; + } + } else if (EntityCategories.TAMEABLE.contains(entityType)) { // victim is tameable + if (isPlot) { + if (plot.getFlag(TamedAttackFlag.class) || plot.getFlag(PveFlag.class) || plot + .isAdded(plotPlayer.getUUID())) { + return true; + } + } else if (roadFlags && (area.getRoadFlag(TamedAttackFlag.class) || area + .getFlag(PveFlag.class))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.pve." + stub) + ); + if (plot != null) { + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false OR tamed-attack = false"); + } + return false; + } + } else if (EntityCategories.PLAYER.contains(entityType)) { + if (isPlot) { + if (!plot.getFlag(PvpFlag.class) && !Permissions + .hasPermission(plotPlayer, "plots.admin.pvp." + stub)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.pvp." + stub) + ); + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false"); + return false; + } else { + return true; + } + } else if (roadFlags && area.getRoadFlag(PvpFlag.class)) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pvp." + stub)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.pvp." + stub) + ); + return false; + } + } else if (EntityCategories.ANIMAL.contains(entityType)) { // victim is animal + if (isPlot) { + if (plot.getFlag(AnimalAttackFlag.class) || plot.getFlag(PveFlag.class) || plot + .isAdded(plotPlayer.getUUID())) { + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false OR animal-attack = false"); + return true; + } + } else if (roadFlags && (area.getRoadFlag(AnimalAttackFlag.class) || area + .getFlag(PveFlag.class))) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.pve." + stub) + ); + return false; + } + } + } else if (EntityCategories.VEHICLE + .contains(entityType)) { // Vehicles are managed in vehicle destroy event + return true; + } else { // victim is something else + if (isPlot) { + if (plot.getFlag(PveFlag.class) || plot.isAdded(plotPlayer.getUUID())) { + return true; + } + } else if (roadFlags && area.getRoadFlag(PveFlag.class)) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + plotPlayer.sendMessage( + TranslatableCaption.of("permission.no_permission_event"), + Template.of("node", "plots.admin.pve." + stub) + ); + if (plot != null) { + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false"); + } + return false; + } + } + return true; + } else if (dplot != null && (!dplot.equals(vplot) || Objects + .equals(dplot.getOwnerAbs(), vplot.getOwnerAbs()))) { + return vplot != null && vplot.getFlag(PveFlag.class); + } + //disable the firework damage. too much of a headache to support at the moment. + if (vplot != null) { + if (EntityDamageEvent.DamageCause.ENTITY_EXPLOSION == cause + && damager.getType() == EntityType.FIREWORK) { + return false; + } + } + if (vplot == null && roadFlags && area.getRoadFlag(PveFlag.class)) { + return true; + } + return ((vplot != null && vplot.getFlag(PveFlag.class)) || !(damager instanceof Arrow + && !(victim instanceof Creature))); + } + + public static boolean checkEntity(Entity entity, Plot plot) { + if (plot == null || !plot.hasOwner() || plot.getFlags().isEmpty() && plot.getArea() + .getFlagContainer().getFlagMap().isEmpty()) { + return false; + } + + final com.sk89q.worldedit.world.entity.EntityType entityType = + BukkitAdapter.adapt(entity.getType()); + + if (EntityCategories.PLAYER.contains(entityType)) { + return false; + } + + if (EntityCategories.PROJECTILE.contains(entityType) || EntityCategories.OTHER + .contains(entityType) || EntityCategories.HANGING.contains(entityType)) { + return EntityUtil.checkEntity(plot, EntityCapFlag.ENTITY_CAP_UNLIMITED, + MiscCapFlag.MISC_CAP_UNLIMITED); + } + + // Has to go go before vehicle as horses are both + // animals and vehicles + if (EntityCategories.ANIMAL.contains(entityType) || EntityCategories.VILLAGER + .contains(entityType) || EntityCategories.TAMEABLE.contains(entityType)) { + return EntityUtil + .checkEntity(plot, EntityCapFlag.ENTITY_CAP_UNLIMITED, MobCapFlag.MOB_CAP_UNLIMITED, + AnimalCapFlag.ANIMAL_CAP_UNLIMITED); + } + + if (EntityCategories.HOSTILE.contains(entityType)) { + return EntityUtil + .checkEntity(plot, EntityCapFlag.ENTITY_CAP_UNLIMITED, MobCapFlag.MOB_CAP_UNLIMITED, + HostileCapFlag.HOSTILE_CAP_UNLIMITED); + } + + if (EntityCategories.VEHICLE.contains(entityType)) { + return EntityUtil.checkEntity(plot, EntityCapFlag.ENTITY_CAP_UNLIMITED, + VehicleCapFlag.VEHICLE_CAP_UNLIMITED); + } + + return EntityUtil.checkEntity(plot, EntityCapFlag.ENTITY_CAP_UNLIMITED); + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java index d3ed2b53c..01e7bf769 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java @@ -27,29 +27,24 @@ package com.plotsquared.bukkit.util; import com.google.inject.Inject; import com.google.inject.Singleton; -import com.plotsquared.bukkit.BukkitPlatform; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.generator.AugmentedUtils; import com.plotsquared.core.location.Location; import com.plotsquared.core.location.PlotLoc; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotManager; -import com.plotsquared.core.queue.LocalBlockQueue; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.GlobalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.RegionUtil; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.entity.EntityCategories; import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.task.TaskTime; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; import io.papermc.lib.PaperLib; @@ -62,16 +57,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Map.Entry; -import java.util.Objects; import java.util.Set; -import java.util.concurrent.Semaphore; -import static com.google.common.base.Preconditions.checkNotNull; import static com.plotsquared.core.util.entity.EntityCategories.CAP_ANIMAL; import static com.plotsquared.core.util.entity.EntityCategories.CAP_ENTITY; import static com.plotsquared.core.util.entity.EntityCategories.CAP_MISC; @@ -79,44 +69,17 @@ import static com.plotsquared.core.util.entity.EntityCategories.CAP_MOB; import static com.plotsquared.core.util.entity.EntityCategories.CAP_MONSTER; import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; -@Singleton public class BukkitRegionManager extends RegionManager { +@Singleton +public class BukkitRegionManager extends RegionManager { - private static final Logger logger = LoggerFactory.getLogger("P2/" + BukkitRegionManager.class.getSimpleName()); + private static final Logger logger = + LoggerFactory.getLogger("P2/" + BukkitRegionManager.class.getSimpleName()); + private final GlobalBlockQueue blockQueue; - @Inject public BukkitRegionManager(@Nonnull final ChunkManager chunkManager) { - super(chunkManager); - } - - public static boolean isIn(CuboidRegion region, int x, int z) { - return x >= region.getMinimumPoint().getX() && x <= region.getMaximumPoint().getX() - && z >= region.getMinimumPoint().getZ() && z <= region.getMaximumPoint().getZ(); - } - - @Override public Set getChunkChunks(String world) { - Set chunks = super.getChunkChunks(world); - if (Bukkit.isPrimaryThread()) { - for (Chunk chunk : Objects.requireNonNull(Bukkit.getWorld(world)).getLoadedChunks()) { - BlockVector2 loc = BlockVector2.at(chunk.getX() >> 5, chunk.getZ() >> 5); - chunks.add(loc); - } - } else { - final Semaphore semaphore = new Semaphore(1); - try { - semaphore.acquire(); - Bukkit.getScheduler().runTask(BukkitPlatform.getPlugin(BukkitPlatform.class), () -> { - for (Chunk chunk : Objects.requireNonNull(Bukkit.getWorld(world)) - .getLoadedChunks()) { - BlockVector2 loc = BlockVector2.at(chunk.getX() >> 5, chunk.getZ() >> 5); - chunks.add(loc); - } - semaphore.release(); - }); - semaphore.acquireUninterruptibly(); - } catch (final Exception e) { - e.printStackTrace(); - } - } - return chunks; + @Inject + public BukkitRegionManager(@Nonnull WorldUtil worldUtil, @Nonnull GlobalBlockQueue blockQueue) { + super(worldUtil, blockQueue); + this.blockQueue = blockQueue; } @Override public boolean handleClear(Plot plot, Runnable whenDone, PlotManager manager) { @@ -131,7 +94,6 @@ import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; } PlotArea area = plot.getArea(); World world = BukkitUtil.getWorld(area.getWorldName()); - Location bot = plot.getBottomAbs(); Location top = plot.getTopAbs(); int bx = bot.getX() >> 4; @@ -199,65 +161,9 @@ import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; return count; } - @Override - public boolean copyRegion(Location pos1, Location pos2, Location newPos, - final Runnable whenDone) { - final int relX = newPos.getX() - pos1.getX(); - final int relZ = newPos.getZ() - pos1.getZ(); - - final CuboidRegion region = - RegionUtil.createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ()); - final World oldWorld = Bukkit.getWorld(pos1.getWorldName()); - final BukkitWorld oldBukkitWorld = new BukkitWorld(oldWorld); - final World newWorld = Bukkit.getWorld(newPos.getWorldName()); - assert newWorld != null; - assert oldWorld != null; - final String newWorldName = newWorld.getName(); - final ContentMap map = new ContentMap(); - final LocalBlockQueue queue = PlotSquared.platform().getGlobalBlockQueue().getNewQueue(newWorldName, false); - ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { - @Override public void run(int[] value) { - int bx = value[2]; - int bz = value[3]; - int tx = value[4]; - int tz = value[5]; - BlockVector2 loc = BlockVector2.at(value[0], value[1]); - int cxx = loc.getX() << 4; - int czz = loc.getZ() << 4; - PaperLib.getChunkAtAsync(oldWorld, loc.getX(), loc.getZ()) - .thenAccept(chunk1 -> map.saveEntitiesIn(chunk1, region)).thenRun(() -> { - for (int x = bx & 15; x <= (tx & 15); x++) { - for (int z = bz & 15; z <= (tz & 15); z++) { - map.saveBlocks(oldBukkitWorld, 256, cxx + x, czz + z, relX, relZ); - } - } - }); - } - }, () -> { - for (Entry entry : map.allBlocks.entrySet()) { - PlotLoc loc = entry.getKey(); - BaseBlock[] blocks = entry.getValue(); - for (int y = 0; y < blocks.length; y++) { - if (blocks[y] != null) { - BaseBlock block = blocks[y]; - queue.setBlock(loc.getX(), y, loc.getZ(), block); - } - } - } - queue.enqueue(); - PlotSquared.platform().getGlobalBlockQueue().addEmptyTask(() -> { - //map.restoreBlocks(newWorld, 0, 0); - map.restoreEntities(newWorld, relX, relZ); - TaskManager.runTask(whenDone); - }); - }, 5); - return true; - } - - @Override - public boolean regenerateRegion(final Location pos1, final Location pos2, + @Override public boolean regenerateRegion(final Location pos1, final Location pos2, final boolean ignoreAugment, final Runnable whenDone) { - final String world = pos1.getWorldName(); + final BukkitWorld world = new BukkitWorld((World) pos1.getWorld()); final int p1x = pos1.getX(); final int p1z = pos1.getZ(); @@ -268,144 +174,123 @@ import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; final int tcx = p2x >> 4; final int tcz = p2z >> 4; - final List chunks = new ArrayList<>(); + final QueueCoordinator queue = blockQueue.getNewQueue(world); + final QueueCoordinator regenQueue = blockQueue.getNewQueue(world); + queue.addReadChunks( + new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()).getChunks()); + queue.setChunkConsumer(chunk -> { - for (int x = bcx; x <= tcx; x++) { - for (int z = bcz; z <= tcz; z++) { - chunks.add(BlockVector2.at(x, z)); + int x = chunk.getX(); + int z = chunk.getZ(); + int xxb = x << 4; + int zzb = z << 4; + int xxt = xxb + 15; + int zzt = zzb + 15; + if (xxb >= p1x && xxt <= p2x && zzb >= p1z && zzt <= p2z) { + AugmentedUtils + .bypass(ignoreAugment, () -> regenQueue.regenChunk(chunk.getX(), chunk.getZ())); + return; } - } - final World worldObj = Bukkit.getWorld(world); - checkNotNull(worldObj, "Critical error during regeneration."); - final BukkitWorld bukkitWorldObj = new BukkitWorld(worldObj); - TaskManager.runTask(new Runnable() { - @Override public void run() { - long start = System.currentTimeMillis(); - while (!chunks.isEmpty() && System.currentTimeMillis() - start < 5) { - final BlockVector2 chunk = chunks.remove(0); - int x = chunk.getX(); - int z = chunk.getZ(); - int xxb = x << 4; - int zzb = z << 4; - int xxt = xxb + 15; - int zzt = zzb + 15; - PaperLib.getChunkAtAsync(worldObj, x, z, false).thenAccept(chunkObj -> { - if (chunkObj == null) { - return; - } - final LocalBlockQueue queue = PlotSquared.platform().getGlobalBlockQueue() - .getNewQueue(world, false); - if (xxb >= p1x && xxt <= p2x && zzb >= p1z && zzt <= p2z) { - AugmentedUtils.bypass(ignoreAugment, - () -> queue.regenChunkSafe(chunk.getX(), chunk.getZ())); - return; - } - boolean checkX1 = false; + boolean checkX1 = false; - int xxb2; + int xxb2; - if (x == bcx) { - xxb2 = p1x - 1; - checkX1 = true; - } else { - xxb2 = xxb; - } - boolean checkX2 = false; - int xxt2; - if (x == tcx) { - xxt2 = p2x + 1; - checkX2 = true; - } else { - xxt2 = xxt; - } - boolean checkZ1 = false; - int zzb2; - if (z == bcz) { - zzb2 = p1z - 1; - checkZ1 = true; - } else { - zzb2 = zzb; - } - boolean checkZ2 = false; - int zzt2; - if (z == tcz) { - zzt2 = p2z + 1; - checkZ2 = true; - } else { - zzt2 = zzt; - } - final ContentMap map = new ContentMap(); - if (checkX1) { - map.saveRegion(bukkitWorldObj, xxb, xxb2, zzb2, zzt2); // - } - if (checkX2) { - map.saveRegion(bukkitWorldObj, xxt2, xxt, zzb2, zzt2); // - } - if (checkZ1) { - map.saveRegion(bukkitWorldObj, xxb2, xxt2, zzb, zzb2); // - } - if (checkZ2) { - map.saveRegion(bukkitWorldObj, xxb2, xxt2, zzt2, zzt); // - } - if (checkX1 && checkZ1) { - map.saveRegion(bukkitWorldObj, xxb, xxb2, zzb, zzb2); // - } - if (checkX2 && checkZ1) { - map.saveRegion(bukkitWorldObj, xxt2, xxt, zzb, zzb2); // ? - } - if (checkX1 && checkZ2) { - map.saveRegion(bukkitWorldObj, xxb, xxb2, zzt2, zzt); // ? - } - if (checkX2 && checkZ2) { - map.saveRegion(bukkitWorldObj, xxt2, xxt, zzt2, zzt); // - } - CuboidRegion currentPlotClear = RegionUtil - .createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ()); - map.saveEntitiesOut(chunkObj, currentPlotClear); - AugmentedUtils.bypass(ignoreAugment, () -> ChunkManager - .setChunkInPlotArea(null, new RunnableVal() { - @Override public void run(ScopedLocalBlockQueue value) { - Location min = value.getMin(); - int bx = min.getX(); - int bz = min.getZ(); - for (int x1 = 0; x1 < 16; x1++) { - for (int z1 = 0; z1 < 16; z1++) { - PlotLoc plotLoc = new PlotLoc(bx + x1, bz + z1); - BaseBlock[] ids = map.allBlocks.get(plotLoc); - if (ids != null) { - for (int y = 0; - y < Math.min(128, ids.length); y++) { - BaseBlock id = ids[y]; - if (id != null) { - value.setBlock(x1, y, z1, id); - } else { - value.setBlock(x1, y, z1, - BlockTypes.AIR.getDefaultState()); - } - } - for (int y = Math.min(128, ids.length); - y < ids.length; y++) { - BaseBlock id = ids[y]; - if (id != null) { - value.setBlock(x1, y, z1, id); - } - } - } + if (x == bcx) { + xxb2 = p1x - 1; + checkX1 = true; + } else { + xxb2 = xxb; + } + boolean checkX2 = false; + int xxt2; + if (x == tcx) { + xxt2 = p2x + 1; + checkX2 = true; + } else { + xxt2 = xxt; + } + boolean checkZ1 = false; + int zzb2; + if (z == bcz) { + zzb2 = p1z - 1; + checkZ1 = true; + } else { + zzb2 = zzb; + } + boolean checkZ2 = false; + int zzt2; + if (z == tcz) { + zzt2 = p2z + 1; + checkZ2 = true; + } else { + zzt2 = zzt; + } + final ContentMap map = new ContentMap(); + if (checkX1) { + map.saveRegion(world, xxb, xxb2, zzb2, zzt2); // + } + if (checkX2) { + map.saveRegion(world, xxt2, xxt, zzb2, zzt2); // + } + if (checkZ1) { + map.saveRegion(world, xxb2, xxt2, zzb, zzb2); // + } + if (checkZ2) { + map.saveRegion(world, xxb2, xxt2, zzt2, zzt); // + } + if (checkX1 && checkZ1) { + map.saveRegion(world, xxb, xxb2, zzb, zzb2); // + } + if (checkX2 && checkZ1) { + map.saveRegion(world, xxt2, xxt, zzb, zzb2); // ? + } + if (checkX1 && checkZ2) { + map.saveRegion(world, xxb, xxb2, zzt2, zzt); // ? + } + if (checkX2 && checkZ2) { + map.saveRegion(world, xxt2, xxt, zzt2, zzt); // + } + CuboidRegion currentPlotClear = + RegionUtil.createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ()); + map.saveEntitiesOut(Bukkit.getWorld(world.getName()).getChunkAt(x, z), + currentPlotClear); + AugmentedUtils.bypass(ignoreAugment, () -> ChunkManager + .setChunkInPlotArea(null, new RunnableVal() { + @Override public void run(ScopedQueueCoordinator value) { + Location min = value.getMin(); + int bx = min.getX(); + int bz = min.getZ(); + for (int x1 = 0; x1 < 16; x1++) { + for (int z1 = 0; z1 < 16; z1++) { + PlotLoc plotLoc = new PlotLoc(bx + x1, bz + z1); + BaseBlock[] ids = map.allBlocks.get(plotLoc); + if (ids != null) { + for (int y = 0; y < Math.min(128, ids.length); y++) { + BaseBlock id = ids[y]; + if (id != null) { + value.setBlock(x1, y, z1, id); + } else { + value.setBlock(x1, y, z1, + BlockTypes.AIR.getDefaultState()); + } + } + for (int y = Math.min(128, ids.length); y < ids.length; y++) { + BaseBlock id = ids[y]; + if (id != null) { + value.setBlock(x1, y, z1, id); } } } - }, world, chunk)); - //map.restoreBlocks(worldObj, 0, 0); - map.restoreEntities(worldObj, 0, 0); - }); - } - if (!chunks.isEmpty()) { - TaskManager.runTaskLater(this, TaskTime.ticks(1L)); - } else { - TaskManager.runTaskLater(whenDone, TaskTime.ticks(1L)); - } - } + } + } + } + }, world.getName(), chunk)); + //map.restoreBlocks(worldObj, 0, 0); + map.restoreEntities(Bukkit.getWorld(world.getName()), 0, 0); }); + regenQueue.setCompleteTask(whenDone); + queue.setCompleteTask(regenQueue::enqueue); + queue.enqueue(); return true; } @@ -438,59 +323,6 @@ import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; } } - @Override - public void swap(Location bot1, Location top1, Location bot2, Location top2, - final Runnable whenDone) { - CuboidRegion region1 = - RegionUtil.createRegion(bot1.getX(), top1.getX(), bot1.getZ(), top1.getZ()); - CuboidRegion region2 = - RegionUtil.createRegion(bot2.getX(), top2.getX(), bot2.getZ(), top2.getZ()); - final World world1 = Bukkit.getWorld(bot1.getWorldName()); - final World world2 = Bukkit.getWorld(bot2.getWorldName()); - checkNotNull(world1, "Critical error during swap."); - checkNotNull(world2, "Critical error during swap."); - int relX = bot2.getX() - bot1.getX(); - int relZ = bot2.getZ() - bot1.getZ(); - - final ArrayDeque maps = new ArrayDeque<>(); - - for (int x = bot1.getX() >> 4; x <= top1.getX() >> 4; x++) { - for (int z = bot1.getZ() >> 4; z <= top1.getZ() >> 4; z++) { - Chunk chunk1 = world1.getChunkAt(x, z); - Chunk chunk2 = world2.getChunkAt(x + (relX >> 4), z + (relZ >> 4)); - maps.add( - BukkitChunkManager.swapChunk(world1, world2, chunk1, chunk2, region1, region2)); - } - } - PlotSquared.platform().getGlobalBlockQueue().addEmptyTask(() -> { - for (ContentMap map : maps) { - map.restoreEntities(world1, 0, 0); - TaskManager.runTaskLater(whenDone, TaskTime.ticks(1L)); - } - }); - } - - @Override - public void setBiome(final CuboidRegion region, final int extendBiome, final BiomeType biome, - final String world, final Runnable whenDone) { - Location pos1 = Location.at(world, region.getMinimumPoint().getX() - extendBiome, - region.getMinimumPoint().getY(), region.getMinimumPoint().getZ() - extendBiome); - Location pos2 = Location.at(world, region.getMaximumPoint().getX() + extendBiome, - region.getMaximumPoint().getY(), region.getMaximumPoint().getZ() + extendBiome); - final LocalBlockQueue queue = PlotSquared.platform().getGlobalBlockQueue() - .getNewQueue(world, false); - - ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { - @Override public void run(int[] value) { - BlockVector2 loc = BlockVector2.at(value[0], value[1]); - PlotSquared.platform().getChunkManager().loadChunk(world, loc, false).thenRun(() -> { - WorldUtil.setBiome(world, value[2], value[3], value[4], value[5], biome); - queue.refreshChunk(value[0], value[1]); - }); - } - }, whenDone, 5); - } - private void count(int[] count, Entity entity) { final com.sk89q.worldedit.world.entity.EntityType entityType = BukkitAdapter.adapt(entity.getType()); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java index 64ee7e724..962af3de8 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java @@ -25,7 +25,6 @@ */ package com.plotsquared.bukkit.util; -import com.google.inject.Inject; import com.google.inject.Singleton; import com.plotsquared.bukkit.BukkitPlatform; import com.plotsquared.bukkit.player.BukkitPlayer; @@ -38,7 +37,6 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.util.BlockUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.PlayerManager; -import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.TaskManager; @@ -106,12 +104,14 @@ import java.util.Collection; import java.util.HashSet; import java.util.Objects; import java.util.Set; +import java.util.concurrent.Semaphore; import java.util.function.Consumer; import java.util.function.IntConsumer; import java.util.stream.Stream; @SuppressWarnings({"unused", "WeakerAccess"}) -@Singleton public class BukkitUtil extends WorldUtil { +@Singleton +public class BukkitUtil extends WorldUtil { private static final Logger logger = LoggerFactory.getLogger("P2/" + BukkitUtil.class.getSimpleName()); @@ -121,10 +121,6 @@ import java.util.stream.Stream; private final Collection tileEntityTypes = new HashSet<>(); - @Inject public BukkitUtil(@Nonnull final RegionManager regionManager) { - super(regionManager); - } - /** * Turn a Bukkit {@link Player} into a PlotSquared {@link PlotPlayer} * @@ -144,8 +140,9 @@ import java.util.stream.Stream; * @return PlotSquared location */ @Nonnull public static Location adapt(@Nonnull final org.bukkit.Location location) { - return Location.at(com.plotsquared.bukkit.util.BukkitWorld.of(location.getWorld()), - MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()), MathMan.roundInt(location.getZ())); + return Location + .at(com.plotsquared.bukkit.util.BukkitWorld.of(location.getWorld()), MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()), + MathMan.roundInt(location.getZ())); } /** @@ -156,9 +153,9 @@ import java.util.stream.Stream; * @return PlotSquared location */ @Nonnull public static Location adaptComplete(@Nonnull final org.bukkit.Location location) { - return Location.at(com.plotsquared.bukkit.util.BukkitWorld.of(location.getWorld()), - MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()), MathMan.roundInt(location.getZ()), location.getYaw(), - location.getPitch()); + return Location + .at(com.plotsquared.bukkit.util.BukkitWorld.of(location.getWorld()), MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()), + MathMan.roundInt(location.getZ()), location.getYaw(), location.getPitch()); } /** @@ -169,8 +166,7 @@ import java.util.stream.Stream; * @return Bukkit location */ @Nonnull public static org.bukkit.Location adapt(@Nonnull final Location location) { - return new org.bukkit.Location((World) location.getWorld().getPlatformWorld(), location.getX(), - location.getY(), location.getZ()); + return new org.bukkit.Location((World) location.getWorld().getPlatformWorld(), location.getX(), location.getY(), location.getZ()); } /** @@ -183,30 +179,24 @@ import java.util.stream.Stream; return Bukkit.getWorld(string); } - private static void ensureLoaded(@Nonnull final String world, final int x, final int z, - @Nonnull final Consumer chunkConsumer) { - PaperLib.getChunkAtAsync(Objects.requireNonNull(getWorld(world)), - x >> 4, z >> 4, true) + private static void ensureLoaded(@Nonnull final String world, final int x, final int z, @Nonnull final Consumer chunkConsumer) { + PaperLib.getChunkAtAsync(Objects.requireNonNull(getWorld(world)), x >> 4, z >> 4, true) .thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk)); } private static void ensureLoaded(@Nonnull final Location location, @Nonnull final Consumer chunkConsumer) { - PaperLib.getChunkAtAsync(adapt(location), true) - .thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk)); + PaperLib.getChunkAtAsync(adapt(location), true).thenAccept(chunk -> ensureMainThread(chunkConsumer, chunk)); } - private static void ensureMainThread(@Nonnull final Consumer consumer, - @Nonnull final T value) { + private static void ensureMainThread(@Nonnull final Consumer consumer, @Nonnull final T value) { if (Bukkit.isPrimaryThread()) { consumer.accept(value); } else { - Bukkit.getScheduler() - .runTask(BukkitPlatform.getPlugin(BukkitPlatform.class), () -> consumer.accept(value)); + Bukkit.getScheduler().runTask(BukkitPlatform.getPlugin(BukkitPlatform.class), () -> consumer.accept(value)); } } - @Override public boolean isBlockSame(@Nonnull final BlockState block1, - @Nonnull final BlockState block2) { + @Override public boolean isBlockSame(@Nonnull final BlockState block1, @Nonnull final BlockState block2) { if (block1.equals(block2)) { return true; } @@ -219,20 +209,15 @@ import java.util.stream.Stream; return getWorld(worldName) != null; } - @Override public void getBiome(@Nonnull final String world, final int x, - final int z, @Nonnull final Consumer result) { - ensureLoaded(world, x, z, - chunk -> result.accept(BukkitAdapter.adapt(getWorld(world).getBiome(x, z)))); + @Override public void getBiome(@Nonnull final String world, final int x, final int z, @Nonnull final Consumer result) { + ensureLoaded(world, x, z, chunk -> result.accept(BukkitAdapter.adapt(getWorld(world).getBiome(x, z)))); } - @Override @Nonnull public BiomeType getBiomeSynchronous(@Nonnull final String world, - final int x, final int z) { + @Override @Nonnull public BiomeType getBiomeSynchronous(@Nonnull final String world, final int x, final int z) { return BukkitAdapter.adapt(Objects.requireNonNull(getWorld(world)).getBiome(x, z)); } - @Override - public void getHighestBlock(@Nonnull final String world, final int x, final int z, - @Nonnull final IntConsumer result) { + @Override public void getHighestBlock(@Nonnull final String world, final int x, final int z, @Nonnull final IntConsumer result) { ensureLoaded(world, x, z, chunk -> { final World bukkitWorld = Objects.requireNonNull(getWorld(world)); // Skip top and bottom block @@ -258,9 +243,7 @@ import java.util.stream.Stream; }); } - @Override @Nonnegative - public int getHighestBlockSynchronous(@Nonnull final String world, - final int x, final int z) { + @Override @Nonnegative public int getHighestBlockSynchronous(@Nonnull final String world, final int x, final int z) { final World bukkitWorld = Objects.requireNonNull(getWorld(world)); // Skip top and bottom block int air = 1; @@ -282,10 +265,8 @@ import java.util.stream.Stream; return bukkitWorld.getMaxHeight() - 1; } - @Override @Nonnull - public String[] getSignSynchronous(@Nonnull final Location location) { - Block block = Objects.requireNonNull(getWorld(location.getWorldName())) - .getBlockAt(location.getX(), location.getY(), location.getZ()); + @Override @Nonnull public String[] getSignSynchronous(@Nonnull final Location location) { + Block block = Objects.requireNonNull(getWorld(location.getWorldName())).getBlockAt(location.getX(), location.getY(), location.getZ()); try { return TaskManager.getPlatformImplementation().sync(() -> { if (block.getState() instanceof Sign) { @@ -300,11 +281,9 @@ import java.util.stream.Stream; return new String[0]; } - @Override @Nonnull - public Location getSpawn(@Nonnull final String world) { + @Override @Nonnull public Location getSpawn(@Nonnull final String world) { final org.bukkit.Location temp = getWorld(world).getSpawnLocation(); - return Location.at(world, temp.getBlockX(), temp.getBlockY(), temp.getBlockZ(), - temp.getYaw(), temp.getPitch()); + return Location.at(world, temp.getBlockX(), temp.getBlockY(), temp.getBlockZ(), temp.getYaw(), temp.getPitch()); } @Override public void setSpawn(@Nonnull final Location location) { @@ -362,16 +341,12 @@ import java.util.stream.Stream; }); } - @Override @Nonnull - public StringComparison.ComparisonResult getClosestBlock(@Nonnull String name) { + @Override @Nonnull public StringComparison.ComparisonResult getClosestBlock(@Nonnull String name) { BlockState state = BlockUtil.get(name); return new StringComparison().new ComparisonResult(1, state); } - @Override - public void setBiomes(@Nonnull final String worldName, - @Nonnull final CuboidRegion region, - @Nonnull final BiomeType biomeType) { + @Override public void setBiomes(@Nonnull final String worldName, @Nonnull final CuboidRegion region, @Nonnull final BiomeType biomeType) { final World world = getWorld(worldName); if (world == null) { logger.warn("[P2] An error occured while setting the biome because the world was null", new RuntimeException()); @@ -379,8 +354,7 @@ import java.util.stream.Stream; } final Biome biome = BukkitAdapter.adapt(biomeType); for (int x = region.getMinimumPoint().getX(); x <= region.getMaximumPoint().getX(); x++) { - for (int z = region.getMinimumPoint().getZ(); - z <= region.getMaximumPoint().getZ(); z++) { + for (int z = region.getMinimumPoint().getZ(); z <= region.getMaximumPoint().getZ(); z++) { if (world.getBiome(x, z) != biome) { world.setBiome(x, z, biome); } @@ -392,50 +366,41 @@ import java.util.stream.Stream; return new BukkitWorld(Bukkit.getWorld(world)); } - @Override - public void getBlock(@Nonnull final Location location, - @Nonnull final Consumer result) { + @Override public void refreshChunk(int x, int z, String world) { + Bukkit.getWorld(world).refreshChunk(x, z); + } + + @Override public void getBlock(@Nonnull final Location location, @Nonnull final Consumer result) { ensureLoaded(location, chunk -> { final World world = getWorld(location.getWorldName()); - final Block block = Objects.requireNonNull(world) - .getBlockAt(location.getX(), location.getY(), location.getZ()); - result.accept(Objects.requireNonNull(BukkitAdapter - .asBlockType(block.getType())).getDefaultState()); + final Block block = Objects.requireNonNull(world).getBlockAt(location.getX(), location.getY(), location.getZ()); + result.accept(Objects.requireNonNull(BukkitAdapter.asBlockType(block.getType())).getDefaultState()); }); } @Override @Nonnull public BlockState getBlockSynchronous(@Nonnull final Location location) { final World world = getWorld(location.getWorldName()); - final Block block = Objects.requireNonNull(world) - .getBlockAt(location.getX(), location.getY(), location.getZ()); - return Objects.requireNonNull(BukkitAdapter - .asBlockType(block.getType())).getDefaultState(); + final Block block = Objects.requireNonNull(world).getBlockAt(location.getX(), location.getY(), location.getZ()); + return Objects.requireNonNull(BukkitAdapter.asBlockType(block.getType())).getDefaultState(); } @Override @Nonnegative public double getHealth(@Nonnull final PlotPlayer player) { - return Objects.requireNonNull(Bukkit - .getPlayer(player.getUUID())).getHealth(); + return Objects.requireNonNull(Bukkit.getPlayer(player.getUUID())).getHealth(); } @Override @Nonnegative public int getFoodLevel(@Nonnull final PlotPlayer player) { - return Objects.requireNonNull(Bukkit.getPlayer(player.getUUID())) - .getFoodLevel(); + return Objects.requireNonNull(Bukkit.getPlayer(player.getUUID())).getFoodLevel(); } - @Override public void setHealth(@Nonnull final PlotPlayer player, - @Nonnegative final double health) { - Objects.requireNonNull(Bukkit.getPlayer(player.getUUID())) - .setHealth(health); + @Override public void setHealth(@Nonnull final PlotPlayer player, @Nonnegative final double health) { + Objects.requireNonNull(Bukkit.getPlayer(player.getUUID())).setHealth(health); } - @Override public void setFoodLevel(@Nonnull final PlotPlayer player, - @Nonnegative final int foodLevel) { + @Override public void setFoodLevel(@Nonnull final PlotPlayer player, @Nonnegative final int foodLevel) { Bukkit.getPlayer(player.getUUID()).setFoodLevel(foodLevel); } - @Override @Nonnull - public Set getTypesInCategory( - @Nonnull final String category) { + @Override @Nonnull public Set getTypesInCategory(@Nonnull final String category) { final Collection> allowedInterfaces = new HashSet<>(); switch (category) { case "animal": { @@ -524,28 +489,45 @@ import java.util.stream.Stream; tileEntityTypes.addAll(BlockCategories.FLOWER_POTS.getAll()); // Individual Types // Add these from strings - Stream.of("barrel", "beacon", "beehive", "bee_nest", "bell", "blast_furnace", - "brewing_stand", "campfire", "chest", "ender_chest", "trapped_chest", - "command_block", "end_gateway", "hopper", "jigsaw", "jubekox", - "lectern", "note_block", "black_shulker_box", "blue_shulker_box", - "brown_shulker_box", "cyan_shulker_box", "gray_shulker_box", "green_shulker_box", - "light_blue_shulker_box", "light_gray_shulker_box", "lime_shulker_box", - "magenta_shulker_box", "orange_shulker_box", "pink_shulker_box", - "purple_shulker_box", "red_shulker_box", "shulker_box", "white_shulker_box", - "yellow_shulker_box", "smoker", "structure_block", "structure_void") - .map(BlockTypes::get) - .filter(Objects::nonNull) - .forEach(tileEntityTypes::add); + Stream.of("barrel", "beacon", "beehive", "bee_nest", "bell", "blast_furnace", "brewing_stand", "campfire", "chest", "ender_chest", + "trapped_chest", "command_block", "end_gateway", "hopper", "jigsaw", "jubekox", "lectern", "note_block", "black_shulker_box", + "blue_shulker_box", "brown_shulker_box", "cyan_shulker_box", "gray_shulker_box", "green_shulker_box", "light_blue_shulker_box", + "light_gray_shulker_box", "lime_shulker_box", "magenta_shulker_box", "orange_shulker_box", "pink_shulker_box", "purple_shulker_box", + "red_shulker_box", "shulker_box", "white_shulker_box", "yellow_shulker_box", "smoker", "structure_block", "structure_void") + .map(BlockTypes::get).filter(Objects::nonNull).forEach(tileEntityTypes::add); } return this.tileEntityTypes; } - @Override @Nonnegative - public int getTileEntityCount(@Nonnull final String world, - @Nonnull final BlockVector2 chunk) { + @Override @Nonnegative public int getTileEntityCount(@Nonnull final String world, @Nonnull final BlockVector2 chunk) { return Objects.requireNonNull(getWorld(world)). - getChunkAt(chunk.getBlockX(), chunk.getBlockZ()) - .getTileEntities().length; + getChunkAt(chunk.getBlockX(), chunk.getBlockZ()).getTileEntities().length; + } + + @Override public Set getChunkChunks(String world) { + Set chunks = super.getChunkChunks(world); + if (Bukkit.isPrimaryThread()) { + for (Chunk chunk : Objects.requireNonNull(Bukkit.getWorld(world)).getLoadedChunks()) { + BlockVector2 loc = BlockVector2.at(chunk.getX() >> 5, chunk.getZ() >> 5); + chunks.add(loc); + } + } else { + final Semaphore semaphore = new Semaphore(1); + try { + semaphore.acquire(); + Bukkit.getScheduler().runTask(BukkitPlatform.getPlugin(BukkitPlatform.class), () -> { + for (Chunk chunk : Objects.requireNonNull(Bukkit.getWorld(world)).getLoadedChunks()) { + BlockVector2 loc = BlockVector2.at(chunk.getX() >> 5, chunk.getZ() >> 5); + chunks.add(loc); + } + semaphore.release(); + }); + semaphore.acquireUninterruptibly(); + } catch (final Exception e) { + e.printStackTrace(); + } + } + return chunks; } } diff --git a/Bukkit/src/main/resources/plugin.yml b/Bukkit/src/main/resources/plugin.yml index 3cfa79a65..175f201c8 100644 --- a/Bukkit/src/main/resources/plugin.yml +++ b/Bukkit/src/main/resources/plugin.yml @@ -6,7 +6,7 @@ load: STARTUP description: "Easy, yet powerful Plot World generation and management." authors: [Citymonstret, Empire92, MattBDev, dordsor21, NotMyFault, SirYwell] website: https://www.spigotmc.org/resources/77506/ -softdepend: [Vault, PlaceholderAPI, Essentials, LuckPerms, BungeePerms] +softdepend: [Vault, PlaceholderAPI, Essentials, LuckPerms, BungeePerms, MVdWPlaceholderAPI] loadbefore: [MultiWorld, Multiverse-Core] depend: [WorldEdit] database: false diff --git a/Core/pom.xml b/Core/pom.xml index 05142d3a8..bb7bfa913 100644 --- a/Core/pom.xml +++ b/Core/pom.xml @@ -48,16 +48,10 @@ 1.0 compile - - org.projectlombok - lombok - 1.18.12 - runtime - com.sk89q.worldedit worldedit-core - 7.0.0 + 7.2.0-SNAPSHOT runtime @@ -74,30 +68,6 @@ - - net.kyori - text-api - 3.0.2 - runtime - - - net.kyori - text-serializer-gson - 3.0.2 - runtime - - - net.kyori - text-serializer-legacy - 3.0.2 - runtime - - - net.kyori - text-serializer-plain - 3.0.2 - runtime - com.google.guava guava @@ -128,6 +98,18 @@ 1.7.0-SNAPSHOT runtime + + net.kyori + adventure-api + 4.0.0-SNAPSHOT + runtime + + + net.kyori + adventure-text-minimessage + 3.0.0-SNAPSHOT + runtime + org.apache.logging.log4j log4j-slf4j-impl diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 0b88ca931..9153d9215 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -59,6 +59,7 @@ import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.PlotManager; import com.plotsquared.core.plot.expiration.ExpireManager; import com.plotsquared.core.plot.expiration.ExpiryTask; +import com.plotsquared.core.plot.flag.GlobalFlagContainer; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; @@ -67,6 +68,7 @@ import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.LegacyConverter; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.ReflectionUtils; +import com.plotsquared.core.util.placeholders.PlaceholderRegistry; import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.uuid.UUIDPipeline; import com.sk89q.worldedit.WorldEdit; @@ -147,7 +149,7 @@ public class PlotSquared { private File storageFile; private EventDispatcher eventDispatcher; private PlotListener plotListener; - + private PlaceholderRegistry placeholderRegistry; /** * Initialize PlotSquared with the desired Implementation class. * @@ -172,6 +174,9 @@ public class PlotSquared { // ConfigurationSerialization.registerClass(BlockBucket.class, "BlockBucket"); + // Setup the global flag container + GlobalFlagContainer.setup(); + try { new ReflectionUtils(this.platform.getNMSPackage()); try { @@ -1501,6 +1506,10 @@ public class PlotSquared { return this.plotListener; } + public PlaceholderRegistry getPlaceholderRegistry() { + return this.placeholderRegistry; + } + public enum SortType { CREATION_DATE, CREATION_DATE_TIMESTAMP, LAST_MODIFIED, DISTANCE_FROM_ORIGIN } diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index f487df952..e918f8daa 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -49,6 +49,8 @@ import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.world.PlotAreaManager; +import com.plotsquared.core.queue.GlobalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.MathMan; @@ -59,7 +61,6 @@ import com.plotsquared.core.util.SchematicHandler; import com.plotsquared.core.util.SetupUtils; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal3; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; @@ -70,11 +71,9 @@ import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; -import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.Template; import javax.annotation.Nonnull; @@ -107,16 +106,16 @@ public class Area extends SubCommand { private final SetupUtils setupUtils; private final WorldUtil worldUtil; private final RegionManager regionManager; + private final GlobalBlockQueue blockQueue; private final Map> metaData = new HashMap<>(); @Inject public Area(@Nonnull final PlotAreaManager plotAreaManager, - @WorldConfig @Nonnull final YamlConfiguration worldConfiguration, - @WorldFile @Nonnull final File worldFile, - @Nonnull final HybridPlotWorldFactory hybridPlotWorldFactory, - @Nonnull final SetupUtils setupUtils, - @Nonnull final WorldUtil worldUtil, - @Nonnull final RegionManager regionManager) { + @WorldConfig @Nonnull final YamlConfiguration worldConfiguration, + @WorldFile @Nonnull final File worldFile, + @Nonnull final HybridPlotWorldFactory hybridPlotWorldFactory, + @Nonnull final SetupUtils setupUtils, @Nonnull final WorldUtil worldUtil, + @Nonnull final RegionManager regionManager, @Nonnull final GlobalBlockQueue blockQueue) { this.plotAreaManager = plotAreaManager; this.worldConfiguration = worldConfiguration; this.worldFile = worldFile; @@ -124,6 +123,7 @@ public class Area extends SubCommand { this.setupUtils = setupUtils; this.worldUtil = worldUtil; this.regionManager = regionManager; + this.blockQueue = blockQueue; } @Override public boolean onCommand(final PlotPlayer player, String[] args) { @@ -146,20 +146,24 @@ public class Area extends SubCommand { player.sendMessage(TranslatableCaption.of("single.single_area_needs_name")); return false; } - final PlotArea existingArea = this.plotAreaManager.getPlotArea(player.getLocation().getWorldName(), args[1]); + final PlotArea existingArea = + this.plotAreaManager.getPlotArea(player.getLocation().getWorldName(), args[1]); if (existingArea != null && existingArea.getId().equalsIgnoreCase(args[1])) { player.sendMessage(TranslatableCaption.of("single.single_area_name_taken")); return false; } - final LocalSession localSession = WorldEdit.getInstance().getSessionManager().getIfPresent(player.toActor()); + final LocalSession localSession = + WorldEdit.getInstance().getSessionManager().getIfPresent(player.toActor()); if (localSession == null) { player.sendMessage(TranslatableCaption.of("single.single_area_missing_selection")); return false; } Region playerSelectedRegion = null; try { - playerSelectedRegion = localSession.getSelection(((Player) player.toActor()).getWorld()); - } catch (final Exception ignored) {} + playerSelectedRegion = + localSession.getSelection(((Player) player.toActor()).getWorld()); + } catch (final Exception ignored) { + } if (playerSelectedRegion == null) { player.sendMessage(TranslatableCaption.of("single.single_area_missing_selection")); return false; @@ -176,15 +180,19 @@ public class Area extends SubCommand { final BlockVector3 playerSelectionMin = playerSelectedRegion.getMinimumPoint(); final BlockVector3 playerSelectionMax = playerSelectedRegion.getMaximumPoint(); // Create a new selection that spans the entire vertical range of the world - final CuboidRegion selectedRegion = new CuboidRegion(playerSelectedRegion.getWorld(), - BlockVector3.at(playerSelectionMin.getX(), 0, playerSelectionMin.getZ()), - BlockVector3.at(playerSelectionMax.getX(), 255, playerSelectionMax.getZ())); + final CuboidRegion selectedRegion = + new CuboidRegion(playerSelectedRegion.getWorld(), + BlockVector3.at(playerSelectionMin.getX(), 0, playerSelectionMin.getZ()), + BlockVector3.at(playerSelectionMax.getX(), 255, playerSelectionMax.getZ())); // There's only one plot in the area... final PlotId plotId = PlotId.of(1, 1); - final HybridPlotWorld hybridPlotWorld = this.hybridPlotWorldFactory.create(player.getLocation().getWorldName(), args[1], - Objects.requireNonNull(PlotSquared.platform()).getDefaultGenerator(), plotId, plotId); + final HybridPlotWorld hybridPlotWorld = this.hybridPlotWorldFactory + .create(player.getLocation().getWorldName(), args[1], + Objects.requireNonNull(PlotSquared.platform()).getDefaultGenerator(), + plotId, plotId); // Plot size is the same as the region width - hybridPlotWorld.PLOT_WIDTH = hybridPlotWorld.SIZE = (short) selectedRegion.getWidth(); + hybridPlotWorld.PLOT_WIDTH = + hybridPlotWorld.SIZE = (short) selectedRegion.getWidth(); // We use a schematic generator hybridPlotWorld.setTerrain(PlotAreaTerrainType.NONE); // It is always a partial plot world @@ -192,23 +200,30 @@ public class Area extends SubCommand { // We save the schematic :D hybridPlotWorld.PLOT_SCHEMATIC = true; // Set the road width to 0 - hybridPlotWorld.ROAD_WIDTH = hybridPlotWorld.ROAD_OFFSET_X = hybridPlotWorld.ROAD_OFFSET_Z = 0; + hybridPlotWorld.ROAD_WIDTH = + hybridPlotWorld.ROAD_OFFSET_X = hybridPlotWorld.ROAD_OFFSET_Z = 0; // Set the plot height to the selection height - hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = hybridPlotWorld.WALL_HEIGHT = playerSelectionMin.getBlockY(); + hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = + hybridPlotWorld.WALL_HEIGHT = playerSelectionMin.getBlockY(); // No sign plz hybridPlotWorld.setAllowSigns(false); - final File parentFile = FileUtils.getFile(PlotSquared.platform().getDirectory(), "schematics" + File.separator + - "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator + - hybridPlotWorld.getId()); + final File parentFile = FileUtils.getFile(PlotSquared.platform().getDirectory(), + "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + + hybridPlotWorld.getWorldName() + File.separator + hybridPlotWorld + .getId()); if (!parentFile.exists() && !parentFile.mkdirs()) { player.sendMessage(TranslatableCaption.of("single.single_area_could_not_make_directories")); return false; } final File file = new File(parentFile, "plot.schem"); - try (final ClipboardWriter clipboardWriter = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) { + try (final ClipboardWriter clipboardWriter = BuiltInClipboardFormat.SPONGE_SCHEMATIC + .getWriter(new FileOutputStream(file))) { final BlockArrayClipboard clipboard = new BlockArrayClipboard(selectedRegion); - final EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(selectedRegion.getWorld(), -1); - final ForwardExtentCopy forwardExtentCopy = new ForwardExtentCopy(editSession, selectedRegion, clipboard, selectedRegion.getMinimumPoint()); + final EditSession editSession = WorldEdit.getInstance().getEditSessionFactory() + .getEditSession(selectedRegion.getWorld(), -1); + final ForwardExtentCopy forwardExtentCopy = + new ForwardExtentCopy(editSession, selectedRegion, clipboard, + selectedRegion.getMinimumPoint()); forwardExtentCopy.setCopyingBiomes(true); forwardExtentCopy.setCopyingEntities(true); Operations.complete(forwardExtentCopy); @@ -231,14 +246,14 @@ public class Area extends SubCommand { // Now the schematic is saved, which is wonderful! PlotAreaBuilder singleBuilder = PlotAreaBuilder.ofPlotArea(hybridPlotWorld) - .plotManager(PlotSquared.platform().getPluginName()) - .generatorName(PlotSquared.platform().getPluginName()) - .maximumId(plotId) - .minimumId(plotId); + .plotManager(PlotSquared.platform().getPluginName()) + .generatorName(PlotSquared.platform().getPluginName()).maximumId(plotId) + .minimumId(plotId); Runnable singleRun = () -> { final String path = - "worlds." + hybridPlotWorld.getWorldName() + ".areas." + hybridPlotWorld.getId() + '-' - + singleBuilder.minimumId() + '-' + singleBuilder.maximumId(); + "worlds." + hybridPlotWorld.getWorldName() + ".areas." + hybridPlotWorld + .getId() + '-' + singleBuilder.minimumId() + '-' + singleBuilder + .maximumId(); final int offsetX = singlePos1.getX(); final int offsetZ = singlePos1.getZ(); if (offsetX != 0) { @@ -276,8 +291,9 @@ public class Area extends SubCommand { case 2: switch (args[1].toLowerCase()) { case "pos1": { // Set position 1 - HybridPlotWorld area = (HybridPlotWorld) metaData.computeIfAbsent(player.getUUID(), missingUUID -> new HashMap<>()) - .get("area_create_area"); + HybridPlotWorld area = (HybridPlotWorld) metaData + .computeIfAbsent(player.getUUID(), + missingUUID -> new HashMap<>()).get("area_create_area"); if (area == null) { player.sendMessage(TranslatableCaption.of("commandconfig.command_syntax"), Templates.of("value", "/plot area create [world[:id]] [=]...")); @@ -294,14 +310,17 @@ public class Area extends SubCommand { } case "pos2": // Set position 2 and finish creation for type=2 (partial) final HybridPlotWorld area = (HybridPlotWorld) metaData - .computeIfAbsent(player.getUUID(), missingUUID -> new HashMap<>()).get("area_create_area"); + .computeIfAbsent(player.getUUID(), + missingUUID -> new HashMap<>()).get("area_create_area"); if (area == null) { player.sendMessage(TranslatableCaption.of("commandconfig.command_syntax"), Templates.of("value", "/plot area create [world[:id]] [=]...")); return false; } Location pos1 = player.getLocation(); - Location pos2 = (Location) metaData.computeIfAbsent(player.getUUID(), missingUUID -> new HashMap<>()).get("area_pos1"); + Location pos2 = (Location) metaData + .computeIfAbsent(player.getUUID(), + missingUUID -> new HashMap<>()).get("area_pos1"); int dx = Math.abs(pos1.getX() - pos2.getX()); int dz = Math.abs(pos1.getZ() - pos2.getZ()); int numX = Math.max(1, @@ -328,19 +347,20 @@ public class Area extends SubCommand { return false; } PlotAreaBuilder builder = PlotAreaBuilder.ofPlotArea(area) - .plotManager(PlotSquared.platform().getPluginName()) - .generatorName(PlotSquared.platform().getPluginName()) - .minimumId(PlotId.of(1, 1)) - .maximumId(PlotId.of(numX, numZ)); + .plotManager(PlotSquared.platform().getPluginName()) + .generatorName(PlotSquared.platform().getPluginName()) + .minimumId(PlotId.of(1, 1)).maximumId(PlotId.of(numX, numZ)); final String path = "worlds." + area.getWorldName() + ".areas." + area.getId() + '-' + builder.minimumId() + '-' + builder.maximumId(); Runnable run = () -> { if (offsetX != 0) { - this.worldConfiguration.set(path + ".road.offset.x", offsetX); + this.worldConfiguration + .set(path + ".road.offset.x", offsetX); } if (offsetZ != 0) { - this.worldConfiguration.set(path + ".road.offset.z", offsetZ); + this.worldConfiguration + .set(path + ".road.offset.z", offsetZ); } final String world = this.setupUtils.setupWorld(builder); if (this.worldUtil.isWorld(world)) { @@ -349,14 +369,13 @@ public class Area extends SubCommand { player.teleport(this.worldUtil.getSpawn(world), TeleportCause.COMMAND); if (area.getTerrain() != PlotAreaTerrainType.ALL) { - this.regionManager.largeRegionTask(world, region, - new RunnableVal() { - @Override public void run(BlockVector2 value) { - AugmentedUtils - .generate(null, world, value.getX(), - value.getZ(), null); - } - }, null); + QueueCoordinator queue = + blockQueue.getNewQueue(worldUtil.getWeWorld(world)); + queue.setChunkConsumer(chunk -> AugmentedUtils + .generate(null, world, chunk.getX(), chunk.getZ(), + null)); + queue.addReadChunks(region.getChunks()); + queue.enqueue(); } } else { player.sendMessage( @@ -383,15 +402,17 @@ public class Area extends SubCommand { } PlotAreaBuilder builder = PlotAreaBuilder.newBuilder(); builder.worldName(split[0]); - final HybridPlotWorld pa = this.hybridPlotWorldFactory.create(builder.worldName(), - id, PlotSquared.platform().getDefaultGenerator(), null, null); + final HybridPlotWorld pa = this.hybridPlotWorldFactory + .create(builder.worldName(), id, + PlotSquared.platform().getDefaultGenerator(), null, null); PlotArea other = this.plotAreaManager.getPlotArea(pa.getWorldName(), id); if (other != null && Objects.equals(pa.getId(), other.getId())) { player.sendMessage(TranslatableCaption.of("setup.setup_world_taken"), Template.of("value", pa.toString())); return false; } - Set areas = this.plotAreaManager.getPlotAreasSet(pa.getWorldName()); + Set areas = + this.plotAreaManager.getPlotAreasSet(pa.getWorldName()); if (!areas.isEmpty()) { PlotArea area = areas.iterator().next(); pa.setType(area.getType()); @@ -477,7 +498,8 @@ public class Area extends SubCommand { if (!this.worldConfiguration.contains(path)) { this.worldConfiguration.createSection(path); } - ConfigurationSection section = this.worldConfiguration.getConfigurationSection(path); + ConfigurationSection section = + this.worldConfiguration.getConfigurationSection(path); pa.saveConfiguration(section); pa.loadConfiguration(section); builder.plotManager(PlotSquared.platform().getPluginName()); @@ -627,7 +649,8 @@ public class Area extends SubCommand { ); return false; } - final List areas = new ArrayList<>(Arrays.asList(this.plotAreaManager.getAllPlotAreas())); + final List areas = + new ArrayList<>(Arrays.asList(this.plotAreaManager.getAllPlotAreas())); paginate(player, areas, 8, page, new RunnableVal3() { @Override public void run(Integer i, PlotArea area, CaptionHolder caption) { @@ -642,7 +665,8 @@ public class Area extends SubCommand { PlotId max = area.getMax(); name = area.getWorldName() + ';' + area.getId() + ';' + min + ';' + max; - int size = (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1); + int size = + (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1); percent = claimed == 0 ? 0 : size / (double) claimed; region = area.getRegion().toString(); } else { @@ -694,15 +718,13 @@ public class Area extends SubCommand { ); return false; } - this.regionManager.largeRegionTask(area.getWorldName(), area.getRegion(), - new RunnableVal() { - @Override public void run(BlockVector2 value) { - AugmentedUtils - .generate(null, area.getWorldName(), value.getX(), value.getZ(), - null); - } - }, () -> player.sendMessage(TranslatableCaption.of("single.regeneration_complete")) - ); + QueueCoordinator queue = + blockQueue.getNewQueue(worldUtil.getWeWorld(area.getWorldName())); + queue.setChunkConsumer(chunk -> AugmentedUtils + .generate(null, area.getWorldName(), chunk.getX(), chunk.getZ(), null)); + queue.addReadChunks(area.getRegion().getChunks()); + queue.setCompleteTask(() -> player.sendMessage(TranslatableCaption.of("single.regeneration_complete"))); + queue.enqueue(); return true; } case "goto": @@ -735,11 +757,13 @@ public class Area extends SubCommand { } else { CuboidRegion region = area.getRegion(); center = Location.at(area.getWorldName(), region.getMinimumPoint().getX() - + (region.getMaximumPoint().getX() - region.getMinimumPoint().getX()) / 2, + + (region.getMaximumPoint().getX() - region.getMinimumPoint().getX()) / 2, 0, region.getMinimumPoint().getZ() - + (region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ()) / 2); - this.worldUtil.getHighestBlock(area.getWorldName(), center.getX(), center.getZ(), y -> - player.teleport(center.withY(1 + y), TeleportCause.COMMAND)); + + (region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ()) + / 2); + this.worldUtil + .getHighestBlock(area.getWorldName(), center.getX(), center.getZ(), + y -> player.teleport(center.withY(1 + y), TeleportCause.COMMAND)); } return true; case "delete": diff --git a/Core/src/main/java/com/plotsquared/core/command/Clear.java b/Core/src/main/java/com/plotsquared/core/command/Clear.java index 7faf174d3..bd9478cd6 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Clear.java +++ b/Core/src/main/java/com/plotsquared/core/command/Clear.java @@ -42,7 +42,7 @@ import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; import net.kyori.adventure.text.minimessage.Template; - +import com.plotsquared.core.util.task.TaskManager; import javax.annotation.Nonnull; import java.util.concurrent.CompletableFuture; @@ -94,7 +94,7 @@ public class Clear extends Command { final long start = System.currentTimeMillis(); boolean result = plot.clear(true, false, () -> { plot.unlink(); - this.blockQueue.addEmptyTask(() -> { + TaskManager.runTask(() -> { plot.removeRunning(); // If the state changes, then mark it as no longer done if (DoneFlag.isDone(plot)) { diff --git a/Core/src/main/java/com/plotsquared/core/command/CommandCaller.java b/Core/src/main/java/com/plotsquared/core/command/CommandCaller.java index fe517fc9a..46720f24a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/CommandCaller.java +++ b/Core/src/main/java/com/plotsquared/core/command/CommandCaller.java @@ -51,15 +51,6 @@ public interface CommandCaller { */ boolean hasPermission(@Nonnull String permission); - /** - * Checks if this object contains an override for the specified - * permission, by fully qualified name - * - * @param permission Name of the permission - * @return true if the permission is set, otherwise false - */ - boolean isPermissionSet(@Nonnull String permission); - /** * Get the type of the caller * diff --git a/Core/src/main/java/com/plotsquared/core/command/Debug.java b/Core/src/main/java/com/plotsquared/core/command/Debug.java index 2741ff1c4..19e59ecf9 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Debug.java +++ b/Core/src/main/java/com/plotsquared/core/command/Debug.java @@ -33,8 +33,8 @@ import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.player.ConsolePlayer; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.StringMan; +import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.entity.EntityCategories; import com.plotsquared.core.util.entity.EntityCategory; import com.plotsquared.core.util.query.PlotQuery; @@ -63,12 +63,12 @@ public class Debug extends SubCommand { private static final Logger logger = LoggerFactory.getLogger("P2/" + Debug.class.getSimpleName()); private final PlotAreaManager plotAreaManager; - private final RegionManager regionManager; + private final WorldUtil worldUtil; @Inject public Debug(@Nonnull final PlotAreaManager plotAreaManager, - @Nonnull final RegionManager regionManager) { + @Nonnull final WorldUtil worldUtil) { this.plotAreaManager = plotAreaManager; - this.regionManager = regionManager; + this.worldUtil = worldUtil; } @Override public boolean onCommand(PlotPlayer player, String[] args) { @@ -82,9 +82,9 @@ public class Debug extends SubCommand { if (args.length > 0 && "loadedchunks".equalsIgnoreCase(args[0])) { final long start = System.currentTimeMillis(); player.sendMessage(TranslatableCaption.of("debug.fetching_loaded_chunks")); - TaskManager.runTaskAsync(() -> player.sendMessage(StaticCaption.of("Loaded chunks: " + this.regionManager.getChunkChunks(player.getLocation().getWorldName()).size() + "(" + ( - System.currentTimeMillis() - start) + "ms) using thread: " + Thread - .currentThread().getName()))); + TaskManager.runTaskAsync(() -> player.sendMessage(StaticCaption + .of("Loaded chunks: " + this.worldUtil.getChunkChunks(player.getLocation().getWorldName()).size() + "(" + (System.currentTimeMillis() + - start) + "ms) using thread: " + Thread.currentThread().getName()))); return true; } if (args.length > 0 && "uuids".equalsIgnoreCase(args[0])) { diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugRoadRegen.java b/Core/src/main/java/com/plotsquared/core/command/DebugRoadRegen.java index 2b257047f..10e8b3f3e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugRoadRegen.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugRoadRegen.java @@ -35,6 +35,7 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotManager; import net.kyori.adventure.text.minimessage.Template; +import com.plotsquared.core.queue.QueueCoordinator; import javax.annotation.Nonnull; import java.util.Arrays; @@ -91,9 +92,10 @@ public class DebugRoadRegen extends SubCommand { player.sendMessage(TranslatableCaption.of("debug.requires_unmerged")); } else { PlotManager manager = area.getPlotManager(); - manager.createRoadEast(plot); - manager.createRoadSouth(plot); - manager.createRoadSouthEast(plot); + QueueCoordinator queue = area.getQueue(); + manager.createRoadEast(plot, queue); + manager.createRoadSouth(plot, queue); + manager.createRoadSouthEast(plot, queue); player.sendMessage( TranslatableCaption.of("debugroadregen.regen_done"), Template.of("value", String.valueOf(plot.getId())) diff --git a/Core/src/main/java/com/plotsquared/core/command/Relight.java b/Core/src/main/java/com/plotsquared/core/command/Relight.java index 0488f1d14..3737902b1 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Relight.java +++ b/Core/src/main/java/com/plotsquared/core/command/Relight.java @@ -25,12 +25,8 @@ */ package com.plotsquared.core.command; -import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.queue.LocalBlockQueue; -import com.plotsquared.core.util.ChunkManager; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; @@ -50,12 +46,13 @@ public class Relight extends Command { public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { - final Plot plot = player.getCurrentPlot(); + player.sendMessage(StaticCaption.of("Not implemented.")); +/* final Plot plot = player.getCurrentPlot(); if (plot == null) { player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); return CompletableFuture.completedFuture(false); } - final LocalBlockQueue queue = plot.getArea().getQueue(false); + final QueueCoordinator queue = plot.getArea().getQueue(false); ChunkManager.chunkTask(plot, new RunnableVal() { @Override public void run(int[] value) { queue.fixChunkLighting(value[0], value[1]); @@ -63,7 +60,7 @@ public class Relight extends Command { }, () -> { plot.refreshChunks(); player.sendMessage(TranslatableCaption.of("setblock.set_block_action_finished")); - }, 5); + }, 5);*/ return CompletableFuture.completedFuture(true); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Set.java b/Core/src/main/java/com/plotsquared/core/command/Set.java index b63a8a8c1..90211a409 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Set.java +++ b/Core/src/main/java/com/plotsquared/core/command/Set.java @@ -35,7 +35,7 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotManager; -import com.plotsquared.core.queue.GlobalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.PatternUtil; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.StringMan; @@ -70,13 +70,8 @@ public class Set extends SubCommand { public static final String[] aliases = new String[] {"b", "w", "wf", "a", "h"}; private final SetCommand component; - private final WorldUtil worldUtil; - private final GlobalBlockQueue blockQueue; - @Inject public Set(@Nonnull final WorldUtil worldUtil, - @Nonnull final GlobalBlockQueue blockQueue) { - this.worldUtil = worldUtil; - this.blockQueue = blockQueue; + @Inject public Set(@Nonnull final WorldUtil worldUtil) { this.component = new SetCommand() { @Override public String getId() { @@ -158,11 +153,13 @@ public class Set extends SubCommand { BackupManager.backup(player, plot, () -> { plot.addRunning(); + QueueCoordinator queue = plotArea.getQueue(); for (Plot current : plot.getConnectedPlots()) { - current.setComponent(component, pattern); + current.setComponent(component, pattern, queue); } + queue.setCompleteTask(plot::removeRunning); + queue.enqueue(); player.sendMessage(TranslatableCaption.of("working.generating_component")); - blockQueue.addEmptyTask(plot::removeRunning); }); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/command/Template.java b/Core/src/main/java/com/plotsquared/core/command/Template.java index 5cf788f9a..1cf1e8c33 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Template.java +++ b/Core/src/main/java/com/plotsquared/core/command/Template.java @@ -41,7 +41,6 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotManager; import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.FileBytes; @@ -71,20 +70,17 @@ public class Template extends SubCommand { private final YamlConfiguration worldConfiguration; private final File worldFile; private final SetupUtils setupUtils; - private final GlobalBlockQueue globalBlockQueue; private final WorldUtil worldUtil; @Inject public Template(@Nonnull final PlotAreaManager plotAreaManager, @WorldConfig @Nonnull final YamlConfiguration worldConfiguration, @WorldFile @Nonnull final File worldFile, @Nonnull final SetupUtils setupUtils, - @Nonnull final GlobalBlockQueue globalBlockQueue, @Nonnull final WorldUtil worldUtil) { this.plotAreaManager = plotAreaManager; this.worldConfiguration = worldConfiguration; this.worldFile = worldFile; this.setupUtils = setupUtils; - this.globalBlockQueue = globalBlockQueue; this.worldUtil = worldUtil; } @@ -227,7 +223,7 @@ public class Template extends SubCommand { .worldName(world); this.setupUtils.setupWorld(builder); - this.globalBlockQueue.addEmptyTask(() -> { + TaskManager.runTask(() -> { player.sendMessage(TranslatableCaption.of("debugimportworlds.done")); player.teleport(this.worldUtil.getSpawn(world), TeleportCause.COMMAND); }); diff --git a/Core/src/main/java/com/plotsquared/core/command/Trim.java b/Core/src/main/java/com/plotsquared/core/command/Trim.java index 4cdb5d82f..0c471dc9b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Trim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Trim.java @@ -35,7 +35,7 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.expiration.ExpireManager; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.queue.GlobalBlockQueue; -import com.plotsquared.core.queue.LocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.RegionUtil; import com.plotsquared.core.util.WorldUtil; @@ -98,7 +98,7 @@ public class Trim extends SubCommand { if (ExpireManager.IMP != null) { plots.removeAll(ExpireManager.IMP.getPendingExpired()); } - result.value1 = new HashSet<>(PlotSquared.platform().getRegionManager().getChunkChunks(world)); + result.value1 = new HashSet<>(PlotSquared.platform().getWorldUtil().getChunkChunks(world)); result.value2 = new HashSet<>(); StaticCaption.of(" - MCA #: " + result.value1.size()); StaticCaption.of(" - CHUNKS: " + (result.value1.size() * 1024) + " (max)"); @@ -190,7 +190,7 @@ public class Trim extends SubCommand { } } } - final LocalBlockQueue queue = blockQueue.getNewQueue(world, false); + final QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(world)); TaskManager.getPlatformImplementation().objectTask(chunks, new RunnableVal() { @Override public void run(BlockVector2 value) { queue.regenChunk(value.getX(), value.getZ()); diff --git a/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java b/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java index 80e894322..87fb16dac 100644 --- a/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java +++ b/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java @@ -37,6 +37,7 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotInventory; import com.plotsquared.core.plot.PlotItemStack; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.InventoryUtil; import com.plotsquared.core.util.PatternUtil; @@ -70,8 +71,7 @@ public class ComponentPresetManager { private final EconHandler econHandler; private final InventoryUtil inventoryUtil; - @Inject public ComponentPresetManager(@Nullable final EconHandler econHandler, @Nonnull final - InventoryUtil inventoryUtil) { + @Inject public ComponentPresetManager(@Nullable final EconHandler econHandler, @Nonnull final InventoryUtil inventoryUtil) { this.econHandler = econHandler; this.inventoryUtil = inventoryUtil; final File file = new File(Objects.requireNonNull(PlotSquared.platform()).getDirectory(), "components.yml"); @@ -105,15 +105,13 @@ public class ComponentPresetManager { this.guiName = yamlConfiguration.getString("title", "&6Plot Components"); if (yamlConfiguration.contains("presets")) { - this.presets = yamlConfiguration.getMapList("presets").stream().map(o -> (Map) o) - .map(ComponentPreset::deserialize).collect(Collectors.toList()); + this.presets = yamlConfiguration.getMapList("presets").stream().map(o -> (Map) o).map(ComponentPreset::deserialize) + .collect(Collectors.toList()); } else { - final List defaultPreset = - Collections.singletonList(new ComponentPreset(ClassicPlotManagerComponent.FLOOR, - "##wool", 0, "", "&6D&ai&cs&ec&bo &2F&3l&do&9o&4r", + final List defaultPreset = Collections.singletonList( + new ComponentPreset(ClassicPlotManagerComponent.FLOOR, "##wool", 0, "", "&6D&ai&cs&ec&bo &2F&3l&do&9o&4r", Arrays.asList("&6Spice up your plot floor"), ItemTypes.YELLOW_WOOL)); - yamlConfiguration.set("presets", defaultPreset.stream().map(ComponentPreset::serialize) - .collect(Collectors.toList())); + yamlConfiguration.set("presets", defaultPreset.stream().map(ComponentPreset::serialize).collect(Collectors.toList())); try { yamlConfiguration.save(file); } catch (final IOException e) { @@ -148,8 +146,7 @@ public class ComponentPresetManager { final List allowedPresets = new ArrayList<>(this.presets.size()); for (final ComponentPreset componentPreset : this.presets) { - if (!componentPreset.getPermission().isEmpty() && !Permissions - .hasPermission(player, componentPreset.getPermission())) { + if (!componentPreset.getPermission().isEmpty() && !Permissions.hasPermission(player, componentPreset.getPermission())) { continue; } allowedPresets.add(componentPreset); @@ -194,11 +191,13 @@ public class ComponentPresetManager { BackupManager.backup(player, plot, () -> { plot.addRunning(); + QueueCoordinator queue = plot.getArea().getQueue(); for (Plot current : plot.getConnectedPlots()) { - current.setComponent(componentPreset.getComponent().name(), pattern); + current.setComponent(componentPreset.getComponent().name(), pattern, queue); } + queue.setCompleteTask(plot::removeRunning); + queue.enqueue(); player.sendMessage(TranslatableCaption.of("working.generating_component")); - PlotSquared.platform().getGlobalBlockQueue().addEmptyTask(plot::removeRunning); }); return false; } diff --git a/Core/src/main/java/com/plotsquared/core/configuration/caption/CaptionHolder.java b/Core/src/main/java/com/plotsquared/core/configuration/caption/CaptionHolder.java index bf6477235..42605bcd8 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/caption/CaptionHolder.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/caption/CaptionHolder.java @@ -8,7 +8,7 @@ * | | * |_| * PlotSquared plot management system for Minecraft - * Copyright (C) ${year} IntellectualSites + * Copyright (C) 2020 IntellectualSites * * 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 @@ -23,7 +23,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package com.plotsquared.core.configuration.caption; public class CaptionHolder { diff --git a/Core/src/main/java/com/plotsquared/core/configuration/caption/CaptionLoader.java b/Core/src/main/java/com/plotsquared/core/configuration/caption/CaptionLoader.java index 5e6ff6a87..a5d95296d 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/caption/CaptionLoader.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/caption/CaptionLoader.java @@ -8,7 +8,7 @@ * | | * |_| * PlotSquared plot management system for Minecraft - * Copyright (C) ${year} IntellectualSites + * Copyright (C) 2020 IntellectualSites * * 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 diff --git a/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java b/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java index 0574b2422..1b42889ca 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/AugmentedUtils.java @@ -31,10 +31,10 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.PlotManager; -import com.plotsquared.core.queue.AreaBoundDelegateLocalBlockQueue; -import com.plotsquared.core.queue.LocalBlockQueue; -import com.plotsquared.core.queue.LocationOffsetDelegateLocalBlockQueue; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.AreaBoundDelegateQueueCoordinator; +import com.plotsquared.core.queue.LocationOffsetDelegateQueueCoordinator; +import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.RegionUtil; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.block.BlockState; @@ -54,8 +54,11 @@ public class AugmentedUtils { enabled = true; } - public static boolean generate(@Nullable Object chunkObject, @Nonnull final String world, - final int chunkX, final int chunkZ, LocalBlockQueue queue) { + public static boolean generate(@Nullable Object chunkObject, + @Nonnull final String world, + final int chunkX, + final int chunkZ, + QueueCoordinator queue) { if (!enabled) { return false; } @@ -71,6 +74,7 @@ public class AugmentedUtils { if (areas.isEmpty()) { return false; } + boolean enqueue = false; boolean generationResult = false; for (final PlotArea area : areas) { // A normal plot world may not contain any clusters @@ -80,16 +84,19 @@ public class AugmentedUtils { } // This means that full vanilla generation is used // so we do not interfere - if (area.getTerrain() == PlotAreaTerrainType.ALL) { + if (area.getTerrain() == PlotAreaTerrainType.ALL || !area.contains(blockX, blockZ)) { continue; } IndependentPlotGenerator generator = area.getGenerator(); // Mask if (queue == null) { - queue = PlotSquared.platform().getGlobalBlockQueue().getNewQueue(world, false); - queue.setChunkObject(chunkObject); + enqueue = true; + queue = PlotSquared.platform().getGlobalBlockQueue().getNewQueue(PlotSquared.platform().getWorldUtil().getWeWorld(world)); + if (chunkObject != null) { + queue.setChunkObject(chunkObject); + } } - LocalBlockQueue primaryMask; + QueueCoordinator primaryMask; // coordinates int relativeBottomX; int relativeBottomZ; @@ -102,14 +109,13 @@ public class AugmentedUtils { relativeTopX = Math.min(15, area.getRegion().getMaximumPoint().getX() - blockX); relativeTopZ = Math.min(15, area.getRegion().getMaximumPoint().getZ() - blockZ); - primaryMask = new AreaBoundDelegateLocalBlockQueue(area, queue); + primaryMask = new AreaBoundDelegateQueueCoordinator(area, queue); } else { relativeBottomX = relativeBottomZ = 0; relativeTopX = relativeTopZ = 15; primaryMask = queue; } - - LocalBlockQueue secondaryMask; + QueueCoordinator secondaryMask; BlockState air = BlockTypes.AIR.getDefaultState(); if (area.getTerrain() == PlotAreaTerrainType.ROAD) { PlotManager manager = area.getPlotManager(); @@ -133,8 +139,7 @@ public class AugmentedUtils { continue; } generationResult = true; - secondaryMask = new LocationOffsetDelegateLocalBlockQueue(canPlace, blockX, blockZ, - primaryMask); + secondaryMask = new LocationOffsetDelegateQueueCoordinator(canPlace, blockX, blockZ, primaryMask); } else { secondaryMask = primaryMask; for (int x = relativeBottomX; x <= relativeTopX; x++) { @@ -146,20 +151,22 @@ public class AugmentedUtils { } generationResult = true; } - primaryMask.setChunkObject(chunkObject); - primaryMask.setForceSync(true); - secondaryMask.setChunkObject(chunkObject); - secondaryMask.setForceSync(true); + if (chunkObject != null) { + primaryMask.setChunkObject(chunkObject); + } + if (chunkObject != null) { + secondaryMask.setChunkObject(chunkObject); + } - ScopedLocalBlockQueue scoped = - new ScopedLocalBlockQueue(secondaryMask, Location.at(world, blockX, 0, blockZ), - Location.at(world, blockX + 15, 255, blockZ + 15)); + ScopedQueueCoordinator scoped = + new ScopedQueueCoordinator(secondaryMask, Location.at(world, blockX, 0, blockZ), Location.at(world, blockX + 15, 255, blockZ + 15)); generator.generateChunk(scoped, area); generator.populateChunk(scoped, area); + scoped.setForceSync(true); + scoped.enqueue(); } - if (queue != null) { - queue.setForceSync(true); - queue.flush(); + if (enqueue) { + queue.enqueue(); } return generationResult; } diff --git a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java index 787376ea3..f4849dd4e 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java @@ -25,7 +25,6 @@ */ package com.plotsquared.core.generator; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.location.Direction; import com.plotsquared.core.location.Location; @@ -33,15 +32,17 @@ import com.plotsquared.core.plot.BlockBucket; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.queue.LocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.BlockUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.RegionManager; +import com.plotsquared.core.util.task.TaskManager; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.List; import java.util.Optional; @@ -53,98 +54,140 @@ public class ClassicPlotManager extends SquarePlotManager { private final ClassicPlotWorld classicPlotWorld; private final RegionManager regionManager; - public ClassicPlotManager(@Nonnull final ClassicPlotWorld classicPlotWorld, - @Nonnull final RegionManager regionManager) { + public ClassicPlotManager(@Nonnull final ClassicPlotWorld classicPlotWorld, @Nonnull final RegionManager regionManager) { super(classicPlotWorld, regionManager); this.classicPlotWorld = classicPlotWorld; this.regionManager = regionManager; } - @Override public boolean setComponent(PlotId plotId, String component, Pattern blocks) { - final Optional componentOptional = - ClassicPlotManagerComponent.fromString(component); + @Override public boolean setComponent(@Nonnull PlotId plotId, + @Nonnull String component, + @Nonnull Pattern blocks, + @Nullable QueueCoordinator queue) { + final Optional componentOptional = ClassicPlotManagerComponent.fromString(component); if (componentOptional.isPresent()) { switch (componentOptional.get()) { case FLOOR: - return setFloor(plotId, blocks); + return setFloor(plotId, blocks, queue); case WALL: - return setWallFilling(plotId, blocks); + return setWallFilling(plotId, blocks, queue); case AIR: - return setAir(plotId, blocks); + return setAir(plotId, blocks, queue); case MAIN: - return setMain(plotId, blocks); + return setMain(plotId, blocks, queue); case MIDDLE: - return setMiddle(plotId, blocks); + return setMiddle(plotId, blocks, queue); case OUTLINE: - return setOutline(plotId, blocks); + return setOutline(plotId, blocks, queue); case BORDER: - return setWall(plotId, blocks); + return setWall(plotId, blocks, queue); case ALL: - return setAll(plotId, blocks); + return setAll(plotId, blocks, queue); } } return false; } - @Override public boolean unClaimPlot(Plot plot, Runnable whenDone) { - setWallFilling(plot.getId(), classicPlotWorld.WALL_FILLING.toPattern()); - if (!classicPlotWorld.WALL_BLOCK.isAir() || !classicPlotWorld.WALL_BLOCK - .equals(classicPlotWorld.CLAIMED_WALL_BLOCK)) { - setWall(plot.getId(), classicPlotWorld.WALL_BLOCK.toPattern()); + @Override public boolean unClaimPlot(@Nonnull Plot plot, @Nullable Runnable whenDone, @Nullable QueueCoordinator queue) { + setWallFilling(plot.getId(), classicPlotWorld.WALL_FILLING.toPattern(), queue); + if (classicPlotWorld.PLACE_TOP_BLOCK && (!classicPlotWorld.WALL_BLOCK.isAir() || !classicPlotWorld.WALL_BLOCK + .equals(classicPlotWorld.CLAIMED_WALL_BLOCK))) { + setWall(plot.getId(), classicPlotWorld.WALL_BLOCK.toPattern(), queue); } - return PlotSquared.platform().getGlobalBlockQueue().addEmptyTask(whenDone); + TaskManager.runTask(whenDone); + return true; } - public boolean setFloor(PlotId plotId, Pattern blocks) { + /** + * Set the plot floor + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public boolean setFloor(@Nonnull PlotId plotId, @Nonnull Pattern blocks, @Nullable QueueCoordinator queue) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - if (plot.isBasePlot()) { - return this.regionManager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, - classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.PLOT_HEIGHT); + if (plot != null && plot.isBasePlot()) { + return this.regionManager + .setCuboids(classicPlotWorld, plot.getRegions(), blocks, classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.PLOT_HEIGHT, queue); } return false; } - public boolean setAll(PlotId plotId, Pattern blocks) { + /** + * Sets the plot main, floor and air areas. + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public boolean setAll(@Nonnull PlotId plotId, @Nonnull Pattern blocks, @Nullable QueueCoordinator queue) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - if (plot.isBasePlot()) { - return this.regionManager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, 1, getWorldHeight()); + if (plot != null && plot.isBasePlot()) { + return this.regionManager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, 1, getWorldHeight(), queue); } return false; } - public boolean setAir(PlotId plotId, Pattern blocks) { + /** + * Sets the plot air region. + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public boolean setAir(@Nonnull PlotId plotId, @Nonnull Pattern blocks, @Nullable QueueCoordinator queue) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - if (plot.isBasePlot()) { - return this.regionManager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, - classicPlotWorld.PLOT_HEIGHT + 1, getWorldHeight()); + if (plot != null && plot.isBasePlot()) { + return this.regionManager + .setCuboids(classicPlotWorld, plot.getRegions(), blocks, classicPlotWorld.PLOT_HEIGHT + 1, getWorldHeight(), queue); } return false; } - public boolean setMain(PlotId plotId, Pattern blocks) { + /** + * Sets the plot main blocks. + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public boolean setMain(@Nonnull PlotId plotId, @Nonnull Pattern blocks, @Nullable QueueCoordinator queue) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - if (plot.isBasePlot()) { - return this.regionManager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, 1, - classicPlotWorld.PLOT_HEIGHT - 1); + if (plot == null || plot.isBasePlot()) { + return this.regionManager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, 1, classicPlotWorld.PLOT_HEIGHT - 1, queue); } return false; } - public boolean setMiddle(PlotId plotId, Pattern blocks) { + /** + * Set the middle plot block to a Pattern + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public boolean setMiddle(@Nonnull PlotId plotId, @Nonnull Pattern blocks, @Nullable QueueCoordinator queue) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - if (!plot.isBasePlot()) { + if (plot == null || !plot.isBasePlot()) { return false; } Location[] corners = plot.getCorners(); - LocalBlockQueue queue = classicPlotWorld.getQueue(false); + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } int x = MathMan.average(corners[0].getX(), corners[1].getX()); int z = MathMan.average(corners[0].getZ(), corners[1].getZ()); queue.setBlock(x, classicPlotWorld.PLOT_HEIGHT, z, blocks); - return queue.enqueue(); + return !enqueue || queue.enqueue(); } - public boolean setOutline(PlotId plotId, Pattern blocks) { + /** + * Set a plot's outline + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public boolean setOutline(@Nonnull PlotId plotId, @Nonnull Pattern blocks, @Nullable QueueCoordinator queue) { if (classicPlotWorld.ROAD_WIDTH == 0) { return false; } @@ -155,9 +198,18 @@ public class ClassicPlotManager extends SquarePlotManager { return true; } Plot plot = classicPlotWorld.getPlotAbs(plotId); + if (plot == null) { + return false; + } Location bottom = plot.getBottomAbs(); Location top = plot.getExtendedTopAbs(); - LocalBlockQueue queue = classicPlotWorld.getQueue(false); + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } + int maxY = classicPlotWorld.getPlotManager().getWorldHeight(); if (!plot.getMerged(Direction.NORTH)) { int z = bottom.getZ(); @@ -194,19 +246,21 @@ public class ClassicPlotManager extends SquarePlotManager { } if (plot.isBasePlot()) { for (CuboidRegion region : plot.getRegions()) { - Location pos1 = - Location.at(classicPlotWorld.getWorldName(), region.getMinimumPoint().getX(), - maxY, region.getMinimumPoint().getZ()); - Location pos2 = - Location.at(classicPlotWorld.getWorldName(), region.getMaximumPoint().getX(), - maxY, region.getMaximumPoint().getZ()); + Location pos1 = Location.at(classicPlotWorld.getWorldName(), region.getMinimumPoint().getX(), maxY, region.getMinimumPoint().getZ()); + Location pos2 = Location.at(classicPlotWorld.getWorldName(), region.getMaximumPoint().getX(), maxY, region.getMaximumPoint().getZ()); queue.setCuboid(pos1, pos2, blocks); } } - return queue.enqueue(); + return !enqueue || queue.enqueue(); } - public boolean setWallFilling(PlotId plotId, Pattern blocks) { + /** + * Set the wall filling for a plot + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public boolean setWallFilling(@Nonnull PlotId plotId, @Nonnull Pattern blocks, @Nullable QueueCoordinator queue) { if (classicPlotWorld.ROAD_WIDTH == 0) { return false; } @@ -217,11 +271,18 @@ public class ClassicPlotManager extends SquarePlotManager { return true; } Plot plot = classicPlotWorld.getPlotAbs(plotId); - Location bot = plot.getExtendedBottomAbs() - .subtract(plot.getMerged(Direction.WEST) ? 0 : 1, 0, - plot.getMerged(Direction.NORTH) ? 0 : 1); + if (plot == null) { + return false; + } + Location bot = plot.getExtendedBottomAbs().subtract(plot.getMerged(Direction.WEST) ? 0 : 1, 0, plot.getMerged(Direction.NORTH) ? 0 : 1); Location top = plot.getExtendedTopAbs().add(1, 0, 1); - LocalBlockQueue queue = classicPlotWorld.getQueue(false); + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } + if (!plot.getMerged(Direction.NORTH)) { int z = bot.getZ(); for (int x = bot.getX(); x < top.getX(); x++) { @@ -240,8 +301,7 @@ public class ClassicPlotManager extends SquarePlotManager { } if (!plot.getMerged(Direction.SOUTH)) { int z = top.getZ(); - for (int x = bot.getX(); - x < top.getX() + (plot.getMerged(Direction.EAST) ? 0 : 1); x++) { + for (int x = bot.getX(); x < top.getX() + (plot.getMerged(Direction.EAST) ? 0 : 1); x++) { for (int y = 1; y <= classicPlotWorld.WALL_HEIGHT; y++) { queue.setBlock(x, y, z, blocks); } @@ -249,17 +309,22 @@ public class ClassicPlotManager extends SquarePlotManager { } if (!plot.getMerged(Direction.EAST)) { int x = top.getX(); - for (int z = bot.getZ(); - z < top.getZ() + (plot.getMerged(Direction.SOUTH) ? 0 : 1); z++) { + for (int z = bot.getZ(); z < top.getZ() + (plot.getMerged(Direction.SOUTH) ? 0 : 1); z++) { for (int y = 1; y <= classicPlotWorld.WALL_HEIGHT; y++) { queue.setBlock(x, y, z, blocks); } } } - return queue.enqueue(); + return !enqueue || queue.enqueue(); } - public boolean setWall(PlotId plotId, Pattern blocks) { + /** + * Set a plot's wall top block only + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public boolean setWall(@Nonnull PlotId plotId, @Nonnull Pattern blocks, @Nullable QueueCoordinator queue) { if (classicPlotWorld.ROAD_WIDTH == 0) { return false; } @@ -270,11 +335,18 @@ public class ClassicPlotManager extends SquarePlotManager { return true; } Plot plot = classicPlotWorld.getPlotAbs(plotId); - Location bot = plot.getExtendedBottomAbs() - .subtract(plot.getMerged(Direction.WEST) ? 0 : 1, 0, - plot.getMerged(Direction.NORTH) ? 0 : 1); + if (plot == null) { + return false; + } + Location bot = plot.getExtendedBottomAbs().subtract(plot.getMerged(Direction.WEST) ? 0 : 1, 0, plot.getMerged(Direction.NORTH) ? 0 : 1); Location top = plot.getExtendedTopAbs().add(1, 0, 1); - LocalBlockQueue queue = classicPlotWorld.getQueue(false); + + boolean enqueue = false; + if (queue == null) { + enqueue = true; + queue = classicPlotWorld.getQueue(); + } + int y = classicPlotWorld.WALL_HEIGHT + 1; if (!plot.getMerged(Direction.NORTH)) { int z = bot.getZ(); @@ -290,237 +362,239 @@ public class ClassicPlotManager extends SquarePlotManager { } if (!plot.getMerged(Direction.SOUTH)) { int z = top.getZ(); - for (int x = bot.getX(); - x < top.getX() + (plot.getMerged(Direction.EAST) ? 0 : 1); x++) { + for (int x = bot.getX(); x < top.getX() + (plot.getMerged(Direction.EAST) ? 0 : 1); x++) { queue.setBlock(x, y, z, blocks); } } if (!plot.getMerged(Direction.EAST)) { int x = top.getX(); - for (int z = bot.getZ(); - z < top.getZ() + (plot.getMerged(Direction.SOUTH) ? 0 : 1); z++) { + for (int z = bot.getZ(); z < top.getZ() + (plot.getMerged(Direction.SOUTH) ? 0 : 1); z++) { queue.setBlock(x, y, z, blocks); } } - return queue.enqueue(); + return !enqueue || queue.enqueue(); } - /** - * PLOT MERGING. - */ - @Override public boolean createRoadEast(Plot plot) { + @Override public boolean createRoadEast(@Nonnull Plot plot, @Nullable QueueCoordinator queue) { Location pos1 = getPlotBottomLocAbs(plot.getId()); Location pos2 = getPlotTopLocAbs(plot.getId()); int sx = pos2.getX() + 1; int ex = sx + classicPlotWorld.ROAD_WIDTH - 1; int sz = pos1.getZ() - 2; int ez = pos2.getZ() + 2; - LocalBlockQueue queue = classicPlotWorld.getQueue(false); + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } + int maxY = getWorldHeight(); - queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, - Math.min(classicPlotWorld.WALL_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex, maxY, ez - 1), - BlockTypes.AIR.getDefaultState()); - queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, 0, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex, 0, ez - 1), + queue.setCuboid( + Location.at(classicPlotWorld.getWorldName(), sx, Math.min(classicPlotWorld.WALL_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex, maxY, ez - 1), BlockTypes.AIR.getDefaultState()); + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, 0, sz + 1), Location.at(classicPlotWorld.getWorldName(), ex, 0, ez - 1), BlockUtil.get((short) 7, (byte) 0)); queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT, ez - 1), - classicPlotWorld.WALL_FILLING.toPattern()); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT + 1, - sz + 1), - Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT + 1, - ez - 1), classicPlotWorld.WALL_BLOCK.toPattern()); + Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT, ez - 1), classicPlotWorld.WALL_FILLING.toPattern()); + + if (classicPlotWorld.PLACE_TOP_BLOCK) { + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT + 1, sz + 1), + Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.WALL_HEIGHT + 1, ez - 1), classicPlotWorld.WALL_BLOCK.toPattern()); + } queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), ex, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT, ez - 1), - classicPlotWorld.WALL_FILLING.toPattern()); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT + 1, - sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT + 1, - ez - 1), classicPlotWorld.WALL_BLOCK.toPattern()); + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT, ez - 1), classicPlotWorld.WALL_FILLING.toPattern()); + if (classicPlotWorld.PLACE_TOP_BLOCK) { + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT + 1, sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.WALL_HEIGHT + 1, ez - 1), classicPlotWorld.WALL_BLOCK.toPattern()); + } queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, - ez - 1), classicPlotWorld.ROAD_BLOCK.toPattern()); - return queue.enqueue(); + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, ez - 1), classicPlotWorld.ROAD_BLOCK.toPattern()); + return !enqueue || queue.enqueue(); } - @Override public boolean createRoadSouth(Plot plot) { + @Override public boolean createRoadSouth(@Nonnull Plot plot, @Nullable QueueCoordinator queue) { Location pos1 = getPlotBottomLocAbs(plot.getId()); Location pos2 = getPlotTopLocAbs(plot.getId()); int sz = pos2.getZ() + 1; int ez = sz + classicPlotWorld.ROAD_WIDTH - 1; int sx = pos1.getX() - 2; int ex = pos2.getX() + 2; - LocalBlockQueue queue = classicPlotWorld.getQueue(false); - queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, - Math.min(classicPlotWorld.WALL_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), - Location.at(classicPlotWorld.getWorldName(), ex - 1, - classicPlotWorld.getPlotManager().getWorldHeight(), ez), + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } + + queue.setCuboid( + Location.at(classicPlotWorld.getWorldName(), sx + 1, Math.min(classicPlotWorld.WALL_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.getPlotManager().getWorldHeight(), ez), BlockTypes.AIR.getDefaultState()); - queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 0, sz), - Location.at(classicPlotWorld.getWorldName(), ex - 1, 0, ez), + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 0, sz), Location.at(classicPlotWorld.getWorldName(), ex - 1, 0, ez), BlockUtil.get((short) 7, (byte) 0)); queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT, sz), - classicPlotWorld.WALL_FILLING.toPattern()); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.WALL_HEIGHT + 1, - sz), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT + 1, - sz), classicPlotWorld.WALL_BLOCK.toPattern()); + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT, sz), classicPlotWorld.WALL_FILLING.toPattern()); + + if (classicPlotWorld.PLACE_TOP_BLOCK) { + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.WALL_HEIGHT + 1, sz), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT + 1, sz), classicPlotWorld.WALL_BLOCK.toPattern()); + } queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, ez), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT, ez), - classicPlotWorld.WALL_FILLING.toPattern()); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.WALL_HEIGHT + 1, - ez), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT + 1, - ez), classicPlotWorld.WALL_BLOCK.toPattern()); + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT, ez), classicPlotWorld.WALL_FILLING.toPattern()); + if (classicPlotWorld.PLACE_TOP_BLOCK) { + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.WALL_HEIGHT + 1, ez), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.WALL_HEIGHT + 1, ez), classicPlotWorld.WALL_BLOCK.toPattern()); + } queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, - ez - 1), classicPlotWorld.ROAD_BLOCK.toPattern()); - return queue.enqueue(); + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, ez - 1), classicPlotWorld.ROAD_BLOCK.toPattern()); + return !enqueue || queue.enqueue(); } - @Override public boolean createRoadSouthEast(Plot plot) { + + @Override public boolean createRoadSouthEast(@Nonnull Plot plot, @Nullable QueueCoordinator queue) { Location pos2 = getPlotTopLocAbs(plot.getId()); int sx = pos2.getX() + 1; int ex = sx + classicPlotWorld.ROAD_WIDTH - 1; int sz = pos2.getZ() + 1; int ez = sz + classicPlotWorld.ROAD_WIDTH - 1; - LocalBlockQueue queue = classicPlotWorld.getQueue(false); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.ROAD_HEIGHT + 1, - sz + 1), Location.at(classicPlotWorld.getWorldName(), ex - 1, - classicPlotWorld.getPlotManager().getWorldHeight(), ez - 1), + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } + + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.ROAD_HEIGHT + 1, sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.getPlotManager().getWorldHeight(), ez - 1), BlockTypes.AIR.getDefaultState()); queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 0, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex - 1, 0, ez - 1), - BlockUtil.get((short) 7, (byte) 0)); + Location.at(classicPlotWorld.getWorldName(), ex - 1, 0, ez - 1), BlockUtil.get((short) 7, (byte) 0)); queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, - ez - 1), classicPlotWorld.ROAD_BLOCK.toPattern()); - return queue.enqueue(); + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.ROAD_HEIGHT, ez - 1), classicPlotWorld.ROAD_BLOCK.toPattern()); + return !enqueue || queue.enqueue(); } - @Override public boolean removeRoadEast(Plot plot) { + @Override public boolean removeRoadEast(@Nonnull Plot plot, @Nullable QueueCoordinator queue) { Location pos1 = getPlotBottomLocAbs(plot.getId()); Location pos2 = getPlotTopLocAbs(plot.getId()); int sx = pos2.getX() + 1; int ex = sx + classicPlotWorld.ROAD_WIDTH - 1; int sz = pos1.getZ() - 1; int ez = pos2.getZ() + 1; - LocalBlockQueue queue = classicPlotWorld.getQueue(false); - queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, - Math.min(classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), - Location.at(classicPlotWorld.getWorldName(), ex, - classicPlotWorld.getPlotManager().getWorldHeight(), ez), - BlockTypes.AIR.getDefaultState()); + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } + + queue + .setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, Math.min(classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getPlotManager().getWorldHeight(), ez), + BlockTypes.AIR.getDefaultState()); queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, 1, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT - 1, - ez - 1), classicPlotWorld.MAIN_BLOCK.toPattern()); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.PLOT_HEIGHT, sz + 1), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT, ez - 1), - classicPlotWorld.TOP_BLOCK.toPattern()); - return queue.enqueue(); + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT - 1, ez - 1), classicPlotWorld.MAIN_BLOCK.toPattern()); + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.PLOT_HEIGHT, sz + 1), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT, ez - 1), classicPlotWorld.TOP_BLOCK.toPattern()); + + return !enqueue || queue.enqueue(); } - @Override public boolean removeRoadSouth(Plot plot) { + @Override public boolean removeRoadSouth(@Nonnull Plot plot, @Nullable QueueCoordinator queue) { Location pos1 = getPlotBottomLocAbs(plot.getId()); Location pos2 = getPlotTopLocAbs(plot.getId()); int sz = pos2.getZ() + 1; int ez = sz + classicPlotWorld.ROAD_WIDTH - 1; int sx = pos1.getX() - 1; int ex = pos2.getX() + 1; - LocalBlockQueue queue = classicPlotWorld.getQueue(false); - queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, - Math.min(classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), - Location.at(classicPlotWorld.getWorldName(), ex, - classicPlotWorld.getPlotManager().getWorldHeight(), ez), - BlockTypes.AIR.getDefaultState()); + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } + + queue + .setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, Math.min(classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getPlotManager().getWorldHeight(), ez), + BlockTypes.AIR.getDefaultState()); queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, 1, sz), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.PLOT_HEIGHT - 1, - ez), classicPlotWorld.MAIN_BLOCK.toPattern()); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.PLOT_HEIGHT, sz), - Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.PLOT_HEIGHT, ez), - classicPlotWorld.TOP_BLOCK.toPattern()); - return queue.enqueue(); + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.PLOT_HEIGHT - 1, ez), classicPlotWorld.MAIN_BLOCK.toPattern()); + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx + 1, classicPlotWorld.PLOT_HEIGHT, sz), + Location.at(classicPlotWorld.getWorldName(), ex - 1, classicPlotWorld.PLOT_HEIGHT, ez), classicPlotWorld.TOP_BLOCK.toPattern()); + + return !enqueue || queue.enqueue(); } - @Override public boolean removeRoadSouthEast(Plot plot) { + @Override public boolean removeRoadSouthEast(@Nonnull Plot plot, @Nullable QueueCoordinator queue) { Location location = getPlotTopLocAbs(plot.getId()); int sx = location.getX() + 1; int ex = sx + classicPlotWorld.ROAD_WIDTH - 1; int sz = location.getZ() + 1; int ez = sz + classicPlotWorld.ROAD_WIDTH - 1; - LocalBlockQueue queue = classicPlotWorld.getQueue(false); - queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, - Math.min(classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), - Location.at(classicPlotWorld.getWorldName(), ex, - classicPlotWorld.getPlotManager().getWorldHeight(), ez), + + boolean enqueue = false; + if (queue == null) { + queue = classicPlotWorld.getQueue(); + enqueue = true; + } + + queue + .setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, Math.min(classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.getPlotManager().getWorldHeight(), ez), BlockTypes.AIR.getDefaultState()); queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, 1, sz), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT - 1, ez), - classicPlotWorld.MAIN_BLOCK.toPattern()); - queue.setCuboid( - Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.PLOT_HEIGHT, sz), - Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT, ez), - classicPlotWorld.TOP_BLOCK.toPattern()); - return queue.enqueue(); + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT - 1, ez), classicPlotWorld.MAIN_BLOCK.toPattern()); + queue.setCuboid(Location.at(classicPlotWorld.getWorldName(), sx, classicPlotWorld.PLOT_HEIGHT, sz), + Location.at(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT, ez), classicPlotWorld.TOP_BLOCK.toPattern()); + + return !enqueue || queue.enqueue(); } - /** - * Finishing off plot merging by adding in the walls surrounding the plot (OPTIONAL)(UNFINISHED). - * - * @return false if part of the merge failed, otherwise true if successful. - */ - @Override public boolean finishPlotMerge(List plotIds) { + @Override public boolean finishPlotMerge(@Nonnull List plotIds, @Nullable QueueCoordinator queue) { final BlockBucket claim = classicPlotWorld.CLAIMED_WALL_BLOCK; - if (!claim.isAir() || !claim.equals(classicPlotWorld.WALL_BLOCK)) { + if (classicPlotWorld.PLACE_TOP_BLOCK && (!claim.isAir() || !claim.equals(classicPlotWorld.WALL_BLOCK))) { for (PlotId plotId : plotIds) { - setWall(plotId, claim.toPattern()); + setWall(plotId, claim.toPattern(), queue); } } if (Settings.General.MERGE_REPLACE_WALL) { final BlockBucket wallBlock = classicPlotWorld.WALL_FILLING; for (PlotId id : plotIds) { - setWallFilling(id, wallBlock.toPattern()); + setWallFilling(id, wallBlock.toPattern(), queue); } } return true; } - @Override public boolean finishPlotUnlink(List plotIds) { + @Override public boolean finishPlotUnlink(@Nonnull List plotIds, @Nullable QueueCoordinator queue) { final BlockBucket claim = classicPlotWorld.CLAIMED_WALL_BLOCK; - if (!claim.isAir() || !claim.equals(classicPlotWorld.WALL_BLOCK)) { + if (classicPlotWorld.PLACE_TOP_BLOCK && (!claim.isAir() || !claim.equals(classicPlotWorld.WALL_BLOCK))) { for (PlotId id : plotIds) { - setWall(id, claim.toPattern()); + setWall(id, claim.toPattern(), queue); } } return true; // return false if unlink has been denied } - @Override public boolean startPlotMerge(List plotIds) { + @Override public boolean startPlotMerge(@Nonnull List plotIds, @Nullable QueueCoordinator queue) { return true; } - @Override public boolean startPlotUnlink(List plotIds) { + @Override public boolean startPlotUnlink(@Nonnull List plotIds, @Nullable QueueCoordinator queue) { return true; } - @Override public boolean claimPlot(Plot plot) { + @Override public boolean claimPlot(@Nonnull Plot plot, @Nullable QueueCoordinator queue) { final BlockBucket claim = classicPlotWorld.CLAIMED_WALL_BLOCK; - if (!claim.isAir() || !claim.equals(classicPlotWorld.WALL_BLOCK)) { - return setWall(plot.getId(), claim.toPattern()); + if (classicPlotWorld.PLACE_TOP_BLOCK && (!claim.isAir() || !claim.equals(classicPlotWorld.WALL_BLOCK))) { + return setWall(plot.getId(), claim.toPattern(), queue); } return true; } - @Override public String[] getPlotComponents(PlotId plotId) { + @Override public String[] getPlotComponents(@Nonnull PlotId plotId) { return ClassicPlotManagerComponent.stringValues(); } @@ -530,11 +604,10 @@ public class ClassicPlotManager extends SquarePlotManager { * @param plot The plot * @return The location where a sign should be */ - @Override public Location getSignLoc(Plot plot) { + @Override public Location getSignLoc(@Nonnull Plot plot) { plot = plot.getBasePlot(false); final Location bot = plot.getBottomAbs(); - return Location.at(classicPlotWorld.getWorldName(), bot.getX() - 1, - classicPlotWorld.ROAD_HEIGHT + 1, bot.getZ() - 2); + return Location.at(classicPlotWorld.getWorldName(), bot.getX() - 1, classicPlotWorld.ROAD_HEIGHT + 1, bot.getZ() - 2); } } diff --git a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotWorld.java index ed6789cbb..5f4dd1f3c 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotWorld.java @@ -58,6 +58,7 @@ public abstract class ClassicPlotWorld extends SquarePlotWorld { public BlockBucket ROAD_BLOCK = new BlockBucket(BlockTypes.QUARTZ_BLOCK); // BlockUtil.get((short) 155, (byte) 0); public boolean PLOT_BEDROCK = true; + public boolean PLACE_TOP_BLOCK = true; public ClassicPlotWorld(@Nonnull final String worldName, @Nullable final String id, @@ -91,6 +92,8 @@ public abstract class ClassicPlotWorld extends SquarePlotWorld { ConfigurationUtil.BLOCK_BUCKET), new ConfigurationNode("wall.block_claimed", this.CLAIMED_WALL_BLOCK, "Wall block (claimed)", ConfigurationUtil.BLOCK_BUCKET), + new ConfigurationNode("wall.place_top_block", this.PLACE_TOP_BLOCK, + "Place or not the top block", ConfigurationUtil.BOOLEAN), new ConfigurationNode("road.width", this.ROAD_WIDTH, "Road width", ConfigurationUtil.INTEGER), new ConfigurationNode("road.height", this.ROAD_HEIGHT, "Road height", @@ -121,5 +124,6 @@ public abstract class ClassicPlotWorld extends SquarePlotWorld { this.WALL_FILLING = new BlockBucket(config.getString("wall.filling")); this.WALL_HEIGHT = Math.min(254, config.getInt("wall.height")); this.CLAIMED_WALL_BLOCK = new BlockBucket(config.getString("wall.block_claimed")); + this.PLACE_TOP_BLOCK = config.getBoolean("wall.place_top_block"); } } diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java b/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java index e29d38bd1..2eeb89e1a 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridGen.java @@ -33,7 +33,7 @@ import com.plotsquared.core.inject.factory.HybridPlotWorldFactory; import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.MathMan; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; @@ -53,7 +53,7 @@ public class HybridGen extends IndependentPlotGenerator { return PlotSquared.platform().getPluginName(); } - private void placeSchem(HybridPlotWorld world, ScopedLocalBlockQueue result, short relativeX, + private void placeSchem(HybridPlotWorld world, ScopedQueueCoordinator result, short relativeX, short relativeZ, int x, int z, boolean isRoad) { int minY; // Math.min(world.PLOT_HEIGHT, world.ROAD_HEIGHT); if ((isRoad && Settings.Schematics.PASTE_ROAD_ON_TOP) || (!isRoad @@ -77,7 +77,7 @@ public class HybridGen extends IndependentPlotGenerator { } @Override - public void generateChunk(@Nonnull ScopedLocalBlockQueue result, @Nonnull PlotArea settings) { + public void generateChunk(@Nonnull ScopedQueueCoordinator result, @Nonnull PlotArea settings) { Preconditions.checkNotNull(result, "result cannot be null"); Preconditions.checkNotNull(settings, "settings cannot be null"); @@ -181,8 +181,10 @@ public class HybridGen extends IndependentPlotGenerator { result.setBlock(x, y, z, hybridPlotWorld.WALL_FILLING.toPattern()); } if (!hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) { - result.setBlock(x, hybridPlotWorld.WALL_HEIGHT + 1, z, - hybridPlotWorld.WALL_BLOCK.toPattern()); + if (hybridPlotWorld.PLACE_TOP_BLOCK) { + result.setBlock(x, hybridPlotWorld.WALL_HEIGHT + 1, z, + hybridPlotWorld.WALL_BLOCK.toPattern()); + } } else { placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true); @@ -206,8 +208,10 @@ public class HybridGen extends IndependentPlotGenerator { result.setBlock(x, y, z, hybridPlotWorld.WALL_FILLING.toPattern()); } if (!hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) { - result.setBlock(x, hybridPlotWorld.WALL_HEIGHT + 1, z, - hybridPlotWorld.WALL_BLOCK.toPattern()); + if (hybridPlotWorld.PLACE_TOP_BLOCK) { + result.setBlock(x, hybridPlotWorld.WALL_HEIGHT + 1, z, + hybridPlotWorld.WALL_BLOCK.toPattern()); + } } else { placeSchem(hybridPlotWorld, result, relativeX[x], relativeZ[z], x, z, true); diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotManager.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotManager.java index b4eaed95b..13e941d2f 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotManager.java @@ -34,21 +34,22 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.queue.LocalBlockQueue; -import com.plotsquared.core.util.ChunkManager; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.FileBytes; import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.task.RunnableVal; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; +import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -62,34 +63,24 @@ public class HybridPlotManager extends ClassicPlotManager { private final HybridPlotWorld hybridPlotWorld; private final RegionManager regionManager; - public HybridPlotManager(@Nonnull final HybridPlotWorld hybridPlotWorld, - @Nonnull final RegionManager regionManager) { + public HybridPlotManager(@Nonnull final HybridPlotWorld hybridPlotWorld, @Nonnull final RegionManager regionManager) { super(hybridPlotWorld, regionManager); this.hybridPlotWorld = hybridPlotWorld; this.regionManager = regionManager; } @Override public void exportTemplate() throws IOException { - HashSet files = Sets.newHashSet( - new FileBytes(Settings.Paths.TEMPLATES + "/tmp-data.yml", - Template.getBytes(hybridPlotWorld))); - String dir = - "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld - .getWorldName() + File.separator; + HashSet files = Sets.newHashSet(new FileBytes(Settings.Paths.TEMPLATES + "/tmp-data.yml", Template.getBytes(hybridPlotWorld))); + String dir = "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator; try { - File sideRoad = - FileUtils.getFile(PlotSquared.platform().getDirectory(), dir + "sideroad.schem"); - String newDir = "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator - + "__TEMP_DIR__" + File.separator; + File sideRoad = FileUtils.getFile(PlotSquared.platform().getDirectory(), dir + "sideroad.schem"); + String newDir = "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + "__TEMP_DIR__" + File.separator; if (sideRoad.exists()) { - files.add(new FileBytes(newDir + "sideroad.schem", - Files.readAllBytes(sideRoad.toPath()))); + files.add(new FileBytes(newDir + "sideroad.schem", Files.readAllBytes(sideRoad.toPath()))); } - File intersection = - FileUtils.getFile(PlotSquared.platform().getDirectory(), dir + "intersection.schem"); + File intersection = FileUtils.getFile(PlotSquared.platform().getDirectory(), dir + "intersection.schem"); if (intersection.exists()) { - files.add(new FileBytes(newDir + "intersection.schem", - Files.readAllBytes(intersection.toPath()))); + files.add(new FileBytes(newDir + "intersection.schem", Files.readAllBytes(intersection.toPath()))); } File plot = FileUtils.getFile(PlotSquared.platform().getDirectory(), dir + "plot.schem"); if (plot.exists()) { @@ -101,42 +92,39 @@ public class HybridPlotManager extends ClassicPlotManager { Template.zipAll(hybridPlotWorld.getWorldName(), files); } - @Override public boolean createRoadEast(Plot plot) { - super.createRoadEast(plot); + @Override public boolean createRoadEast(@Nonnull final Plot plot, @Nullable QueueCoordinator queue) { + super.createRoadEast(plot, queue); PlotId id = plot.getId(); PlotId id2 = PlotId.of(id.getX() + 1, id.getY()); Location bot = getPlotBottomLocAbs(id2); Location top = getPlotTopLocAbs(id); Location pos1 = Location.at(hybridPlotWorld.getWorldName(), top.getX() + 1, 0, bot.getZ() - 1); - Location pos2 = Location.at(hybridPlotWorld.getWorldName(), bot.getX(), - Math.min(getWorldHeight(), 255), top.getZ() + 1); + Location pos2 = Location.at(hybridPlotWorld.getWorldName(), bot.getX(), Math.min(getWorldHeight(), 255), top.getZ() + 1); this.resetBiome(hybridPlotWorld, pos1, pos2); if (!hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) { return true; } - LocalBlockQueue queue = hybridPlotWorld.getQueue(false); + boolean enqueue = false; + if (queue == null) { + queue = hybridPlotWorld.getQueue(); + enqueue = true; + } createSchemAbs(queue, pos1, pos2, true); - queue.enqueue(); - return true; + return !enqueue || queue.enqueue(); } - private void resetBiome(@Nonnull final HybridPlotWorld hybridPlotWorld, @Nonnull final Location pos1, - @Nonnull final Location pos2) { + private void resetBiome(@Nonnull final HybridPlotWorld hybridPlotWorld, @Nonnull final Location pos1, @Nonnull final Location pos2) { BiomeType biome = hybridPlotWorld.getPlotBiome(); if (!Objects.equals(PlotSquared.platform().getWorldUtil() - .getBiomeSynchronous(hybridPlotWorld.getWorldName(), (pos1.getX() + pos2.getX()) / 2, - (pos1.getZ() + pos2.getZ()) / 2), biome)) { - WorldUtil.setBiome(hybridPlotWorld.getWorldName(), pos1.getX(), pos1.getZ(), pos2.getX(), pos2.getZ(), - biome); + .getBiomeSynchronous(hybridPlotWorld.getWorldName(), (pos1.getX() + pos2.getX()) / 2, (pos1.getZ() + pos2.getZ()) / 2), biome)) { + WorldUtil.setBiome(hybridPlotWorld.getWorldName(), pos1.getX(), pos1.getZ(), pos2.getX(), pos2.getZ(), biome); } } - private void createSchemAbs(LocalBlockQueue queue, Location pos1, Location pos2, - boolean isRoad) { + private void createSchemAbs(@Nonnull final QueueCoordinator queue, @Nonnull final Location pos1, @Nonnull final Location pos2, boolean isRoad) { int size = hybridPlotWorld.SIZE; int minY; - if ((isRoad && Settings.Schematics.PASTE_ROAD_ON_TOP) || (!isRoad - && Settings.Schematics.PASTE_ON_TOP)) { + if ((isRoad && Settings.Schematics.PASTE_ROAD_ON_TOP) || (!isRoad && Settings.Schematics.PASTE_ON_TOP)) { minY = hybridPlotWorld.SCHEM_Y; } else { minY = 1; @@ -173,37 +161,43 @@ public class HybridPlotManager extends ClassicPlotManager { } } - @Override public boolean createRoadSouth(Plot plot) { - super.createRoadSouth(plot); + @Override public boolean createRoadSouth(@Nonnull final Plot plot, @Nullable QueueCoordinator queue) { + super.createRoadSouth(plot, queue); PlotId id = plot.getId(); PlotId id2 = PlotId.of(id.getX(), id.getY() + 1); Location bot = getPlotBottomLocAbs(id2); Location top = getPlotTopLocAbs(id); Location pos1 = Location.at(hybridPlotWorld.getWorldName(), bot.getX() - 1, 0, top.getZ() + 1); - Location pos2 = Location.at(hybridPlotWorld.getWorldName(), top.getX() + 1, - Math.min(getWorldHeight(), 255), bot.getZ()); + Location pos2 = Location.at(hybridPlotWorld.getWorldName(), top.getX() + 1, Math.min(getWorldHeight(), 255), bot.getZ()); this.resetBiome(hybridPlotWorld, pos1, pos2); if (!hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) { return true; } - LocalBlockQueue queue = hybridPlotWorld.getQueue(false); + boolean enqueue = false; + if (queue == null) { + enqueue = true; + queue = hybridPlotWorld.getQueue(); + } createSchemAbs(queue, pos1, pos2, true); - queue.enqueue(); - return true; + return !enqueue || queue.enqueue(); } - @Override public boolean createRoadSouthEast(Plot plot) { - super.createRoadSouthEast(plot); + @Override public boolean createRoadSouthEast(@Nonnull final Plot plot, @Nullable QueueCoordinator queue) { + super.createRoadSouthEast(plot, queue); PlotId id = plot.getId(); PlotId id2 = PlotId.of(id.getX() + 1, id.getY() + 1); Location pos1 = getPlotTopLocAbs(id).add(1, 0, 1).withY(0); Location pos2 = getPlotBottomLocAbs(id2).withY(Math.min(getWorldHeight(), 255)); - LocalBlockQueue queue = hybridPlotWorld.getQueue(false); + boolean enqueue = false; + if (queue == null) { + enqueue = true; + queue = hybridPlotWorld.getQueue(); + } createSchemAbs(queue, pos1, pos2, true); if (hybridPlotWorld.ROAD_SCHEMATIC_ENABLED) { createSchemAbs(queue, pos1, pos2, true); } - return queue.enqueue(); + return !enqueue || queue.enqueue(); } /** @@ -213,7 +207,7 @@ public class HybridPlotManager extends ClassicPlotManager { * don't need to do something quite as complex unless you happen to have 512x512 sized plots. *

*/ - @Override public boolean clearPlot(Plot plot, final Runnable whenDone) { + @Override public boolean clearPlot(@Nonnull final Plot plot, @Nullable final Runnable whenDone, @Nullable QueueCoordinator queue) { if (this.regionManager.notifyClear(this)) { //If this returns false, the clear didn't work if (this.regionManager.handleClear(plot, whenDone, this)) { @@ -221,12 +215,11 @@ public class HybridPlotManager extends ClassicPlotManager { } } final String world = hybridPlotWorld.getWorldName(); - Location pos1 = plot.getBottomAbs(); - Location pos2 = plot.getExtendedTopAbs(); + final Location pos1 = plot.getBottomAbs(); + final Location pos2 = plot.getExtendedTopAbs(); // If augmented final boolean canRegen = - (hybridPlotWorld.getType() == PlotAreaType.AUGMENTED) && (hybridPlotWorld.getTerrain() - != PlotAreaTerrainType.NONE) && REGENERATIVE_CLEAR; + (hybridPlotWorld.getType() == PlotAreaType.AUGMENTED) && (hybridPlotWorld.getTerrain() != PlotAreaTerrainType.NONE) && REGENERATIVE_CLEAR; // The component blocks final Pattern plotfloor = hybridPlotWorld.TOP_BLOCK.toPattern(); final Pattern filling = hybridPlotWorld.MAIN_BLOCK.toPattern(); @@ -240,43 +233,29 @@ public class HybridPlotManager extends ClassicPlotManager { } final BiomeType biome = hybridPlotWorld.getPlotBiome(); - final LocalBlockQueue queue = hybridPlotWorld.getQueue(false); - ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { - @Override public void run(int[] value) { - // If the chunk isn't near the edge and it isn't an augmented world we can just regen the whole chunk - if (canRegen && (value[6] == 0)) { - queue.regenChunk(value[0], value[1]); - return; - } - /* Otherwise we need to set each component, as we don't want to regenerate the road or other plots that share the same chunk.*/ - // Set the biome - WorldUtil.setBiome(world, value[2], value[3], value[4], value[5], biome); - // These two locations are for each component (e.g. bedrock, main block, floor, air) - Location bot = Location.at(world, value[2], 0, value[3]); - Location top = Location.at(world, value[4], 1, value[5]); - queue.setCuboid(bot, top, bedrock); - // Each component has a different layer - bot = bot.withY(1); - top = top.withY(hybridPlotWorld.PLOT_HEIGHT); - queue.setCuboid(bot, top, filling); - bot = bot.withY(hybridPlotWorld.PLOT_HEIGHT); - top = top.withY(hybridPlotWorld.PLOT_HEIGHT + 1); - queue.setCuboid(bot, top, plotfloor); - bot = bot.withY(hybridPlotWorld.PLOT_HEIGHT + 1); - top = top.withY(getWorldHeight()); - queue.setCuboid(bot, top, air); - // And finally set the schematic, the y value is unimportant for this function - pastePlotSchematic(queue, bot, top); - } - }, () -> { - queue.enqueue(); - // And notify whatever called this when plot clearing is done - PlotSquared.platform().getGlobalBlockQueue().addEmptyTask(whenDone); - }, 10); - return true; + boolean enqueue = false; + if (queue == null) { + enqueue = true; + queue = hybridPlotWorld.getQueue(); + } + if (!canRegen) { + queue.setCuboid(pos1.withY(0), pos2.withY(0), bedrock); + // Each component has a different layer + queue.setCuboid(pos1.withY(1), pos2.withY(hybridPlotWorld.PLOT_HEIGHT - 1), filling); + queue.setCuboid(pos1.withY(hybridPlotWorld.PLOT_HEIGHT), pos2.withY(hybridPlotWorld.PLOT_HEIGHT), plotfloor); + queue.setCuboid(pos1.withY(hybridPlotWorld.PLOT_HEIGHT + 1), pos2.withY(getWorldHeight()), air); + queue.setBiomeCuboid(pos1, pos2, biome); + } else { + queue.setRegenRegion(new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3())); + } + pastePlotSchematic(queue, pos1, pos2); + if (whenDone != null) { + queue.setCompleteTask(whenDone); + } + return !enqueue || queue.enqueue(); } - public void pastePlotSchematic(LocalBlockQueue queue, Location bottom, Location top) { + public void pastePlotSchematic(@Nonnull final QueueCoordinator queue, @Nonnull final Location bottom, @Nonnull final Location top) { if (!hybridPlotWorld.PLOT_SCHEMATIC) { return; } @@ -289,7 +268,7 @@ public class HybridPlotManager extends ClassicPlotManager { * @param plot The plot * @return The location where a sign should be */ - @Override public Location getSignLoc(Plot plot) { + @Override public Location getSignLoc(@Nonnull final @NotNull Plot plot) { return hybridPlotWorld.getSignLocation(plot); } diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java index 98783887f..caa4cf2d3 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java @@ -41,7 +41,6 @@ import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.MathMan; -import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.SchematicHandler; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTagBuilder; @@ -81,8 +80,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { private Location SIGN_LOCATION; private File root = null; - private final RegionManager regionManager; - private final SchematicHandler schematicHandler; + @Inject private SchematicHandler schematicHandler; @Inject public HybridPlotWorld(@Assisted("world") final String worldName, @Nullable @Assisted("id") final String id, @@ -90,13 +88,10 @@ public class HybridPlotWorld extends ClassicPlotWorld { @Nullable @Assisted("min") final PlotId min, @Nullable @Assisted("max") final PlotId max, @WorldConfig @Nonnull final YamlConfiguration worldConfiguration, - @Nonnull final RegionManager regionManager, - @Nonnull final SchematicHandler schematicHandler, @Nonnull final GlobalBlockQueue blockQueue, @Nullable final EconHandler econHandler) { super(worldName, id, generator, min, max, worldConfiguration, blockQueue, econHandler); - this.regionManager = regionManager; - this.schematicHandler = schematicHandler; + PlotSquared.platform().getInjector().injectMembers(this); } public static byte wrap(byte data, int start) { @@ -127,11 +122,9 @@ public class HybridPlotWorld extends ClassicPlotWorld { Direction direction = MCDirections.fromRotation(rot); if (direction != null) { - Vector3 vector = transform.apply(direction.toVector()) - .subtract(transform.apply(Vector3.ZERO)).normalize(); - Direction newDirection = Direction.findClosest(vector, - Direction.Flag.CARDINAL | Direction.Flag.ORDINAL - | Direction.Flag.SECONDARY_ORDINAL); + Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize(); + Direction newDirection = + Direction.findClosest(vector, Direction.Flag.CARDINAL | Direction.Flag.ORDINAL | Direction.Flag.SECONDARY_ORDINAL); if (newDirection != null) { CompoundTagBuilder builder = tag.createBuilder(); @@ -147,7 +140,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { } @Nonnull @Override protected PlotManager createManager() { - return new HybridPlotManager(this, this.regionManager); + return new HybridPlotManager(this, PlotSquared.platform().getRegionManager()); } public Location getSignLocation(@Nonnull Plot plot) { @@ -218,21 +211,24 @@ public class HybridPlotWorld extends ClassicPlotWorld { // Try to determine root. This means that plot areas can have separate schematic // directories - if (!(root = FileUtils.getFile(PlotSquared.platform().getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" + - this.getWorldName() + "/" + this.getId())).exists()) { - root = FileUtils.getFile(PlotSquared.platform().getDirectory(), - "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName()); + if (!(root = + FileUtils.getFile(PlotSquared.platform().getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName() + "/" + this.getId())) + .exists()) { + root = FileUtils.getFile(PlotSquared.platform().getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName()); } File schematic1File = new File(root, "sideroad.schem"); - if (!schematic1File.exists()) + if (!schematic1File.exists()) { schematic1File = new File(root, "sideroad.schematic"); + } File schematic2File = new File(root, "intersection.schem"); - if (!schematic2File.exists()) + if (!schematic2File.exists()) { schematic2File = new File(root, "intersection.schematic"); + } File schematic3File = new File(root, "plot.schem"); - if (!schematic3File.exists()) + if (!schematic3File.exists()) { schematic3File = new File(root, "plot.schematic"); + } Schematic schematic1 = this.schematicHandler.getSchematic(schematic1File); Schematic schematic2 = this.schematicHandler.getSchematic(schematic2File); Schematic schematic3 = this.schematicHandler.getSchematic(schematic3File); @@ -285,18 +281,15 @@ public class HybridPlotWorld extends ClassicPlotWorld { for (short x = 0; x < w3; x++) { for (short z = 0; z < l3; z++) { for (short y = 0; y < h3; y++) { - BaseBlock id = blockArrayClipboard3.getFullBlock(BlockVector3 - .at(x + min.getBlockX(), y + min.getBlockY(), z + min.getBlockZ())); + BaseBlock id = + blockArrayClipboard3.getFullBlock(BlockVector3.at(x + min.getBlockX(), y + min.getBlockY(), z + min.getBlockZ())); if (!id.getBlockType().getMaterial().isAir()) { - addOverlayBlock((short) (x + shift + oddshift + centerShiftX), - (short) (y + plotY), (short) (z + shift + oddshift + centerShiftZ), - id, false, h3); + addOverlayBlock((short) (x + shift + oddshift + centerShiftX), (short) (y + plotY), + (short) (z + shift + oddshift + centerShiftZ), id, false, h3); } } - BiomeType biome = blockArrayClipboard3 - .getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); - addOverlayBiome((short) (x + shift + oddshift + centerShiftX), - (short) (z + shift + oddshift + centerShiftZ), biome); + BiomeType biome = blockArrayClipboard3.getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); + addOverlayBiome((short) (x + shift + oddshift + centerShiftX), (short) (z + shift + oddshift + centerShiftZ), biome); } } @@ -325,20 +318,15 @@ public class HybridPlotWorld extends ClassicPlotWorld { for (short x = 0; x < w1; x++) { for (short z = 0; z < l1; z++) { for (short y = 0; y < h1; y++) { - BaseBlock id = blockArrayClipboard1.getFullBlock(BlockVector3 - .at(x + min.getBlockX(), y + min.getBlockY(), z + min.getBlockZ())); + BaseBlock id = blockArrayClipboard1.getFullBlock(BlockVector3.at(x + min.getBlockX(), y + min.getBlockY(), z + min.getBlockZ())); if (!id.getBlockType().getMaterial().isAir()) { - addOverlayBlock((short) (x - shift), (short) (y + roadY), - (short) (z + shift + oddshift), id, false, h1); - addOverlayBlock((short) (z + shift + oddshift), (short) (y + roadY), - (short) (shift - x + (oddshift - 1)), id, true, h1); + addOverlayBlock((short) (x - shift), (short) (y + roadY), (short) (z + shift + oddshift), id, false, h1); + addOverlayBlock((short) (z + shift + oddshift), (short) (y + roadY), (short) (shift - x + (oddshift - 1)), id, true, h1); } } - BiomeType biome = blockArrayClipboard1 - .getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); + BiomeType biome = blockArrayClipboard1.getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); addOverlayBiome((short) (x - shift), (short) (z + shift + oddshift), biome); - addOverlayBiome((short) (z + shift + oddshift), - (short) (shift - x + (oddshift - 1)), biome); + addOverlayBiome((short) (z + shift + oddshift), (short) (shift - x + (oddshift - 1)), biome); } } @@ -351,22 +339,18 @@ public class HybridPlotWorld extends ClassicPlotWorld { for (short x = 0; x < w2; x++) { for (short z = 0; z < l2; z++) { for (short y = 0; y < h2; y++) { - BaseBlock id = blockArrayClipboard2.getFullBlock(BlockVector3 - .at(x + min.getBlockX(), y + min.getBlockY(), z + min.getBlockZ())); + BaseBlock id = blockArrayClipboard2.getFullBlock(BlockVector3.at(x + min.getBlockX(), y + min.getBlockY(), z + min.getBlockZ())); if (!id.getBlockType().getMaterial().isAir()) { - addOverlayBlock((short) (x - shift), (short) (y + roadY), - (short) (z - shift), id, false, h2); + addOverlayBlock((short) (x - shift), (short) (y + roadY), (short) (z - shift), id, false, h2); } } - BiomeType biome = blockArrayClipboard2 - .getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); + BiomeType biome = blockArrayClipboard2.getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); addOverlayBiome((short) (x - shift), (short) (z - shift), biome); } } } - public void addOverlayBlock(short x, short y, short z, BaseBlock id, boolean rotate, - int height) { + public void addOverlayBlock(short x, short y, short z, BaseBlock id, boolean rotate, int height) { if (z < 0) { z += this.SIZE; } else if (z >= this.SIZE) { diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java index 85ec460e4..2a1215074 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java @@ -41,9 +41,9 @@ import com.plotsquared.core.plot.flag.GlobalFlagContainer; import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.plot.flag.implementations.AnalysisFlag; import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.queue.ChunkBlockQueue; +import com.plotsquared.core.queue.ChunkQueueCoordinator; import com.plotsquared.core.queue.GlobalBlockQueue; -import com.plotsquared.core.queue.LocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.RegionManager; @@ -93,27 +93,26 @@ public class HybridUtils { private final ChunkManager chunkManager; private final GlobalBlockQueue blockQueue; private final WorldUtil worldUtil; - private final RegionManager regionManager; private final SchematicHandler schematicHandler; @Inject public HybridUtils(@Nonnull final PlotAreaManager plotAreaManager, - @Nonnull final ChunkManager chunkManager, @Nonnull final GlobalBlockQueue blockQueue, - @Nonnull final WorldUtil worldUtil, @Nonnull final RegionManager regionManager, @Nonnull final SchematicHandler schematicHandler) { + @Nonnull final ChunkManager chunkManager, + @Nonnull final GlobalBlockQueue blockQueue, + @Nonnull final WorldUtil worldUtil, + @Nonnull final SchematicHandler schematicHandler) { this.plotAreaManager = plotAreaManager; this.chunkManager = chunkManager; this.blockQueue = blockQueue; this.worldUtil = worldUtil; - this.regionManager = regionManager; this.schematicHandler = schematicHandler; } public void regeneratePlotWalls(final PlotArea area) { PlotManager plotManager = area.getPlotManager(); - plotManager.regenerateAllPlotWalls(); + plotManager.regenerateAllPlotWalls(null); } - public void analyzeRegion(final String world, final CuboidRegion region, - final RunnableVal whenDone) { + public void analyzeRegion(final String world, final CuboidRegion region, final RunnableVal whenDone) { // int diff, int variety, int vertices, int rotation, int height_sd /* * diff: compare to base by looping through all blocks @@ -127,8 +126,6 @@ public class HybridUtils { * */ TaskManager.runTaskAsync(() -> { - final LocalBlockQueue queue = blockQueue.getNewQueue(world, false); - final BlockVector3 bot = region.getMinimumPoint(); final BlockVector3 top = region.getMaximumPoint(); @@ -150,7 +147,7 @@ public class HybridUtils { } HybridPlotWorld hpw = (HybridPlotWorld) area; - ChunkBlockQueue chunk = new ChunkBlockQueue(bot, top, false); + ChunkQueueCoordinator chunk = new ChunkQueueCoordinator(bot, top, false); hpw.getGenerator().generateChunk(chunk, hpw); final BlockState[][][] oldBlocks = chunk.getBlocks(); @@ -160,6 +157,55 @@ public class HybridUtils { System.gc(); System.gc(); + QueueCoordinator queue = area.getQueue(); + queue.addReadChunks(region.getChunks()); + queue.setChunkConsumer(blockVector2 -> { + int X = blockVector2.getX(); + int Z = blockVector2.getZ(); + int minX; + if (X == cbx) { + minX = bx & 15; + } else { + minX = 0; + } + int minZ; + if (Z == cbz) { + minZ = bz & 15; + } else { + minZ = 0; + } + int maxX; + if (X == ctx) { + maxX = tx & 15; + } else { + maxX = 16; + } + int maxZ; + if (Z == ctz) { + maxZ = tz & 15; + } else { + maxZ = 16; + } + + int chunkBlockX = X << 4; + int chunkBlockZ = Z << 4; + + int xb = chunkBlockX - bx; + int zb = chunkBlockZ - bz; + for (int x = minX; x <= maxX; x++) { + int xx = chunkBlockX + x; + for (int z = minZ; z <= maxZ; z++) { + int zz = chunkBlockZ + z; + for (int y = 0; y < 256; y++) { + BlockState block = queue.getBlock(xx, y, zz); + int xr = xb + x; + int zr = zb + z; + newBlocks[y][xr][zr] = block; + } + } + } + }); + final Runnable run = () -> TaskManager.runTaskAsync(() -> { int size = width * length; int[] changes = new int[size]; @@ -186,30 +232,23 @@ public class HybridUtils { } else { // check vertices // modifications_adjacent - if (x > 0 && z > 0 && y > 0 && x < width - 1 && z < length - 1 - && y < 255) { - if (newBlocks[y - 1][x][z].getBlockType().getMaterial() - .isAir()) { + if (x > 0 && z > 0 && y > 0 && x < width - 1 && z < length - 1 && y < 255) { + if (newBlocks[y - 1][x][z].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y][x - 1][z].getBlockType().getMaterial() - .isAir()) { + if (newBlocks[y][x - 1][z].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y][x][z - 1].getBlockType().getMaterial() - .isAir()) { + if (newBlocks[y][x][z - 1].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y + 1][x][z].getBlockType().getMaterial() - .isAir()) { + if (newBlocks[y + 1][x][z].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y][x + 1][z].getBlockType().getMaterial() - .isAir()) { + if (newBlocks[y][x + 1][z].getBlockType().getMaterial().isAir()) { faces[i]++; } - if (newBlocks[y][x][z + 1].getBlockType().getMaterial() - .isAir()) { + if (newBlocks[y][x][z + 1].getBlockType().getMaterial().isAir()) { faces[i]++; } } @@ -248,57 +287,8 @@ public class HybridUtils { whenDone.value = analysis; whenDone.run(); }); - System.gc(); - Location botLoc = Location.at(world, bot.getX(), bot.getY(), bot.getZ()); - Location topLoc = Location.at(world, top.getX(), top.getY(), top.getZ()); - ChunkManager.chunkTask(botLoc, topLoc, new RunnableVal() { - @Override public void run(int[] value) { - int X = value[0]; - int Z = value[1]; - int minX; - if (X == cbx) { - minX = bx & 15; - } else { - minX = 0; - } - int minZ; - if (Z == cbz) { - minZ = bz & 15; - } else { - minZ = 0; - } - int maxX; - if (X == ctx) { - maxX = tx & 15; - } else { - maxX = 16; - } - int maxZ; - if (Z == ctz) { - maxZ = tz & 15; - } else { - maxZ = 16; - } - - int cbx = X << 4; - int cbz = Z << 4; - - int xb = cbx - bx; - int zb = cbz - bz; - for (int x = minX; x <= maxX; x++) { - int xx = cbx + x; - for (int z = minZ; z <= maxZ; z++) { - int zz = cbz + z; - for (int y = 0; y < 256; y++) { - BlockState block = queue.getBlock(xx, y, zz); - int xr = xb + x; - int zr = zb + z; - newBlocks[y][xr][zr] = block; - } - } - } - } - }, () -> TaskManager.runTaskAsync(run), 5); + queue.setCompleteTask(run); + queue.enqueue(); }); } @@ -347,9 +337,7 @@ public class HybridUtils { result.add(whenDone.value.data_sd); result.add(whenDone.value.air_sd); result.add(whenDone.value.variety_sd); - PlotFlag plotFlag = - GlobalFlagContainer.getInstance().getFlag(AnalysisFlag.class) - .createFlagInstance(result); + PlotFlag plotFlag = GlobalFlagContainer.getInstance().getFlag(AnalysisFlag.class).createFlagInstance(result); PlotFlagAddEvent event = new PlotFlagAddEvent(plotFlag, origin); if (event.getEventResult() == Result.DENY) { return; @@ -371,15 +359,13 @@ public class HybridUtils { run.run(); } - public int checkModified(LocalBlockQueue queue, int x1, int x2, int y1, int y2, int z1, int z2, - BlockState[] blocks) { + public int checkModified(QueueCoordinator queue, int x1, int x2, int y1, int y2, int z1, int z2, BlockState[] blocks) { int count = 0; for (int y = y1; y <= y2; y++) { for (int x = x1; x <= x2; x++) { for (int z = z1; z <= z2; z++) { BlockState block = queue.getBlock(x, y, z); - boolean same = - Arrays.stream(blocks).anyMatch(p -> this.worldUtil.isBlockSame(block, p)); + boolean same = Arrays.stream(blocks).anyMatch(p -> this.worldUtil.isBlockSame(block, p)); if (!same) { count++; } @@ -406,7 +392,7 @@ public class HybridUtils { return false; } HybridUtils.UPDATE = true; - Set regions = this.regionManager.getChunkChunks(area.getWorldName()); + Set regions = this.worldUtil.getChunkChunks(area.getWorldName()); return scheduleRoadUpdate(area, regions, extend, new HashSet<>()); } @@ -420,8 +406,7 @@ public class HybridUtils { return scheduleRoadUpdate(plot.getArea(), regions, extend, new HashSet<>()); } - public boolean scheduleRoadUpdate(final PlotArea area, Set regions, - final int extend, Set chunks) { + public boolean scheduleRoadUpdate(final PlotArea area, Set regions, final int extend, Set chunks) { HybridUtils.regions = regions; HybridUtils.area = area; HybridUtils.height = extend; @@ -438,7 +423,6 @@ public class HybridUtils { if (!regenedRoad && Settings.DEBUG) { logger.info("[P2] Failed to regenerate roads"); } - chunkManager.unloadChunk(area.getWorldName(), chunk, true); } if (Settings.DEBUG) { logger.info("[P2] Cancelled road task"); @@ -461,13 +445,11 @@ public class HybridUtils { try { if (chunks.size() < 1024) { if (!HybridUtils.regions.isEmpty()) { - Iterator iterator = - HybridUtils.regions.iterator(); + Iterator iterator = HybridUtils.regions.iterator(); BlockVector2 loc = iterator.next(); iterator.remove(); if (Settings.DEBUG) { - logger.info("[P2] Updating .mcr: {}, {} (approx 1024 chunks)", - loc.getX(), loc.getZ()); + logger.info("[P2] Updating .mcr: {}, {} (approx 1024 chunks)", loc.getX(), loc.getZ()); logger.info("[P2] - Remaining: {}", HybridUtils.regions.size()); } chunks.addAll(getChunks(loc)); @@ -478,12 +460,10 @@ public class HybridUtils { TaskManager.getPlatformImplementation().sync(() -> { long start = System.currentTimeMillis(); Iterator iterator = chunks.iterator(); - while (System.currentTimeMillis() - start < 20 && !chunks - .isEmpty()) { + while (System.currentTimeMillis() - start < 20 && !chunks.isEmpty()) { final BlockVector2 chunk = iterator.next(); iterator.remove(); - boolean regenedRoads = - regenerateRoad(area, chunk, extend); + boolean regenedRoads = regenerateRoad(area, chunk, extend); if (!regenedRoads && Settings.DEBUG) { logger.info("[P2] Failed to regenerate road"); } @@ -496,18 +476,10 @@ public class HybridUtils { Iterator iterator = HybridUtils.regions.iterator(); BlockVector2 loc = iterator.next(); iterator.remove(); - logger.error("[P2] Error! Could not update '{}/region/r.{}.{}.mca' (Corrupt chunk?)", - area.getWorldHash(), loc.getX(), loc.getZ()); - int sx = loc.getX() << 5; - int sz = loc.getZ() << 5; - for (int x = sx; x < sx + 32; x++) { - for (int z = sz; z < sz + 32; z++) { - chunkManager.unloadChunk(area.getWorldName(), BlockVector2.at(x, z), - true); - } - } + logger.error("[P2] Error! Could not update '{}/region/r.{}.{}.mca' (Corrupt chunk?)", area.getWorldHash(), loc.getX(), + loc.getZ()); } - blockQueue.addEmptyTask(() -> TaskManager.runTaskLater(task, TaskTime.seconds(1L))); + TaskManager.runTaskLater(task, TaskTime.seconds(1L)); }); } } @@ -517,7 +489,7 @@ public class HybridUtils { public boolean setupRoadSchematic(Plot plot) { final String world = plot.getWorldName(); - final LocalBlockQueue queue = blockQueue.getNewQueue(world, false); + final QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(world)); Location bot = plot.getBottomAbs().subtract(1, 0, 1); Location top = plot.getTopAbs(); final HybridPlotWorld plotworld = (HybridPlotWorld) plot.getArea(); @@ -532,36 +504,31 @@ public class HybridUtils { int tz = sz - 1; int ty = get_ey(plotManager, queue, sx, ex, bz, tz, sy); - Set sideRoad = new HashSet<>( - Collections.singletonList(RegionUtil.createRegion(sx, ex, sy, ey, sz, ez))); - final Set intersection = new HashSet<>( - Collections.singletonList(RegionUtil.createRegion(sx, ex, sy, ty, bz, tz))); + Set sideRoad = new HashSet<>(Collections.singletonList(RegionUtil.createRegion(sx, ex, sy, ey, sz, ez))); + final Set intersection = new HashSet<>(Collections.singletonList(RegionUtil.createRegion(sx, ex, sy, ty, bz, tz))); - final String dir = - "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + plot.getArea() - .toString() + File.separator; + final String dir = "schematics" + File.separator + "GEN_ROAD_SCHEMATIC" + File.separator + plot.getArea().toString() + File.separator; this.schematicHandler.getCompoundTag(world, sideRoad, new RunnableVal() { @Override public void run(CompoundTag value) { schematicHandler.save(value, dir + "sideroad.schem"); schematicHandler.getCompoundTag(world, intersection, new RunnableVal() { - @Override public void run(CompoundTag value) { - schematicHandler.save(value, dir + "intersection.schem"); - plotworld.ROAD_SCHEMATIC_ENABLED = true; - try { - plotworld.setupSchematics(); - } catch (SchematicHandler.UnsupportedFormatException e) { - e.printStackTrace(); - } + @Override public void run(CompoundTag value) { + schematicHandler.save(value, dir + "intersection.schem"); + plotworld.ROAD_SCHEMATIC_ENABLED = true; + try { + plotworld.setupSchematics(); + } catch (SchematicHandler.UnsupportedFormatException e) { + e.printStackTrace(); } - }); + } + }); } }); return true; } - public int get_ey(final PlotManager pm, LocalBlockQueue queue, int sx, int ex, int sz, int ez, - int sy) { + public int get_ey(final PlotManager pm, QueueCoordinator queue, int sx, int ex, int sz, int ez, int sy) { int ey = sy; for (int x = sx; x <= ex; x++) { for (int z = sz; z <= ez; z++) { @@ -604,7 +571,7 @@ public class HybridUtils { z -= plotWorld.ROAD_OFFSET_Z; final int finalX = x; final int finalZ = z; - LocalBlockQueue queue = this.blockQueue.getNewQueue(plotWorld.getWorldName(), false); + QueueCoordinator queue = this.blockQueue.getNewQueue(worldUtil.getWeWorld(plotWorld.getWorldName())); if (id1 == null || id2 == null || id1 != id2) { this.chunkManager.loadChunk(area.getWorldName(), chunk, false).thenRun(() -> { if (id1 != null) { @@ -632,8 +599,7 @@ public class HybridUtils { } boolean condition; if (toCheck.get()) { - condition = manager.getPlotId(finalX + X + plotWorld.ROAD_OFFSET_X, 1, - finalZ + Z + plotWorld.ROAD_OFFSET_Z) == null; + condition = manager.getPlotId(finalX + X + plotWorld.ROAD_OFFSET_X, 1, finalZ + Z + plotWorld.ROAD_OFFSET_Z) == null; } else { boolean gx = absX > plotWorld.PATH_WIDTH_LOWER; boolean gz = absZ > plotWorld.PATH_WIDTH_LOWER; @@ -647,27 +613,23 @@ public class HybridUtils { int maxY = Math.max(extend, blocks.length); for (int y = 0; y < maxY; y++) { if (y > blocks.length - 1) { - queue.setBlock(finalX + X + plotWorld.ROAD_OFFSET_X, minY + y, - finalZ + Z + plotWorld.ROAD_OFFSET_Z, WEExtent.AIRBASE); + queue.setBlock(finalX + X + plotWorld.ROAD_OFFSET_X, minY + y, finalZ + Z + plotWorld.ROAD_OFFSET_Z, + WEExtent.AIRBASE); } else { BaseBlock block = blocks[y]; if (block != null) { - queue.setBlock(finalX + X + plotWorld.ROAD_OFFSET_X, - minY + y, finalZ + Z + plotWorld.ROAD_OFFSET_Z, block); + queue.setBlock(finalX + X + plotWorld.ROAD_OFFSET_X, minY + y, finalZ + Z + plotWorld.ROAD_OFFSET_Z, block); } else { - queue.setBlock(finalX + X + plotWorld.ROAD_OFFSET_X, - minY + y, finalZ + Z + plotWorld.ROAD_OFFSET_Z, + queue.setBlock(finalX + X + plotWorld.ROAD_OFFSET_X, minY + y, finalZ + Z + plotWorld.ROAD_OFFSET_Z, WEExtent.AIRBASE); } } } BiomeType biome = plotWorld.G_SCH_B.get(MathMan.pair(absX, absZ)); if (biome != null) { - queue.setBiome(finalX + X + plotWorld.ROAD_OFFSET_X, - finalZ + Z + plotWorld.ROAD_OFFSET_Z, biome); + queue.setBiome(finalX + X + plotWorld.ROAD_OFFSET_X, finalZ + Z + plotWorld.ROAD_OFFSET_Z, biome); } else { - queue.setBiome(finalX + X + plotWorld.ROAD_OFFSET_X, - finalZ + Z + plotWorld.ROAD_OFFSET_Z, plotWorld.getPlotBiome()); + queue.setBiome(finalX + X + plotWorld.ROAD_OFFSET_X, finalZ + Z + plotWorld.ROAD_OFFSET_Z, plotWorld.getPlotBiome()); } } } diff --git a/Core/src/main/java/com/plotsquared/core/generator/IndependentPlotGenerator.java b/Core/src/main/java/com/plotsquared/core/generator/IndependentPlotGenerator.java index c42e54546..f3675ab40 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/IndependentPlotGenerator.java +++ b/Core/src/main/java/com/plotsquared/core/generator/IndependentPlotGenerator.java @@ -29,7 +29,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.SetupObject; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.setup.PlotAreaBuilder; /** @@ -52,9 +52,9 @@ public abstract class IndependentPlotGenerator { * @param result * @param settings */ - public abstract void generateChunk(ScopedLocalBlockQueue result, PlotArea settings); + public abstract void generateChunk(ScopedQueueCoordinator result, PlotArea settings); - public boolean populateChunk(ScopedLocalBlockQueue result, PlotArea setting) { + public boolean populateChunk(ScopedQueueCoordinator result, PlotArea setting) { return false; } @@ -75,8 +75,7 @@ public abstract class IndependentPlotGenerator { * * @param setup */ - @Deprecated - public void processSetup(SetupObject setup) { + @Deprecated public void processSetup(SetupObject setup) { } /** @@ -85,7 +84,8 @@ public abstract class IndependentPlotGenerator { * * @param builder the area builder to modify */ - public void processAreaSetup(PlotAreaBuilder builder) { } + public void processAreaSetup(PlotAreaBuilder builder) { + } /** * It is preferred for the PlotArea object to do most of the initialization necessary. diff --git a/Core/src/main/java/com/plotsquared/core/generator/SingleWorldGenerator.java b/Core/src/main/java/com/plotsquared/core/generator/SingleWorldGenerator.java index 12df0288f..818fd654b 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/SingleWorldGenerator.java +++ b/Core/src/main/java/com/plotsquared/core/generator/SingleWorldGenerator.java @@ -32,7 +32,7 @@ import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockTypes; @@ -57,7 +57,7 @@ public class SingleWorldGenerator extends IndependentPlotGenerator { return "PlotSquared:single"; } - @Override public void generateChunk(ScopedLocalBlockQueue result, PlotArea settings) { + @Override public void generateChunk(ScopedQueueCoordinator result, PlotArea settings) { SinglePlotArea area = (SinglePlotArea) settings; if (area.VOID) { Location min = result.getMin(); diff --git a/Core/src/main/java/com/plotsquared/core/generator/SquarePlotManager.java b/Core/src/main/java/com/plotsquared/core/generator/SquarePlotManager.java index 389214029..0cfc21a95 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/SquarePlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/generator/SquarePlotManager.java @@ -30,13 +30,16 @@ import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.HashUtil; import com.plotsquared.core.util.RegionManager; import com.sk89q.worldedit.regions.CuboidRegion; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Iterator; import java.util.Set; @@ -56,12 +59,14 @@ public abstract class SquarePlotManager extends GridPlotManager { this.regionManager = regionManager; } - @Override public boolean clearPlot(final Plot plot, final Runnable whenDone) { + @Override public boolean clearPlot(final @NotNull Plot plot, final @Nullable Runnable whenDone, @Nullable QueueCoordinator queue) { final Set regions = plot.getRegions(); Runnable run = new Runnable() { @Override public void run() { if (regions.isEmpty()) { - whenDone.run(); + if (whenDone != null) { + whenDone.run(); + } return; } Iterator iterator = regions.iterator(); @@ -76,13 +81,13 @@ public abstract class SquarePlotManager extends GridPlotManager { return true; } - @Override public Location getPlotTopLocAbs(PlotId plotId) { + @Override public Location getPlotTopLocAbs(@NotNull PlotId plotId) { int px = plotId.getX(); int pz = plotId.getY(); - int x = (squarePlotWorld.ROAD_OFFSET_X + (px * (squarePlotWorld.ROAD_WIDTH - + squarePlotWorld.PLOT_WIDTH))) - (int) Math.floor(squarePlotWorld.ROAD_WIDTH / 2) - 1; - int z = (squarePlotWorld.ROAD_OFFSET_Z + (pz * (squarePlotWorld.ROAD_WIDTH - + squarePlotWorld.PLOT_WIDTH))) - (int) Math.floor(squarePlotWorld.ROAD_WIDTH / 2) - 1; + int x = (squarePlotWorld.ROAD_OFFSET_X + (px * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - (int) Math + .floor(squarePlotWorld.ROAD_WIDTH / 2) - 1; + int z = (squarePlotWorld.ROAD_OFFSET_Z + (pz * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - (int) Math + .floor(squarePlotWorld.ROAD_WIDTH / 2) - 1; return Location.at(squarePlotWorld.getWorldName(), x, Math.min(getWorldHeight(), 255), z); } @@ -130,7 +135,7 @@ public abstract class SquarePlotManager extends GridPlotManager { } } - public PlotId getNearestPlotId(PlotArea plotArea, int x, int y, int z) { + public PlotId getNearestPlotId(@Nonnull PlotArea plotArea, int x, int y, int z) { SquarePlotWorld dpw = (SquarePlotWorld) plotArea; if (dpw.ROAD_OFFSET_X != 0) { x -= dpw.ROAD_OFFSET_X; @@ -191,8 +196,7 @@ public abstract class SquarePlotManager extends GridPlotManager { rz = z % size; } PlotId id = PlotId.of(dx, dz); - boolean[] merged = - new boolean[] {rz <= pathWidthLower, rx > end, rz > end, rx <= pathWidthLower}; + boolean[] merged = new boolean[] {rz <= pathWidthLower, rx > end, rz > end, rx <= pathWidthLower}; int hash = HashUtil.hash(merged); // Not merged, and no need to check if it is if (hash == 0) { @@ -230,8 +234,7 @@ public abstract class SquarePlotManager extends GridPlotManager { return plot.getMerged(Direction.NORTHWEST) ? id : null; } } catch (Exception ignored) { - logger.error( "Invalid plot / road width in settings.yml for world: {}", squarePlotWorld - .getWorldName()); + logger.error("Invalid plot / road width in settings.yml for world: {}", squarePlotWorld.getWorldName()); } return null; } @@ -239,15 +242,13 @@ public abstract class SquarePlotManager extends GridPlotManager { /** * Get the bottom plot loc (some basic math). */ - @Override public Location getPlotBottomLocAbs(PlotId plotId) { + @Override public Location getPlotBottomLocAbs(@NotNull PlotId plotId) { int px = plotId.getX(); int pz = plotId.getY(); - int x = (squarePlotWorld.ROAD_OFFSET_X + (px * (squarePlotWorld.ROAD_WIDTH - + squarePlotWorld.PLOT_WIDTH))) - squarePlotWorld.PLOT_WIDTH - (int) Math - .floor(squarePlotWorld.ROAD_WIDTH / 2); - int z = (squarePlotWorld.ROAD_OFFSET_Z + (pz * (squarePlotWorld.ROAD_WIDTH - + squarePlotWorld.PLOT_WIDTH))) - squarePlotWorld.PLOT_WIDTH - (int) Math - .floor(squarePlotWorld.ROAD_WIDTH / 2); + int x = (squarePlotWorld.ROAD_OFFSET_X + (px * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - squarePlotWorld.PLOT_WIDTH + - (int) Math.floor(squarePlotWorld.ROAD_WIDTH / 2); + int z = (squarePlotWorld.ROAD_OFFSET_Z + (pz * (squarePlotWorld.ROAD_WIDTH + squarePlotWorld.PLOT_WIDTH))) - squarePlotWorld.PLOT_WIDTH + - (int) Math.floor(squarePlotWorld.ROAD_WIDTH / 2); return Location.at(squarePlotWorld.getWorldName(), x, squarePlotWorld.getMinBuildHeight(), z); } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/OffsetLocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorBuilderFactory.java similarity index 64% rename from Core/src/main/java/com/plotsquared/core/queue/OffsetLocalBlockQueue.java rename to Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorBuilderFactory.java index 06233277d..c526ae731 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/OffsetLocalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorBuilderFactory.java @@ -23,28 +23,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.plotsquared.core.queue; +package com.plotsquared.core.inject.factory; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.plotsquared.core.queue.ChunkCoordinatorBuilder; +import org.jetbrains.annotations.NotNull; -public class OffsetLocalBlockQueue extends DelegateLocalBlockQueue { - private final int ox; - private final int oy; - private final int oz; +import javax.annotation.Nonnull; - public OffsetLocalBlockQueue(LocalBlockQueue parent, int ox, int oy, int oz) { - super(parent); - this.ox = ox; - this.oy = oy; - this.oz = oz; - } +public interface ChunkCoordinatorBuilderFactory { - @Override public boolean setBiome(int x, int y, BiomeType biome) { - return super.setBiome(ox + x, oy + y, biome); - } + @Inject @Nonnull ChunkCoordinatorBuilder create(@Assisted @NotNull ChunkCoordinatorFactory chunkCoordinatorFactory); - @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { - return super.setBlock(ox + x, oy + y, oz + z, id); - } } diff --git a/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java b/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java new file mode 100644 index 000000000..aeb62d659 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/inject/factory/ChunkCoordinatorFactory.java @@ -0,0 +1,47 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.inject.factory; + +import com.plotsquared.core.queue.ChunkCoordinator; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.function.Consumer; + +public interface ChunkCoordinatorFactory { + + @Nonnull ChunkCoordinator create(final long maxIterationTime, + final int initialBatchSize, + @Nonnull final Consumer chunkConsumer, + @Nonnull final World world, + @Nonnull final Collection requestedChunks, + @Nonnull final Runnable whenDone, + @Nonnull final Consumer throwableConsumer, + final boolean unloadAfter); + +} diff --git a/Core/src/main/java/com/plotsquared/core/permissions/Permission.java b/Core/src/main/java/com/plotsquared/core/permissions/Permission.java index ff1b913ef..7df2b69a8 100644 --- a/Core/src/main/java/com/plotsquared/core/permissions/Permission.java +++ b/Core/src/main/java/com/plotsquared/core/permissions/Permission.java @@ -8,7 +8,7 @@ * | | * |_| * PlotSquared plot management system for Minecraft - * Copyright (C) ${year} IntellectualSites + * Copyright (C) 2020 IntellectualSites * * 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 diff --git a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java index 5edf2d0ef..7ba30fdd3 100644 --- a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java @@ -139,10 +139,6 @@ public class ConsolePlayer extends PlotPlayer { return true; } - @Override public boolean isPermissionSet(@Nonnull String permission) { - return true; - } - @Override public void sendMessage(@Nonnull final Caption caption, @Nonnull final Template... replacements) { String message = caption.getComponent(this); diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 718d3d97a..0e59b2024 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -31,7 +31,6 @@ import com.google.common.collect.Sets; import com.google.inject.Inject; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.command.Like; -import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.configuration.ConfigurationUtil; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.Caption; @@ -51,6 +50,7 @@ import com.plotsquared.core.location.BlockLoc; import com.plotsquared.core.location.Direction; import com.plotsquared.core.location.Location; import com.plotsquared.core.location.PlotLoc; +import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.ConsolePlayer; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.comment.PlotComment; @@ -66,7 +66,7 @@ import com.plotsquared.core.plot.flag.implementations.ServerPlotFlag; import com.plotsquared.core.plot.flag.types.DoubleFlag; import com.plotsquared.core.plot.schematic.Schematic; import com.plotsquared.core.queue.GlobalBlockQueue; -import com.plotsquared.core.queue.LocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; @@ -142,15 +142,13 @@ public class Plot { private static final Logger logger = LoggerFactory.getLogger("P2/" + Plot.class.getSimpleName()); private static final DecimalFormat FLAG_DECIMAL_FORMAT = new DecimalFormat("0"); - static { - FLAG_DECIMAL_FORMAT.setMaximumFractionDigits(340); - } - private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().build(); private static Set connected_cache; private static Set regions_cache; - + static { + FLAG_DECIMAL_FORMAT.setMaximumFractionDigits(340); + } /** * Plot flag container */ @@ -275,9 +273,18 @@ public class Plot { * @param merged an array giving merged plots * @see Plot#getPlot(Location) for existing plots */ - public Plot(@Nonnull PlotId id, UUID owner, HashSet trusted, HashSet members, - HashSet denied, String alias, BlockLoc position, Collection> flags, - PlotArea area, boolean[] merged, long timestamp, int temp) { + public Plot(@Nonnull PlotId id, + UUID owner, + HashSet trusted, + HashSet members, + HashSet denied, + String alias, + BlockLoc position, + Collection> flags, + PlotArea area, + boolean[] merged, + long timestamp, + int temp) { this.id = id; this.area = area; this.owner = owner; @@ -309,8 +316,7 @@ public class Plot { * @param message If a message should be sent to the player if a plot cannot be found * @return The plot if only 1 result is found, or null */ - @Nullable public static Plot getPlotFromString(PlotPlayer player, String arg, - boolean message) { + @Nullable public static Plot getPlotFromString(PlotPlayer player, String arg, boolean message) { if (arg == null) { if (player == null) { if (message) { @@ -332,8 +338,7 @@ public class Plot { String[] split = arg.split(";|,"); PlotId id; if (split.length == 4) { - area = PlotSquared.get().getPlotAreaManager() - .getPlotAreaByString(split[0] + ';' + split[1]); + area = PlotSquared.get().getPlotAreaManager().getPlotAreaByString(split[0] + ';' + split[1]); id = PlotId.fromString(split[2] + ';' + split[3]); } else if (split.length == 3) { area = PlotSquared.get().getPlotAreaManager().getPlotAreaByString(split[0]); @@ -412,8 +417,7 @@ public class Plot { return null; } - @Nonnull private static Location[] getCorners(@Nonnull final String world, - @Nonnull final CuboidRegion region) { + @Nonnull private static Location[] getCorners(@Nonnull final String world, @Nonnull final CuboidRegion region) { final BlockVector3 min = region.getMinimumPoint(); final BlockVector3 max = region.getMaximumPoint(); return new Location[] {Location.at(world, min), Location.at(world, max)}; @@ -612,8 +616,7 @@ public class Plot { UUID last = this.getOwner(); owners.add(this.getOwner()); for (Plot current : array) { - if (last == null || current.getOwner().getMostSignificantBits() != last - .getMostSignificantBits()) { + if (last == null || current.getOwner().getMostSignificantBits() != last.getMostSignificantBits()) { owners.add(current.getOwner()); last = current.getOwner(); } @@ -655,8 +658,8 @@ public class Plot { * @return boolean false if the player is allowed to enter */ public boolean isDenied(UUID uuid) { - return this.denied != null && (this.denied.contains(DBFunc.EVERYONE) && !this.isAdded(uuid) - || !this.isAdded(uuid) && this.denied.contains(uuid)); + return this.denied != null && (this.denied.contains(DBFunc.EVERYONE) && !this.isAdded(uuid) || !this.isAdded(uuid) && this.denied + .contains(uuid)); } /** @@ -780,8 +783,7 @@ public class Plot { * @return true if this plot is merged, otherwise false */ public boolean isMerged() { - return getSettings().getMerged(0) || getSettings().getMerged(2) || getSettings() - .getMerged(1) || getSettings().getMerged(3); + return getSettings().getMerged(0) || getSettings().getMerged(2) || getSettings().getMerged(1) || getSettings().getMerged(3); } /** @@ -832,10 +834,8 @@ public class Plot { int i2 = 0; if (this.getSettings().getMerged(i2)) { if (this.getSettings().getMerged(i)) { - if (this.area.getPlotAbs(this.id.getRelative(Direction.getFromIndex(i))) - .getMerged(i2)) { - return this.area.getPlotAbs(this.id.getRelative(Direction.getFromIndex(i2))) - .getMerged(i); + if (this.area.getPlotAbs(this.id.getRelative(Direction.getFromIndex(i))).getMerged(i2)) { + return this.area.getPlotAbs(this.id.getRelative(Direction.getFromIndex(i2))).getMerged(i); } } } @@ -845,9 +845,8 @@ public class Plot { case 6: i = dir - 4; i2 = dir - 3; - return this.getSettings().getMerged(i2) && this.getSettings().getMerged(i) - && this.area.getPlotAbs(this.id.getRelative(Direction.getFromIndex(i))) - .getMerged(i2) && this.area + return this.getSettings().getMerged(i2) && this.getSettings().getMerged(i) && this.area + .getPlotAbs(this.id.getRelative(Direction.getFromIndex(i))).getMerged(i2) && this.area .getPlotAbs(this.id.getRelative(Direction.getFromIndex(i2))).getMerged(i); } @@ -1049,8 +1048,7 @@ public class Plot { this.removeSign(); } PlotUnlinkEvent event = this.eventDispatcher - .callUnlink(getArea(), this, true, !isDelete, - isDelete ? PlotUnlinkEvent.REASON.DELETE : PlotUnlinkEvent.REASON.CLEAR); + .callUnlink(getArea(), this, true, !isDelete, isDelete ? PlotUnlinkEvent.REASON.DELETE : PlotUnlinkEvent.REASON.CLEAR); if (event.getEventResult() != Result.DENY) { this.unlinkPlot(event.isCreateRoad(), event.isCreateSign()); } @@ -1065,28 +1063,31 @@ public class Plot { } TaskManager.runTask(whenDone); }; + QueueCoordinator queue = getArea().getQueue(); for (Plot current : plots) { if (isDelete || !current.hasOwner()) { - manager.unClaimPlot(current, null); + manager.unClaimPlot(current, null, queue); } else { - manager.claimPlot(current); + manager.claimPlot(current, queue); } } - blockQueue.addEmptyTask(run); + if (queue.size() > 0) { + queue.enqueue(); + } + TaskManager.runTask(run); return; } Plot current = queue.poll(); if (Plot.this.area.getTerrain() != PlotAreaTerrainType.NONE) { try { - regionManager.regenerateRegion(current.getBottomAbs(), current.getTopAbs(), false, - this); + regionManager.regenerateRegion(current.getBottomAbs(), current.getTopAbs(), false, this); } catch (UnsupportedOperationException exception) { logger.info("[P2] Please ask md_5 to fix regenerateChunk() because it breaks plugins. We apologize for the inconvenience."); return; } return; } - manager.clearPlot(current, this); + manager.clearPlot(current, this, null); } }; run.run(); @@ -1138,26 +1139,28 @@ public class Plot { ids.add(current.getId()); } this.clearRatings(); + QueueCoordinator queue = null; if (createSign) { this.removeSign(); + queue = getArea().getQueue(); } PlotManager manager = this.area.getPlotManager(); if (createRoad) { - manager.startPlotUnlink(ids); + manager.startPlotUnlink(ids, queue); } if (this.area.getTerrain() != PlotAreaTerrainType.ALL && createRoad) { for (Plot current : plots) { if (current.getMerged(Direction.EAST)) { - manager.createRoadEast(current); + manager.createRoadEast(current, queue); if (current.getMerged(Direction.SOUTH)) { - manager.createRoadSouth(current); + manager.createRoadSouth(current, queue); if (current.getMerged(Direction.SOUTHEAST)) { - manager.createRoadSouthEast(current); + manager.createRoadSouthEast(current, queue); } } } if (current.getMerged(Direction.SOUTH)) { - manager.createRoadSouth(current); + manager.createRoadSouth(current, queue); } } } @@ -1166,16 +1169,14 @@ public class Plot { current.setMerged(merged); } if (createSign) { - blockQueue.addEmptyTask(() -> { - TaskManager.runTaskAsync(() -> { - for (Plot current : plots) { - current.setSign(PlayerManager.getName(current.getOwnerAbs())); - } - }); - }); + queue.setCompleteTask(() -> TaskManager.runTaskAsync(() -> { + for (Plot current : plots) { + current.setSign(PlayerManager.getName(current.getOwnerAbs())); + } + })); } if (createRoad) { - manager.finishPlotUnlink(ids); + manager.finishPlotUnlink(ids, queue); } return true; } @@ -1281,14 +1282,12 @@ public class Plot { * @param ignorePluginFlags Whether or not to ignore {@link InternalFlag internal flags} * @return Collection containing all the flags that matched the given criteria */ - public Collection> getApplicableFlags(final boolean plotOnly, - final boolean ignorePluginFlags) { + public Collection> getApplicableFlags(final boolean plotOnly, final boolean ignorePluginFlags) { if (!hasOwner()) { return Collections.emptyList(); } final Map, PlotFlag> flags = new HashMap<>(); - if (!plotOnly && getArea() != null && !getArea().getFlagContainer().getFlagMap() - .isEmpty()) { + if (!plotOnly && getArea() != null && !getArea().getFlagContainer().getFlagMap().isEmpty()) { final Map, PlotFlag> flagMap = getArea().getFlagContainer().getFlagMap(); flags.putAll(flagMap); } @@ -1446,8 +1445,7 @@ public class Plot { if (Settings.Backup.DELETE_ON_UNCLAIM) { // Destroy all backups when the plot is unclaimed - Objects.requireNonNull(PlotSquared.platform()).getBackupManager().getProfile(current) - .destroy(); + Objects.requireNonNull(PlotSquared.platform()).getBackupManager().getProfile(current).destroy(); } getArea().removePlot(getId()); @@ -1475,8 +1473,8 @@ public class Plot { Location[] corners = getCorners(); Location top = corners[0]; Location bot = corners[1]; - Location location = Location.at(this.getWorldName(), MathMan.average(bot.getX(), top.getX()), - MathMan.average(bot.getY(), top.getY()), MathMan.average(bot.getZ(), top.getZ())); + Location location = Location.at(this.getWorldName(), MathMan.average(bot.getX(), top.getX()), MathMan.average(bot.getY(), top.getY()), + MathMan.average(bot.getZ(), top.getZ())); if (!isLoaded()) { result.accept(location); return; @@ -1497,8 +1495,8 @@ public class Plot { Location[] corners = getCorners(); Location top = corners[0]; Location bot = corners[1]; - Location location = Location.at(this.getWorldName(), MathMan.average(bot.getX(), top.getX()), - MathMan.average(bot.getY(), top.getY()), MathMan.average(bot.getZ(), top.getZ())); + Location location = Location.at(this.getWorldName(), MathMan.average(bot.getX(), top.getX()), MathMan.average(bot.getY(), top.getY()), + MathMan.average(bot.getZ(), top.getZ())); if (!isLoaded()) { return location; } @@ -1514,8 +1512,7 @@ public class Plot { */ @Deprecated public Location getSideSynchronous() { CuboidRegion largest = getLargestRegion(); - int x = (largest.getMaximumPoint().getX() >> 1) - (largest.getMinimumPoint().getX() >> 1) - + largest.getMinimumPoint().getX(); + int x = (largest.getMaximumPoint().getX() >> 1) - (largest.getMinimumPoint().getX() >> 1) + largest.getMinimumPoint().getX(); int z = largest.getMinimumPoint().getZ() - 1; PlotManager manager = getManager(); int y = isLoaded() ? this.worldUtil.getHighestBlockSynchronous(getWorldName(), x, z) : 62; @@ -1527,8 +1524,7 @@ public class Plot { public void getSide(Consumer result) { CuboidRegion largest = getLargestRegion(); - int x = (largest.getMaximumPoint().getX() >> 1) - (largest.getMinimumPoint().getX() >> 1) - + largest.getMinimumPoint().getX(); + int x = (largest.getMaximumPoint().getX() >> 1) - (largest.getMinimumPoint().getX() >> 1) + largest.getMinimumPoint().getX(); int z = largest.getMinimumPoint().getZ() - 1; PlotManager manager = getManager(); if (isLoaded()) { @@ -1557,15 +1553,15 @@ public class Plot { return this.getDefaultHomeSynchronous(true); } else { Location bottom = this.getBottomAbs(); - Location location = Location.at(bottom.getWorldName(), bottom.getX() + home.getX(), - bottom.getY() + home.getY(), bottom.getZ() + home.getZ(), home.getYaw(), - home.getPitch()); + Location location = Location + .at(bottom.getWorldName(), bottom.getX() + home.getX(), bottom.getY() + home.getY(), bottom.getZ() + home.getZ(), home.getYaw(), + home.getPitch()); if (!isLoaded()) { return location; } if (!this.worldUtil.getBlockSynchronous(location).getBlockType().getMaterial().isAir()) { - location = location.withY(Math.max(1 + this.worldUtil.getHighestBlockSynchronous(this.getWorldName(), location.getX(), - location.getZ()), bottom.getY())); + location = location.withY( + Math.max(1 + this.worldUtil.getHighestBlockSynchronous(this.getWorldName(), location.getX(), location.getZ()), bottom.getY())); } return location; } @@ -1580,9 +1576,9 @@ public class Plot { this.getDefaultHome(result); } else { Location bottom = this.getBottomAbs(); - Location location = Location.at(bottom.getWorldName(), bottom.getX() + home.getX(), - bottom.getY() + home.getY(), bottom.getZ() + home.getZ(), home.getYaw(), - home.getPitch()); + Location location = Location + .at(bottom.getWorldName(), bottom.getX() + home.getX(), bottom.getY() + home.getY(), bottom.getZ() + home.getZ(), home.getYaw(), + home.getPitch()); if (!isLoaded()) { result.accept(location); return; @@ -1590,7 +1586,7 @@ public class Plot { this.worldUtil.getBlock(location, block -> { if (!block.getBlockType().getMaterial().isAir()) { this.worldUtil.getHighestBlock(this.getWorldName(), location.getX(), location.getZ(), - y -> result.accept(location.withY(Math.max(1 + y, bottom.getY())))); + y -> result.accept(location.withY(Math.max(1 + y, bottom.getY())))); } else { result.accept(location); } @@ -1636,21 +1632,15 @@ public class Plot { if (loc.getX() == Integer.MAX_VALUE && loc.getZ() == Integer.MAX_VALUE) { // center CuboidRegion largest = plot.getLargestRegion(); - x = (largest.getMaximumPoint().getX() >> 1) - (largest.getMinimumPoint().getX() - >> 1) + largest.getMinimumPoint().getX(); - z = (largest.getMaximumPoint().getZ() >> 1) - (largest.getMinimumPoint().getZ() - >> 1) + largest.getMinimumPoint().getZ(); + x = (largest.getMaximumPoint().getX() >> 1) - (largest.getMinimumPoint().getX() >> 1) + largest.getMinimumPoint().getX(); + z = (largest.getMaximumPoint().getZ() >> 1) - (largest.getMinimumPoint().getZ() >> 1) + largest.getMinimumPoint().getZ(); } else { // specific Location bot = plot.getBottomAbs(); x = bot.getX() + loc.getX(); z = bot.getZ() + loc.getZ(); } - int y = loc.getY() < 1 ? - (isLoaded() ? - this.worldUtil.getHighestBlockSynchronous(plot.getWorldName(), x, z) + 1 : - 63) : - loc.getY(); + int y = loc.getY() < 1 ? (isLoaded() ? this.worldUtil.getHighestBlockSynchronous(plot.getWorldName(), x, z) + 1 : 63) : loc.getY(); return Location.at(plot.getWorldName(), x, y, z); } // Side @@ -1666,10 +1656,8 @@ public class Plot { if (loc.getX() == Integer.MAX_VALUE && loc.getZ() == Integer.MAX_VALUE) { // center CuboidRegion largest = plot.getLargestRegion(); - x = (largest.getMaximumPoint().getX() >> 1) - (largest.getMinimumPoint().getX() - >> 1) + largest.getMinimumPoint().getX(); - z = (largest.getMaximumPoint().getZ() >> 1) - (largest.getMinimumPoint().getZ() - >> 1) + largest.getMinimumPoint().getZ(); + x = (largest.getMaximumPoint().getX() >> 1) - (largest.getMinimumPoint().getX() >> 1) + largest.getMinimumPoint().getX(); + z = (largest.getMaximumPoint().getZ() >> 1) - (largest.getMinimumPoint().getZ() >> 1) + largest.getMinimumPoint().getZ(); } else { // specific Location bot = plot.getBottomAbs(); @@ -1678,8 +1666,7 @@ public class Plot { } if (loc.getY() < 1) { if (isLoaded()) { - this.worldUtil.getHighestBlock(plot.getWorldName(), x, z, - y -> result.accept(Location.at(plot.getWorldName(), x, y + 1, z))); + this.worldUtil.getHighestBlock(plot.getWorldName(), x, z, y -> result.accept(Location.at(plot.getWorldName(), x, y + 1, z))); } else { result.accept(Location.at(plot.getWorldName(), x, 63, z)); } @@ -1695,10 +1682,8 @@ public class Plot { public double getVolume() { double count = 0; for (CuboidRegion region : getRegions()) { - count += - (region.getMaximumPoint().getX() - (double) region.getMinimumPoint().getX() + 1) * ( - region.getMaximumPoint().getZ() - (double) region.getMinimumPoint().getZ() + 1) - * MAX_HEIGHT; + count += (region.getMaximumPoint().getX() - (double) region.getMinimumPoint().getX() + 1) * ( + region.getMaximumPoint().getZ() - (double) region.getMinimumPoint().getZ() + 1) * MAX_HEIGHT; } return count; } @@ -1781,15 +1766,13 @@ public class Plot { * This should not need to be called */ public void refreshChunks() { - LocalBlockQueue queue = this.blockQueue.getNewQueue(getWorldName(), false); + QueueCoordinator queue = this.blockQueue.getNewQueue(PlotSquared.platform().getWorldUtil().getWeWorld(getWorldName())); HashSet chunks = new HashSet<>(); for (CuboidRegion region : Plot.this.getRegions()) { - for (int x = region.getMinimumPoint().getX() >> 4; - x <= region.getMaximumPoint().getX() >> 4; x++) { - for (int z = region.getMinimumPoint().getZ() >> 4; - z <= region.getMaximumPoint().getZ() >> 4; z++) { + for (int x = region.getMinimumPoint().getX() >> 4; x <= region.getMaximumPoint().getX() >> 4; x++) { + for (int z = region.getMinimumPoint().getZ() >> 4; z <= region.getMaximumPoint().getZ() >> 4; z++) { if (chunks.add(BlockVector2.at(x, z))) { - queue.refreshChunk(x, z); + worldUtil.refreshChunk(x, z, getWorldName()); } } } @@ -1805,10 +1788,9 @@ public class Plot { return; } Location location = manager.getSignLoc(this); - LocalBlockQueue queue = this.blockQueue.getNewQueue(getWorldName(), false); - queue.setBlock(location.getX(), location.getY(), location.getZ(), - BlockTypes.AIR.getDefaultState()); - queue.flush(); + QueueCoordinator queue = this.blockQueue.getNewQueue(worldUtil.getWeWorld(getWorldName())); + queue.setBlock(location.getX(), location.getY(), location.getZ(), BlockTypes.AIR.getDefaultState()); + queue.enqueue(); } /** @@ -1819,8 +1801,7 @@ public class Plot { this.setSign("unknown"); return; } - this.impromptuPipeline.getSingle(this.getOwnerAbs(), (username, sign) -> - this.setSign(username)); + this.impromptuPipeline.getSingle(this.getOwnerAbs(), (username, sign) -> this.setSign(username)); } /** @@ -1842,13 +1823,12 @@ public class Plot { return claim(player, teleport, schematic, true); } - public boolean claim(@Nonnull final PlotPlayer player, boolean teleport, String schematic, - boolean updateDB) { + public boolean claim(@Nonnull final PlotPlayer player, boolean teleport, String schematic, boolean updateDB) { if (updateDB) { if (!create(player.getUUID(), true)) { - logger.error("[P2] Player {} attempted to claim plot {}, but the database failed to update", - player.getName(), this.getId().toCommaSeparatedString()); + logger.error("[P2] Player {} attempted to claim plot {}, but the database failed to update", player.getName(), + this.getId().toCommaSeparatedString()); return false; } } else { @@ -1877,18 +1857,17 @@ public class Plot { e.printStackTrace(); return true; } - schematicHandler.paste(sch, this, 0, 1, 0, Settings.Schematics.PASTE_ON_TOP, - new RunnableVal() { - @Override public void run(Boolean value) { - if (value) { - player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_success")); - } else { - player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_failed")); - } + schematicHandler.paste(sch, this, 0, 1, 0, Settings.Schematics.PASTE_ON_TOP, new RunnableVal() { + @Override public void run(Boolean value) { + if (value) { + player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_success")); + } else { + player.sendMessage(TranslatableCaption.of("schematics.schematic_paste_failed")); } - }); + } + }); } - plotworld.getPlotManager().claimPlot(this); + plotworld.getPlotManager().claimPlot(this, null); return true; } @@ -1925,11 +1904,9 @@ public class Plot { DBFunc.createPlotAndSettings(this, () -> { PlotArea plotworld = Plot.this.area; if (notify && plotworld.isAutoMerge()) { - final PlotPlayer player = PlotSquared.platform().getPlayerManager() - .getPlayerIfExists(uuid); + final PlotPlayer player = PlotSquared.platform().getPlayerManager().getPlayerIfExists(uuid); - PlotMergeEvent event = this.eventDispatcher - .callMerge(this, Direction.ALL, Integer.MAX_VALUE, player); + PlotMergeEvent event = this.eventDispatcher.callMerge(this, Direction.ALL, Integer.MAX_VALUE, player); if (event.getEventResult() == Result.DENY) { if (player != null) { @@ -1943,8 +1920,7 @@ public class Plot { }); return true; } - logger.info("[P2] Failed to add plot {} to plot area {}", - this.getId().toCommaSeparatedString(), this.area.toString()); + logger.info("[P2] Failed to add plot {} to plot area {}", this.getId().toCommaSeparatedString(), this.area.toString()); return false; } @@ -1952,12 +1928,12 @@ public class Plot { * Sets components such as border, wall, floor. * (components are generator specific) */ - @Deprecated public boolean setComponent(String component, String blocks) { + @Deprecated public boolean setComponent(String component, String blocks, QueueCoordinator queue) { BlockBucket parsed = ConfigurationUtil.BLOCK_BUCKET.parseString(blocks); if (parsed != null && parsed.isEmpty()) { return false; } - return this.setComponent(component, parsed.toPattern()); + return this.setComponent(component, parsed.toPattern(), queue); } //TODO Better documentation needed. @@ -1966,8 +1942,7 @@ public class Plot { * Retrieve the biome of the plot. */ public void getBiome(Consumer result) { - this.getCenter(location -> this.worldUtil - .getBiome(location.getWorldName(), location.getX(), location.getZ(), result)); + this.getCenter(location -> this.worldUtil.getBiome(location.getWorldName(), location.getX(), location.getZ(), result)); } //TODO Better documentation needed. @@ -1977,8 +1952,7 @@ public class Plot { */ @Deprecated public BiomeType getBiomeSynchronous() { final Location location = this.getCenterSynchronous(); - return this.worldUtil - .getBiomeSynchronous(location.getWorldName(), location.getX(), location.getZ()); + return this.worldUtil.getBiomeSynchronous(location.getWorldName(), location.getX(), location.getZ()); } /** @@ -2108,19 +2082,20 @@ public class Plot { /** * Remove the east road section of a plot
* - Used when a plot is merged
+ * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. */ - public void removeRoadEast() { - if (this.area.getType() != PlotAreaType.NORMAL - && this.area.getTerrain() == PlotAreaTerrainType.ROAD) { + public void removeRoadEast(@Nullable QueueCoordinator queue) { + if (this.area.getType() != PlotAreaType.NORMAL && this.area.getTerrain() == PlotAreaTerrainType.ROAD) { Plot other = this.getRelative(Direction.EAST); Location bot = other.getBottomAbs(); Location top = this.getTopAbs(); Location pos1 = Location.at(this.getWorldName(), top.getX(), 0, bot.getZ()); Location pos2 = Location.at(this.getWorldName(), bot.getX(), MAX_HEIGHT, top.getZ()); this.regionManager.regenerateRegion(pos1, pos2, true, null); - } else if (this.area.getTerrain() - != PlotAreaTerrainType.ALL) { // no road generated => no road to remove - this.area.getPlotManager().removeRoadEast(this); + } else if (this.area.getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove + this.area.getPlotManager().removeRoadEast(this, queue); } } @@ -2279,10 +2254,8 @@ public class Plot { } } else { TaskManager.runTaskAsync(() -> { - String name = Plot.this.id + "," + Plot.this.area + ',' + - PlayerManager.getName(Plot.this.getOwnerAbs()); - boolean result = schematicHandler.save(value, - Settings.Paths.SCHEMATICS + File.separator + name + ".schem"); + String name = Plot.this.id + "," + Plot.this.area + ',' + PlayerManager.getName(Plot.this.getOwnerAbs()); + boolean result = schematicHandler.save(value, Settings.Paths.SCHEMATICS + File.separator + name + ".schem"); if (whenDone != null) { whenDone.value = result; TaskManager.runTask(whenDone); @@ -2329,8 +2302,7 @@ public class Plot { return false; } Plot other = (Plot) obj; - return this.hashCode() == other.hashCode() && this.id.equals(other.id) - && this.area == other.area; + return this.hashCode() == other.hashCode() && this.id.equals(other.id) && this.area == other.area; } /** @@ -2351,7 +2323,7 @@ public class Plot { * * @return The plot alias */ - public String getAlias() { + @Nonnull public String getAlias() { if (this.settings == null) { return ""; } @@ -2390,8 +2362,9 @@ public class Plot { if (value) { Plot other = this.getRelative(direction).getBasePlot(false); if (!other.equals(this.getBasePlot(false))) { - Plot base = other.id.getY() < this.id.getY() - || other.id.getY() == this.id.getY() && other.id.getX() < this.id.getX() ? other : this.origin; + Plot base = other.id.getY() < this.id.getY() || other.id.getY() == this.id.getY() && other.id.getX() < this.id.getX() ? + other : + this.origin; this.origin.origin = base; other.origin = base; this.origin = base; @@ -2464,8 +2437,7 @@ public class Plot { public boolean canClaim(@Nonnull PlotPlayer player) { PlotCluster cluster = this.getCluster(); if (cluster != null) { - if (!cluster.isAdded(player.getUUID()) && !Permissions - .hasPermission(player, "plots.admin.command.claim")) { + if (!cluster.isAdded(player.getUUID()) && !Permissions.hasPermission(player, "plots.admin.command.claim")) { return false; } } @@ -2479,19 +2451,20 @@ public class Plot { /** * Remove the south road section of a plot
* - Used when a plot is merged
+ * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. */ - public void removeRoadSouth() { - if (this.area.getType() != PlotAreaType.NORMAL - && this.area.getTerrain() == PlotAreaTerrainType.ROAD) { + public void removeRoadSouth(@Nullable QueueCoordinator queue) { + if (this.area.getType() != PlotAreaType.NORMAL && this.area.getTerrain() == PlotAreaTerrainType.ROAD) { Plot other = this.getRelative(Direction.SOUTH); Location bot = other.getBottomAbs(); Location top = this.getTopAbs(); Location pos1 = Location.at(this.getWorldName(), bot.getX(), 0, top.getZ()); Location pos2 = Location.at(this.getWorldName(), top.getX(), MAX_HEIGHT, bot.getZ()); this.regionManager.regenerateRegion(pos1, pos2, true, null); - } else if (this.area.getTerrain() - != PlotAreaTerrainType.ALL) { // no road generated => no road to remove - this.getManager().removeRoadSouth(this); + } else if (this.area.getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove + this.getManager().removeRoadSouth(this, queue); } } @@ -2510,12 +2483,12 @@ public class Plot { return false; } Set connected = this.getConnectedPlots(); - HashSet merged = - connected.stream().map(Plot::getId).collect(Collectors.toCollection(HashSet::new)); + HashSet merged = connected.stream().map(Plot::getId).collect(Collectors.toCollection(HashSet::new)); ArrayDeque frontier = new ArrayDeque<>(connected); Plot current; boolean toReturn = false; HashSet visited = new HashSet<>(); + QueueCoordinator queue = getArea().getQueue(); while ((current = frontier.poll()) != null && max >= 0) { if (visited.contains(current)) { continue; @@ -2524,11 +2497,9 @@ public class Plot { Set plots; if ((dir == Direction.ALL || dir == Direction.NORTH) && !getMerged(Direction.NORTH)) { Plot other = current.getRelative(Direction.NORTH); - if (other != null && other.isOwner(uuid) && ( - other.getBasePlot(false).equals(current.getBasePlot(false)) - || (plots = other.getConnectedPlots()).size() <= max && frontier - .addAll(plots) && (max -= plots.size()) != -1)) { - current.mergePlot(other, removeRoads); + if (other != null && other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) + || (plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1)) { + current.mergePlot(other, removeRoads, queue); merged.add(current.getId()); merged.add(other.getId()); toReturn = true; @@ -2537,18 +2508,15 @@ public class Plot { ArrayList ids = new ArrayList<>(); ids.add(current.getId()); ids.add(other.getId()); - this.getManager().finishPlotMerge(ids); + this.getManager().finishPlotMerge(ids, queue); } } } - if (max >= 0 && (dir == Direction.ALL || dir == Direction.EAST) && !current - .getMerged(Direction.EAST)) { + if (max >= 0 && (dir == Direction.ALL || dir == Direction.EAST) && !current.getMerged(Direction.EAST)) { Plot other = current.getRelative(Direction.EAST); - if (other != null && other.isOwner(uuid) && ( - other.getBasePlot(false).equals(current.getBasePlot(false)) - || (plots = other.getConnectedPlots()).size() <= max && frontier - .addAll(plots) && (max -= plots.size()) != -1)) { - current.mergePlot(other, removeRoads); + if (other != null && other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) + || (plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1)) { + current.mergePlot(other, removeRoads, queue); merged.add(current.getId()); merged.add(other.getId()); toReturn = true; @@ -2557,18 +2525,15 @@ public class Plot { ArrayList ids = new ArrayList<>(); ids.add(current.getId()); ids.add(other.getId()); - this.getManager().finishPlotMerge(ids); + this.getManager().finishPlotMerge(ids, queue); } } } - if (max >= 0 && (dir == Direction.ALL || dir == Direction.SOUTH) && !getMerged( - Direction.SOUTH)) { + if (max >= 0 && (dir == Direction.ALL || dir == Direction.SOUTH) && !getMerged(Direction.SOUTH)) { Plot other = current.getRelative(Direction.SOUTH); - if (other != null && other.isOwner(uuid) && ( - other.getBasePlot(false).equals(current.getBasePlot(false)) - || (plots = other.getConnectedPlots()).size() <= max && frontier - .addAll(plots) && (max -= plots.size()) != -1)) { - current.mergePlot(other, removeRoads); + if (other != null && other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) + || (plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1)) { + current.mergePlot(other, removeRoads, queue); merged.add(current.getId()); merged.add(other.getId()); toReturn = true; @@ -2577,18 +2542,15 @@ public class Plot { ArrayList ids = new ArrayList<>(); ids.add(current.getId()); ids.add(other.getId()); - this.getManager().finishPlotMerge(ids); + this.getManager().finishPlotMerge(ids, queue); } } } - if (max >= 0 && (dir == Direction.ALL || dir == Direction.WEST) && !getMerged( - Direction.WEST)) { + if (max >= 0 && (dir == Direction.ALL || dir == Direction.WEST) && !getMerged(Direction.WEST)) { Plot other = current.getRelative(Direction.WEST); - if (other != null && other.isOwner(uuid) && ( - other.getBasePlot(false).equals(current.getBasePlot(false)) - || (plots = other.getConnectedPlots()).size() <= max && frontier - .addAll(plots) && (max -= plots.size()) != -1)) { - current.mergePlot(other, removeRoads); + if (other != null && other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) + || (plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1)) { + current.mergePlot(other, removeRoads, queue); merged.add(current.getId()); merged.add(other.getId()); toReturn = true; @@ -2597,10 +2559,13 @@ public class Plot { ArrayList ids = new ArrayList<>(); ids.add(current.getId()); ids.add(other.getId()); - this.getManager().finishPlotMerge(ids); + this.getManager().finishPlotMerge(ids, queue); } } } + if (queue.size() > 0) { + queue.enqueue(); + } } return toReturn; } @@ -2615,8 +2580,7 @@ public class Plot { final FlagContainer flagContainer1 = this.getFlagContainer(); final FlagContainer flagContainer2 = plot.getFlagContainer(); if (!flagContainer1.equals(flagContainer2)) { - boolean greater = - flagContainer1.getFlagMap().size() > flagContainer2.getFlagMap().size(); + boolean greater = flagContainer1.getFlagMap().size() > flagContainer2.getFlagMap().size(); if (greater) { flagContainer1.addAll(flagContainer2.getFlagMap().values()); } else { @@ -2657,17 +2621,18 @@ public class Plot { /** * Remove the SE road (only effects terrain) + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. */ - public void removeRoadSouthEast() { - if (this.area.getType() != PlotAreaType.NORMAL - && this.area.getTerrain() == PlotAreaTerrainType.ROAD) { + public void removeRoadSouthEast(@Nullable QueueCoordinator queue) { + if (this.area.getType() != PlotAreaType.NORMAL && this.area.getTerrain() == PlotAreaTerrainType.ROAD) { Plot other = this.getRelative(1, 1); Location pos1 = this.getTopAbs().add(1, 0, 1).withY(0); Location pos2 = other.getBottomAbs().subtract(1, 0, 1).withY(MAX_HEIGHT); this.regionManager.regenerateRegion(pos1, pos2, true, null); - } else if (this.area.getTerrain() - != PlotAreaTerrainType.ALL) { // no road generated => no road to remove - this.area.getPlotManager().removeRoadSouthEast(this); + } else if (this.area.getTerrain() != PlotAreaTerrainType.ALL) { // no road generated => no road to remove + this.area.getPlotManager().removeRoadSouthEast(this, queue); } } @@ -2854,14 +2819,12 @@ public class Plot { PlotId top = PlotId.of(current.getId().getX(), current.getId().getY()); while (merge) { merge = false; - List ids = Lists.newArrayList((Iterable) - PlotId.PlotRangeIterator.range(PlotId.of(bot.getX(), bot.getY() - 1), - PlotId.of(top.getX(), bot.getY() - 1))); + List ids = Lists.newArrayList((Iterable) PlotId.PlotRangeIterator + .range(PlotId.of(bot.getX(), bot.getY() - 1), PlotId.of(top.getX(), bot.getY() - 1))); boolean tmp = true; for (PlotId id : ids) { Plot plot = this.area.getPlotAbs(id); - if (plot == null || !plot.getMerged(Direction.SOUTH) || visited - .contains(plot.getId())) { + if (plot == null || !plot.getMerged(Direction.SOUTH) || visited.contains(plot.getId())) { tmp = false; } } @@ -2869,14 +2832,12 @@ public class Plot { merge = true; bot = PlotId.of(bot.getX(), bot.getY() - 1); } - ids = Lists.newArrayList((Iterable) - PlotId.PlotRangeIterator.range(PlotId.of(top.getX() + 1, bot.getY()), - PlotId.of(top.getX() + 1, top.getY()))); + ids = Lists.newArrayList((Iterable) PlotId.PlotRangeIterator + .range(PlotId.of(top.getX() + 1, bot.getY()), PlotId.of(top.getX() + 1, top.getY()))); tmp = true; for (PlotId id : ids) { Plot plot = this.area.getPlotAbs(id); - if (plot == null || !plot.getMerged(Direction.WEST) || visited - .contains(plot.getId())) { + if (plot == null || !plot.getMerged(Direction.WEST) || visited.contains(plot.getId())) { tmp = false; } } @@ -2884,14 +2845,12 @@ public class Plot { merge = true; top = PlotId.of(top.getX() + 1, top.getY()); } - ids = Lists.newArrayList((Iterable) - PlotId.PlotRangeIterator.range(PlotId.of(bot.getX(), top.getY() + 1), - PlotId.of(top.getX(), top.getY() + 1))); + ids = Lists.newArrayList((Iterable) PlotId.PlotRangeIterator + .range(PlotId.of(bot.getX(), top.getY() + 1), PlotId.of(top.getX(), top.getY() + 1))); tmp = true; for (PlotId id : ids) { Plot plot = this.area.getPlotAbs(id); - if (plot == null || !plot.getMerged(Direction.NORTH) || visited - .contains(plot.getId())) { + if (plot == null || !plot.getMerged(Direction.NORTH) || visited.contains(plot.getId())) { tmp = false; } } @@ -2899,14 +2858,12 @@ public class Plot { merge = true; top = PlotId.of(top.getX(), top.getY() + 1); } - ids = Lists.newArrayList((Iterable) - PlotId.PlotRangeIterator.range(PlotId.of(bot.getX() - 1, bot.getY()), - PlotId.of(bot.getX() - 1, top.getY()))); + ids = Lists.newArrayList((Iterable) PlotId.PlotRangeIterator + .range(PlotId.of(bot.getX() - 1, bot.getY()), PlotId.of(bot.getX() - 1, top.getY()))); tmp = true; for (PlotId id : ids) { Plot plot = this.area.getPlotAbs(id); - if (plot == null || !plot.getMerged(Direction.EAST) || visited - .contains(plot.getId())) { + if (plot == null || !plot.getMerged(Direction.EAST) || visited.contains(plot.getId())) { tmp = false; } } @@ -2917,8 +2874,7 @@ public class Plot { } Location gtopabs = this.area.getPlotAbs(top).getTopAbs(); Location gbotabs = this.area.getPlotAbs(bot).getBottomAbs(); - visited.addAll(Lists.newArrayList((Iterable) - PlotId.PlotRangeIterator.range(bot, top))); + visited.addAll(Lists.newArrayList((Iterable) PlotId.PlotRangeIterator.range(bot, top))); for (int x = bot.getX(); x <= top.getX(); x++) { Plot plot = this.area.getPlotAbs(PlotId.of(x, top.getY())); if (plot.getMerged(Direction.SOUTH)) { @@ -2927,8 +2883,7 @@ public class Plot { Location botabs = plot.getBottomAbs(); Location topabs = plot.getTopAbs(); BlockVector3 pos1 = BlockVector3.at(botabs.getX(), 0, topabs.getZ() + 1); - BlockVector3 pos2 = - BlockVector3.at(topabs.getX(), Plot.MAX_HEIGHT - 1, toploc.getZ()); + BlockVector3 pos2 = BlockVector3.at(topabs.getX(), Plot.MAX_HEIGHT - 1, toploc.getZ()); regions.add(new CuboidRegion(pos1, pos2)); if (plot.getMerged(Direction.SOUTHEAST)) { pos1 = BlockVector3.at(topabs.getX() + 1, 0, topabs.getZ() + 1); @@ -2947,8 +2902,7 @@ public class Plot { Location botabs = plot.getBottomAbs(); Location topabs = plot.getTopAbs(); BlockVector3 pos1 = BlockVector3.at(topabs.getX() + 1, 0, botabs.getZ()); - BlockVector3 pos2 = - BlockVector3.at(toploc.getX(), Plot.MAX_HEIGHT - 1, topabs.getZ()); + BlockVector3 pos2 = BlockVector3.at(toploc.getX(), Plot.MAX_HEIGHT - 1, topabs.getZ()); regions.add(new CuboidRegion(pos1, pos2)); if (plot.getMerged(Direction.SOUTHEAST)) { pos1 = BlockVector3.at(topabs.getX() + 1, 0, topabs.getZ() + 1); @@ -2959,8 +2913,7 @@ public class Plot { } } BlockVector3 pos1 = BlockVector3.at(gbotabs.getX(), 0, gbotabs.getZ()); - BlockVector3 pos2 = - BlockVector3.at(gtopabs.getX(), Plot.MAX_HEIGHT - 1, gtopabs.getZ()); + BlockVector3 pos2 = BlockVector3.at(gtopabs.getX(), Plot.MAX_HEIGHT - 1, gtopabs.getZ()); regions.add(new CuboidRegion(pos1, pos2)); } return regions; @@ -2976,9 +2929,8 @@ public class Plot { CuboidRegion max = null; double area = Double.NEGATIVE_INFINITY; for (CuboidRegion region : regions) { - double current = - (region.getMaximumPoint().getX() - (double) region.getMinimumPoint().getX() + 1) * ( - region.getMaximumPoint().getZ() - (double) region.getMinimumPoint().getZ() + 1); + double current = (region.getMaximumPoint().getX() - (double) region.getMinimumPoint().getX() + 1) * ( + region.getMaximumPoint().getZ() - (double) region.getMinimumPoint().getZ() + 1); if (current > area) { max = region; area = current; @@ -3014,7 +2966,8 @@ public class Plot { player.sendMessage(caption, plotTemplate, messageTemplate); } } - } catch (final Exception ignored) {} + } catch (final Exception ignored) { + } } /** @@ -3025,8 +2978,7 @@ public class Plot { public List getAllCorners() { Area area = new Area(); for (CuboidRegion region : this.getRegions()) { - Rectangle2D rect = new Rectangle2D.Double(region.getMinimumPoint().getX() - 0.6, - region.getMinimumPoint().getZ() - 0.6, + Rectangle2D rect = new Rectangle2D.Double(region.getMinimumPoint().getX() - 0.6, region.getMinimumPoint().getZ() - 0.6, region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + 1.2, region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + 1.2); Area rectArea = new Area(rect); @@ -3062,12 +3014,9 @@ public class Plot { * @param cause the cause of the teleport * @param resultConsumer Called with the result of the teleportation */ - public void teleportPlayer(final PlotPlayer player, TeleportCause cause, - Consumer resultConsumer) { + public void teleportPlayer(final PlotPlayer player, TeleportCause cause, Consumer resultConsumer) { Plot plot = this.getBasePlot(false); - Result result = - this.eventDispatcher.callTeleport(player, player.getLocation(), plot) - .getEventResult(); + Result result = this.eventDispatcher.callTeleport(player, player.getLocation(), plot).getEventResult(); if (result == Result.DENY) { player.sendMessage( TranslatableCaption.of("events.event_denied"), @@ -3096,7 +3045,8 @@ public class Plot { try { player.sendMessage(TranslatableCaption.of("teleport.teleported_to_plot")); player.teleport(location, cause); - } catch (final Exception ignored) {} + } catch (final Exception ignored) { + } }, TaskTime.seconds(Settings.Teleport.DELAY)); resultConsumer.accept(true); }; @@ -3117,12 +3067,11 @@ public class Plot { return false; } if (!isMerged()) { - return PlotSquared.platform().getPlayerManager() - .getPlayerIfExists(Objects.requireNonNull(this.getOwnerAbs())) != null; + return PlotSquared.platform().getPlayerManager().getPlayerIfExists(Objects.requireNonNull(this.getOwnerAbs())) != null; } for (final Plot current : getConnectedPlots()) { - if (current.hasOwner() && PlotSquared.platform().getPlayerManager() - .getPlayerIfExists(Objects.requireNonNull(current.getOwnerAbs())) != null) { + if (current.hasOwner() + && PlotSquared.platform().getPlayerManager().getPlayerIfExists(Objects.requireNonNull(current.getOwnerAbs())) != null) { return true; } } @@ -3138,19 +3087,17 @@ public class Plot { * @param blocks Pattern to use the generation * @return True if the component was set successfully */ - public boolean setComponent(String component, Pattern blocks) { - PlotComponentSetEvent event = - this.eventDispatcher.callComponentSet(this, component, blocks); + public boolean setComponent(String component, Pattern blocks, @Nullable QueueCoordinator queue) { + PlotComponentSetEvent event = this.eventDispatcher.callComponentSet(this, component, blocks); component = event.getComponent(); blocks = event.getPattern(); - return this.getManager().setComponent(this.getId(), component, blocks); + return this.getManager().setComponent(this.getId(), component, blocks, queue); } public int getDistanceFromOrigin() { Location bot = getManager().getPlotBottomLocAbs(id); Location top = getManager().getPlotTopLocAbs(id); - return Math.max(Math.max(Math.abs(bot.getX()), Math.abs(bot.getZ())), - Math.max(Math.abs(top.getX()), Math.abs(top.getZ()))); + return Math.max(Math.max(Math.abs(bot.getX()), Math.abs(bot.getZ())), Math.max(Math.abs(top.getX()), Math.abs(top.getZ()))); } /** @@ -3170,10 +3117,10 @@ public class Plot { /** * Merges two plots.
- Assumes plots are directly next to each other
- saves to DB * - * @param lesserPlot - * @param removeRoads + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. */ - public void mergePlot(Plot lesserPlot, boolean removeRoads) { + public void mergePlot(Plot lesserPlot, boolean removeRoads, @Nullable QueueCoordinator queue) { Plot greaterPlot = this; lesserPlot.removeSign(); if (lesserPlot.getId().getX() == greaterPlot.getId().getX()) { @@ -3190,14 +3137,14 @@ public class Plot { lesserPlot.mergeData(greaterPlot); if (removeRoads) { //lesserPlot.removeSign(); - lesserPlot.removeRoadSouth(); + lesserPlot.removeRoadSouth(queue); Plot diagonal = greaterPlot.getRelative(Direction.EAST); if (diagonal.getMerged(Direction.NORTHWEST)) { - lesserPlot.removeRoadSouthEast(); + lesserPlot.removeRoadSouthEast(queue); } Plot below = greaterPlot.getRelative(Direction.WEST); if (below.getMerged(Direction.NORTHEAST)) { - below.getRelative(Direction.NORTH).removeRoadSouthEast(); + below.getRelative(Direction.NORTH).removeRoadSouthEast(queue); } } } @@ -3217,17 +3164,16 @@ public class Plot { //lesserPlot.removeSign(); Plot diagonal = greaterPlot.getRelative(Direction.SOUTH); if (diagonal.getMerged(Direction.NORTHWEST)) { - lesserPlot.removeRoadSouthEast(); + lesserPlot.removeRoadSouthEast(queue); } - lesserPlot.removeRoadEast(); + lesserPlot.removeRoadEast(queue); } Plot below = greaterPlot.getRelative(Direction.NORTH); if (below.getMerged(Direction.SOUTHWEST)) { - below.getRelative(Direction.WEST).removeRoadSouthEast(); + below.getRelative(Direction.WEST).removeRoadSouthEast(queue); } } } - } /** @@ -3238,10 +3184,8 @@ public class Plot { * @param allowSwap whether to swap plots * @return success */ - public CompletableFuture move(final Plot destination, final Runnable whenDone, - boolean allowSwap) { - final PlotId offset = PlotId.of(destination.getId().getX() - this.getId().getX(), - destination.getId().getY() - this.getId().getY()); + public CompletableFuture move(final Plot destination, final Runnable whenDone, boolean allowSwap) { + final PlotId offset = PlotId.of(destination.getId().getX() - this.getId().getX(), destination.getId().getY() - this.getId().getY()); Location db = destination.getBottomAbs(); Location ob = this.getBottomAbs(); final int offsetX = db.getX() - ob.getX(); @@ -3308,8 +3252,7 @@ public class Plot { Location pos1 = corners[0]; Location pos2 = corners[1]; Location pos3 = pos1.add(offsetX, 0, offsetZ).withWorld(destination.getWorldName()); - Location pos4 = pos2.add(offsetX, 0, offsetZ).withWorld(destination.getWorldName()); - regionManager.swap(pos1, pos2, pos3, pos4, this); + regionManager.swap(pos1, pos2, pos3, this); } } }.run(); @@ -3318,11 +3261,14 @@ public class Plot { @Override public void run() { if (regions.isEmpty()) { Plot plot = destination.getRelative(0, 0); - Plot originPlot = originArea - .getPlotAbs(PlotId.of(plot.id.getX() - offset.getX(), plot.id.getY() - offset.getY())); + Plot originPlot = originArea.getPlotAbs(PlotId.of(plot.id.getX() - offset.getX(), plot.id.getY() - offset.getY())); final Runnable clearDone = () -> { + QueueCoordinator queue = getArea().getQueue(); for (final Plot current : plot.getConnectedPlots()) { - getManager().claimPlot(current); + getManager().claimPlot(current, queue); + } + if (queue.size() > 0) { + queue.enqueue(); } plot.setSign(); TaskManager.runTask(whenDone); @@ -3356,8 +3302,7 @@ public class Plot { * @return */ public boolean copy(final Plot destination, final Runnable whenDone) { - PlotId offset = PlotId.of(destination.getId().getX() - this.getId().getX(), - destination.getId().getY() - this.getId().getY()); + PlotId offset = PlotId.of(destination.getId().getX() - this.getId().getX(), destination.getId().getY() - this.getId().getY()); Location db = destination.getBottomAbs(); Location ob = this.getBottomAbs(); final int offsetX = db.getX() - ob.getX(); @@ -3386,8 +3331,7 @@ public class Plot { other.getFlagContainer().addAll(plot.getFlagContainer().getFlagMap().values()); // Update the database for (final PlotFlag flag : existingFlags) { - final PlotFlag newFlag = - other.getFlagContainer().queryLocal(flag.getClass()); + final PlotFlag newFlag = other.getFlagContainer().queryLocal(flag.getClass()); if (other.getFlagContainer().queryLocal(flag.getClass()) == null) { DBFunc.removeFlag(other, flag); } else { @@ -3422,8 +3366,12 @@ public class Plot { Runnable run = new Runnable() { @Override public void run() { if (regions.isEmpty()) { + QueueCoordinator queue = getArea().getQueue(); for (Plot current : getConnectedPlots()) { - destination.getManager().claimPlot(current); + destination.getManager().claimPlot(current, queue); + } + if (queue.size() > 0) { + queue.enqueue(); } destination.setSign(); TaskManager.runTask(whenDone); @@ -3433,7 +3381,7 @@ public class Plot { Location[] corners = getCorners(getWorldName(), region); Location pos1 = corners[0]; Location pos2 = corners[1]; - Location newPos = pos1 .add(offsetX, 0, offsetZ).withWorld(destination.getWorldName()); + Location newPos = pos1.add(offsetX, 0, offsetZ).withWorld(destination.getWorldName()); regionManager.copyRegion(pos1, pos2, newPos, this); } }; diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java index 14abb33b8..dc2069368 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java @@ -27,6 +27,7 @@ package com.plotsquared.core.plot; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.plotsquared.core.PlotSquared; import com.google.common.collect.Lists; import com.plotsquared.core.collection.QuadMap; import com.plotsquared.core.configuration.ConfigurationNode; @@ -55,7 +56,7 @@ import com.plotsquared.core.plot.flag.PlotFlag; import com.plotsquared.core.plot.flag.implementations.DoneFlag; import com.plotsquared.core.plot.flag.types.DoubleFlag; import com.plotsquared.core.queue.GlobalBlockQueue; -import com.plotsquared.core.queue.LocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.Expression; import com.plotsquared.core.util.MathMan; @@ -183,8 +184,8 @@ public abstract class PlotArea { @Nonnull protected abstract PlotManager createManager(); - public LocalBlockQueue getQueue(final boolean autoQueue) { - return this.globalBlockQueue.getNewQueue(worldName, autoQueue); + public QueueCoordinator getQueue() { + return this.globalBlockQueue.getNewQueue(PlotSquared.platform().getWorldUtil().getWeWorld(worldName)); } /** @@ -947,7 +948,8 @@ public abstract class PlotArea { final PlotId pos2 = plotIds.get(plotIds.size() - 1); final PlotManager manager = getPlotManager(); - manager.startPlotMerge(plotIds); + QueueCoordinator queue = getQueue(); + manager.startPlotMerge(plotIds, queue); final Set trusted = new HashSet<>(); final Set members = new HashSet<>(); final Set denied = new HashSet<>(); @@ -982,24 +984,25 @@ public abstract class PlotArea { if (ly) { if (!plot.getMerged(Direction.EAST) || !plot.getMerged(Direction.SOUTH)) { if (removeRoads) { - plot.removeRoadSouthEast(); + plot.removeRoadSouthEast(queue); } } } if (!plot.getMerged(Direction.EAST)) { plot2 = plot.getRelative(1, 0); - plot.mergePlot(plot2, removeRoads); + plot.mergePlot(plot2, removeRoads, queue); } } if (ly) { if (!plot.getMerged(Direction.SOUTH)) { plot2 = plot.getRelative(0, 1); - plot.mergePlot(plot2, removeRoads); + plot.mergePlot(plot2, removeRoads, queue); } } } } - manager.finishPlotMerge(plotIds); + manager.finishPlotMerge(plotIds, queue); + queue.enqueue(); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotItemStack.java b/Core/src/main/java/com/plotsquared/core/plot/PlotItemStack.java index 56c691fdc..bb733868d 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotItemStack.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotItemStack.java @@ -43,7 +43,7 @@ public class PlotItemStack { * @param amount Amount of items in the stack * @param name The display name of the item stack * @param lore The item stack lore - * @deprecated Use {@link PlotItemStack(String, int, String, String...)} + * @deprecated Use {@link #PlotItemStack(String, int, String, String...)} */ @Deprecated public PlotItemStack(final int id, final short data, final int amount, final String name, final String... lore) { diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotManager.java b/Core/src/main/java/com/plotsquared/core/plot/PlotManager.java index 236eeee0f..187e29ffd 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotManager.java @@ -28,9 +28,12 @@ package com.plotsquared.core.plot; import com.plotsquared.core.command.Template; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.location.Location; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.FileBytes; import com.sk89q.worldedit.function.pattern.Pattern; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.IOException; import java.util.Collections; import java.util.HashSet; @@ -40,7 +43,7 @@ public abstract class PlotManager { private final PlotArea plotArea; - public PlotManager(PlotArea plotArea) { + public PlotManager(@Nonnull PlotArea plotArea) { this.plotArea = plotArea; } @@ -53,19 +56,22 @@ public abstract class PlotManager { public abstract PlotId getPlotId(int x, int y, int z); // If you have a circular plot, just return the corner if it were a square - public abstract Location getPlotBottomLocAbs(PlotId plotId); + public abstract Location getPlotBottomLocAbs(@Nonnull PlotId plotId); // the same applies here - public abstract Location getPlotTopLocAbs(PlotId plotId); + public abstract Location getPlotTopLocAbs(@Nonnull PlotId plotId); - /* - * Plot clearing (return false if you do not support some method) + public abstract boolean clearPlot(@Nonnull Plot plot, @Nullable Runnable whenDone, @Nullable QueueCoordinator queue); + + public abstract boolean claimPlot(@Nonnull Plot plot, @Nullable QueueCoordinator queue); + + /** + * Completes block changes associated with plot unclaim. + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. */ - public abstract boolean clearPlot(Plot plot, Runnable whenDone); - - public abstract boolean claimPlot(Plot plot); - - public abstract boolean unClaimPlot(Plot plot, Runnable whenDone); + public abstract boolean unClaimPlot(@Nonnull Plot plot, @Nullable Runnable whenDone, @Nullable QueueCoordinator queue); /** * Retrieves the location of where a sign should be for a plot. @@ -73,44 +79,98 @@ public abstract class PlotManager { * @param plot The plot * @return The location where a sign should be */ - public abstract Location getSignLoc(Plot plot); + public abstract Location getSignLoc(@Nonnull Plot plot); /* * Plot set functions (return false if you do not support the specific set * method). */ - public abstract String[] getPlotComponents(PlotId plotId); + public abstract String[] getPlotComponents(@Nonnull PlotId plotId); - public abstract boolean setComponent(PlotId plotId, String component, Pattern blocks); - - /* - * PLOT MERGING (return false if your generator does not support plot - * merging). + /** + * Set the specified components to the specified Pattern on the specified plot. + * + * @param component FLOOR, WALL, AIR, MAIN, MIDDLE, OUTLINE, BORDER, ALL (floor, air and main). + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. */ - public abstract boolean createRoadEast(Plot plot); + public abstract boolean setComponent(@Nonnull PlotId plotId, + @Nonnull String component, + @Nonnull Pattern blocks, + @Nullable QueueCoordinator queue); - public abstract boolean createRoadSouth(Plot plot); + /** + * Create the road east of the plot (not schematic-based) + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public abstract boolean createRoadEast(@Nonnull Plot plot, @Nullable QueueCoordinator queue); - public abstract boolean createRoadSouthEast(Plot plot); + /** + * Create the road south of the plot (not schematic-based) + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public abstract boolean createRoadSouth(@Nonnull Plot plot, @Nullable QueueCoordinator queue); - public abstract boolean removeRoadEast(Plot plot); + /** + * Create the south-east corner of the road (intersection, not schematic-based) + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public abstract boolean createRoadSouthEast(@Nonnull Plot plot, @Nullable QueueCoordinator queue); - public abstract boolean removeRoadSouth(Plot plot); + /** + * Replace the road to the east of the plot with standard plot blocks (for when merging plots) + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public abstract boolean removeRoadEast(@Nonnull Plot plot, @Nullable QueueCoordinator queue); - public abstract boolean removeRoadSouthEast(Plot plot); + /** + * Replace the road to the south of the plot with standard plot blocks (for when merging plots) + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public abstract boolean removeRoadSouth(@Nonnull Plot plot, @Nullable QueueCoordinator queue); - public abstract boolean startPlotMerge(List plotIds); + /** + * Replace the road to the south east of the plot (intersection) with standard plot blocks (for when merging plots) + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public abstract boolean removeRoadSouthEast(@Nonnull Plot plot, @Nullable QueueCoordinator queue); - public abstract boolean startPlotUnlink(List plotIds); + public abstract boolean startPlotMerge(@Nonnull List plotIds, @Nullable QueueCoordinator queue); - public abstract boolean finishPlotMerge(List plotIds); + public abstract boolean startPlotUnlink(@Nonnull List plotIds, @Nullable QueueCoordinator queue); - public abstract boolean finishPlotUnlink(List plotIds); + /** + * Finishing off plot merging by adding in the walls surrounding the plot (OPTIONAL)(UNFINISHED). + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + * @return false if part if the merge failed, otherwise true if successful. + */ + public abstract boolean finishPlotMerge(@Nonnull List plotIds, @Nullable QueueCoordinator queue); + + /** + * Finished off an unlink by resetting the top wall block for unlinked plots + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + */ + public abstract boolean finishPlotUnlink(@Nonnull List plotIds, @Nullable QueueCoordinator queue); public void exportTemplate() throws IOException { - HashSet files = new HashSet<>(Collections.singletonList( - new FileBytes(Settings.Paths.TEMPLATES + "/tmp-data.yml", - Template.getBytes(plotArea)))); + HashSet files = + new HashSet<>(Collections.singletonList(new FileBytes(Settings.Paths.TEMPLATES + "/tmp-data.yml", Template.getBytes(plotArea)))); Template.zipAll(plotArea.getWorldName(), files); } @@ -121,15 +181,17 @@ public abstract class PlotManager { /** * Sets all the blocks along all the plot walls to their correct state (claimed or unclaimed). * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. * @return true if the wall blocks were successfully set */ - public boolean regenerateAllPlotWalls() { + public boolean regenerateAllPlotWalls(@Nullable QueueCoordinator queue) { boolean success = true; for (Plot plot : plotArea.getPlots()) { if (plot.hasOwner()) { - success &= claimPlot(plot); + success &= claimPlot(plot, queue); } else { - success &= unClaimPlot(plot, null); + success &= unClaimPlot(plot, null, queue); } } return success; diff --git a/Core/src/main/java/com/plotsquared/core/plot/flag/GlobalFlagContainer.java b/Core/src/main/java/com/plotsquared/core/plot/flag/GlobalFlagContainer.java index b321fa1f2..f243e25ae 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/flag/GlobalFlagContainer.java +++ b/Core/src/main/java/com/plotsquared/core/plot/flag/GlobalFlagContainer.java @@ -25,6 +25,7 @@ */ package com.plotsquared.core.plot.flag; +import com.google.common.base.Preconditions; import com.plotsquared.core.plot.flag.implementations.AnalysisFlag; import com.plotsquared.core.plot.flag.implementations.AnimalAttackFlag; import com.plotsquared.core.plot.flag.implementations.AnimalCapFlag; @@ -113,7 +114,13 @@ import java.util.Map; public final class GlobalFlagContainer extends FlagContainer { - private static final GlobalFlagContainer instance = new GlobalFlagContainer(); + private static GlobalFlagContainer instance; + + public static void setup() { + Preconditions.checkState(instance == null, "Cannot setup the container twice"); + instance = new GlobalFlagContainer(); + } + private static Map> stringClassMap; private GlobalFlagContainer() { @@ -123,6 +130,7 @@ public final class GlobalFlagContainer extends FlagContainer { } }); stringClassMap = new HashMap<>(); + // Register all default flags here // Boolean flags this.addFlag(ExplosionFlag.EXPLOSION_FALSE); diff --git a/Core/src/main/java/com/plotsquared/core/plot/flag/PlotFlag.java b/Core/src/main/java/com/plotsquared/core/plot/flag/PlotFlag.java index 26e914558..7b91edfd3 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/flag/PlotFlag.java +++ b/Core/src/main/java/com/plotsquared/core/plot/flag/PlotFlag.java @@ -144,8 +144,7 @@ public abstract class PlotFlag> { } /** - * Get the category this flag belongs to. Usually a caption from - * {@link Captions} + * Get the category this flag belongs to. Usually a caption from {@link com.plotsquared.core.configuration.caption.TranslatableCaption} *

* These categories are used to categorize the flags when outputting * flag lists to players. diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotManager.java b/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotManager.java index 82aaa7a3f..cffa305a1 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotManager.java @@ -31,11 +31,14 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.PlotManager; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.FileUtils; import com.plotsquared.core.util.task.TaskManager; import com.sk89q.worldedit.function.pattern.Pattern; +import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; import java.util.List; @@ -53,15 +56,15 @@ public class SinglePlotManager extends PlotManager { return PlotId.of(0, 0); } - @Override public Location getPlotBottomLocAbs(@Nonnull final PlotId plotId) { + @Override public Location getPlotBottomLocAbs(@Nonnull final @NotNull PlotId plotId) { return Location.at(plotId.toCommaSeparatedString(), -30000000, 0, -30000000); } - @Override public Location getPlotTopLocAbs(@Nonnull final PlotId plotId) { + @Override public Location getPlotTopLocAbs(@Nonnull final @NotNull PlotId plotId) { return Location.at(plotId.toCommaSeparatedString(), 30000000, 0, 30000000); } - @Override public boolean clearPlot(Plot plot, final Runnable whenDone) { + @Override public boolean clearPlot(@NotNull Plot plot, final Runnable whenDone, @Nullable QueueCoordinator queue) { PlotSquared.platform().getSetupUtils().unload(plot.getWorldName(), false); final File worldFolder = new File(PlotSquared.platform().getWorldContainer(), plot.getWorldName()); TaskManager.getPlatformImplementation().taskAsync(() -> { @@ -73,71 +76,72 @@ public class SinglePlotManager extends PlotManager { return true; } - @Override public boolean claimPlot(Plot plot) { + @Override public boolean claimPlot(@NotNull Plot plot, @Nullable QueueCoordinator queue) { // TODO return true; } - @Override public boolean unClaimPlot(Plot plot, Runnable whenDone) { + @Override public boolean unClaimPlot(@NotNull Plot plot, Runnable whenDone, @Nullable QueueCoordinator queue) { if (whenDone != null) { whenDone.run(); } return true; } - @Override public Location getSignLoc(Plot plot) { + @Override public Location getSignLoc(@NotNull Plot plot) { return null; } - @Override public String[] getPlotComponents(PlotId plotId) { + @Override public String[] getPlotComponents(@NotNull PlotId plotId) { return new String[0]; } - @Override public boolean setComponent(PlotId plotId, String component, Pattern blocks) { + @Override + public boolean setComponent(@NotNull PlotId plotId, @NotNull String component, @NotNull Pattern blocks, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean createRoadEast(Plot plot) { + @Override public boolean createRoadEast(@NotNull Plot plot, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean createRoadSouth(Plot plot) { + @Override public boolean createRoadSouth(@NotNull Plot plot, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean createRoadSouthEast(Plot plot) { + @Override public boolean createRoadSouthEast(@NotNull Plot plot, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean removeRoadEast(Plot plot) { + @Override public boolean removeRoadEast(@NotNull Plot plot, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean removeRoadSouth(Plot plot) { + @Override public boolean removeRoadSouth(@NotNull Plot plot, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean removeRoadSouthEast(Plot plot) { + @Override public boolean removeRoadSouthEast(@NotNull Plot plot, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean startPlotMerge(List plotIds) { + @Override public boolean startPlotMerge(@NotNull List plotIds, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean startPlotUnlink(List plotIds) { + @Override public boolean startPlotUnlink(@NotNull List plotIds, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean finishPlotMerge(List plotIds) { + @Override public boolean finishPlotMerge(@NotNull List plotIds, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean finishPlotUnlink(List plotIds) { + @Override public boolean finishPlotUnlink(@NotNull List plotIds, @Nullable QueueCoordinator queue) { return false; } - @Override public boolean regenerateAllPlotWalls() { + @Override public boolean regenerateAllPlotWalls(@Nullable QueueCoordinator queue) { return false; } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/AreaBoundDelegateLocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/AreaBoundDelegateQueueCoordinator.java similarity index 67% rename from Core/src/main/java/com/plotsquared/core/queue/AreaBoundDelegateLocalBlockQueue.java rename to Core/src/main/java/com/plotsquared/core/queue/AreaBoundDelegateQueueCoordinator.java index 7bafdfcfa..028f49223 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/AreaBoundDelegateLocalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/AreaBoundDelegateQueueCoordinator.java @@ -26,6 +26,7 @@ package com.plotsquared.core.queue; import com.plotsquared.core.plot.PlotArea; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; @@ -35,45 +36,64 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; -public class AreaBoundDelegateLocalBlockQueue extends DelegateLocalBlockQueue { +/** + * Queue Coordinator that only sets blocks with the specified PlotArea + */ +public class AreaBoundDelegateQueueCoordinator extends DelegateQueueCoordinator { private final PlotArea area; - public AreaBoundDelegateLocalBlockQueue(@Nonnull final PlotArea area, - @Nullable final LocalBlockQueue parent) { + public AreaBoundDelegateQueueCoordinator(@Nonnull final PlotArea area, @Nullable final QueueCoordinator parent) { super(parent); this.area = Objects.requireNonNull(area); } - @Override public boolean setBlock(int x, int y, int z, BlockState id) { + /** + * Gets the plot area block settings is limited to + */ + public PlotArea getArea() { + return this.area; + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull BlockState id) { if (area.contains(x, z)) { return super.setBlock(x, y, z, id); } return false; } - @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { + @Override public boolean setBlock(int x, int y, int z, @Nonnull BaseBlock id) { if (area.contains(x, z)) { return super.setBlock(x, y, z, id); } return false; } - @Override public boolean setBlock(int x, int y, int z, Pattern pattern) { + @Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) { if (area.contains(x, z)) { return super.setBlock(x, y, z, pattern); } return false; } - @Override public boolean setBiome(int x, int z, BiomeType biome) { + @Override public boolean setBiome(int x, int z, @Nonnull BiomeType biome) { if (area.contains(x, z)) { return super.setBiome(x, z, biome); } return false; } - public PlotArea getArea() { - return this.area; + @Override public boolean setBiome(int x, int y, int z, @Nonnull BiomeType biome) { + if (area.contains(x, z)) { + return super.setBiome(x, y, z, biome); + } + return false; + } + + @Override public boolean setTile(int x, int y, int z, @Nonnull CompoundTag tag) { + if (area.contains(x, z)) { + return super.setTile(x, y, z, tag); + } + return false; } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java deleted file mode 100644 index 487cfaf7a..000000000 --- a/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * 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 . - */ -package com.plotsquared.core.queue; - -import com.plotsquared.core.util.ChunkUtil; -import com.plotsquared.core.util.MathMan; -import com.plotsquared.core.util.PatternUtil; -import com.plotsquared.core.util.task.TaskManager; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; - -import javax.annotation.Nonnull; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.concurrent.ExecutionException; - -public abstract class BasicLocalBlockQueue extends LocalBlockQueue { - - private final String world; - private final ConcurrentHashMap blockChunks = new ConcurrentHashMap<>(); - private final ConcurrentLinkedDeque chunks = new ConcurrentLinkedDeque<>(); - private long modified; - private LocalChunk lastWrappedChunk; - private int lastX = Integer.MIN_VALUE; - private int lastZ = Integer.MIN_VALUE; - private boolean setbiome = false; - - private GlobalBlockQueue globalBlockQueue; - - public BasicLocalBlockQueue(String world) { - super(world); - this.world = world; - this.modified = System.currentTimeMillis(); - } - - public abstract LocalChunk getLocalChunk(int x, int z); - - @Override public abstract BlockState getBlock(int x, int y, int z); - - public abstract void setComponents(LocalChunk lc) - throws ExecutionException, InterruptedException; - - @Override public final String getWorld() { - return world; - } - - @Override public final boolean next() { - lastX = Integer.MIN_VALUE; - lastZ = Integer.MIN_VALUE; - try { - if (this.blockChunks.size() == 0) { - return false; - } - synchronized (blockChunks) { - LocalChunk chunk = chunks.poll(); - if (chunk != null) { - blockChunks.remove(chunk.longHash()); - return this.execute(chunk); - } - } - } catch (Throwable e) { - e.printStackTrace(); - } - return false; - } - - public final boolean execute(@Nonnull LocalChunk lc) - throws ExecutionException, InterruptedException { - this.setComponents(lc); - return true; - } - - @Override public void startSet(boolean parallel) { - // Do nothing - } - - @Override public void endSet(boolean parallel) { - // Do nothing - } - - @Override public final int size() { - return chunks.size(); - } - - @Override public final long getModified() { - return modified; - } - - @Override public final void setModified(long modified) { - this.modified = modified; - } - - @Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) { - return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z)); - } - - @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { - if ((y > 255) || (y < 0)) { - return false; - } - int cx = x >> 4; - int cz = z >> 4; - if (cx != lastX || cz != lastZ) { - lastX = cx; - lastZ = cz; - long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL; - lastWrappedChunk = this.blockChunks.get(pair); - if (lastWrappedChunk == null) { - lastWrappedChunk = this.getLocalChunk(x >> 4, z >> 4); - lastWrappedChunk.setBlock(x & 15, y, z & 15, id); - LocalChunk previous = this.blockChunks.put(pair, lastWrappedChunk); - if (previous == null) { - return chunks.add(lastWrappedChunk); - } - this.blockChunks.put(pair, previous); - lastWrappedChunk = previous; - } - } - lastWrappedChunk.setBlock(x & 15, y, z & 15, id); - return true; - } - - @Override public boolean setBlock(int x, int y, int z, BlockState id) { - // Trying to mix BlockState and BaseBlock leads to all kinds of issues. - // Since BaseBlock has more features than BlockState, simply convert - // all BlockStates to BaseBlocks - return setBlock(x, y, z, id.toBaseBlock()); - } - - @Override public final boolean setBiome(int x, int z, BiomeType biomeType) { - long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL; - LocalChunk result = this.blockChunks.get(pair); - if (result == null) { - result = this.getLocalChunk(x >> 4, z >> 4); - LocalChunk previous = this.blockChunks.put(pair, result); - if (previous != null) { - this.blockChunks.put(pair, previous); - result = previous; - } else { - chunks.add(result); - } - } - result.setBiome(x & 15, z & 15, biomeType); - setbiome = true; - return true; - } - - @Override public final boolean setBiome() { - return setbiome; - } - - public final void setChunk(LocalChunk chunk) { - LocalChunk previous = this.blockChunks.put(chunk.longHash(), chunk); - if (previous != null) { - chunks.remove(previous); - } - chunks.add(chunk); - } - - @Override public void flush() { - this.globalBlockQueue.dequeue(this); - try { - TaskManager.getPlatformImplementation().sync(() -> { - while (next()) { - } - return null; - }); - } catch (final Exception e) { - e.printStackTrace(); - } - } - - - public abstract class LocalChunk { - public final BasicLocalBlockQueue parent; - public final int z; - public final int x; - - public BaseBlock[][] baseblocks; - public BiomeType[][] biomes; - - public LocalChunk(BasicLocalBlockQueue parent, int x, int z) { - this.parent = parent; - this.x = x; - this.z = z; - } - - /** - * Get the parent queue this chunk belongs to - * - * @return - */ - public BasicLocalBlockQueue getParent() { - return parent; - } - - public int getX() { - return x; - } - - public int getZ() { - return z; - } - - public abstract void setBlock(final int x, final int y, final int z, final BaseBlock block); - - public void setBiome(int x, int z, BiomeType biomeType) { - if (this.biomes == null) { - this.biomes = new BiomeType[16][]; - } - BiomeType[] index = this.biomes[x]; - if (index == null) { - index = this.biomes[x] = new BiomeType[16]; - } - index[z] = biomeType; - } - - public long longHash() { - return MathMan.pairInt(x, z); - } - - @Override public int hashCode() { - return MathMan.pair((short) x, (short) z); - } - } - - - public class BasicLocalChunk extends LocalChunk { - - public BasicLocalChunk(BasicLocalBlockQueue parent, int x, int z) { - super(parent, x, z); - baseblocks = new BaseBlock[16][]; - } - - @Override public void setBlock(int x, int y, int z, BaseBlock block) { - this.setInternal(x, y, z, block); - } - - private void setInternal(final int x, final int y, final int z, final BaseBlock baseBlock) { - final int i = y >> 4; - final int j = ChunkUtil.getJ(x, y, z); - BaseBlock[] array = baseblocks[i]; - if (array == null) { - array = (baseblocks[i] = new BaseBlock[4096]); - } - array[j] = baseBlock; - } - } -} diff --git a/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java new file mode 100644 index 000000000..cca1899fe --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/BasicQueueCoordinator.java @@ -0,0 +1,273 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.queue; + +import com.plotsquared.core.util.PatternUtil; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.entity.EntityTypes; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +/** + * Standard block setting queue that allows block setting across numerous chunks, without limits. + */ +public abstract class BasicQueueCoordinator extends QueueCoordinator { + + private final World world; + private final ConcurrentHashMap blockChunks = new ConcurrentHashMap<>(); + private final List readRegion = new ArrayList<>(); + private long modified; + private LocalChunk lastWrappedChunk; + private int lastX = Integer.MIN_VALUE; + private int lastZ = Integer.MIN_VALUE; + private boolean settingBiomes = false; + private boolean settingTiles = false; + private boolean regen = false; + private int[] regenStart; + private int[] regenEnd; + private CuboidRegion regenRegion = null; + private Consumer consumer = null; + private boolean unloadAfter = true; + private Runnable whenDone; + + public BasicQueueCoordinator(@Nonnull World world) { + super(world); + this.world = world; + this.modified = System.currentTimeMillis(); + } + + @Override public abstract BlockState getBlock(int x, int y, int z); + + @Override public final @Nonnull World getWorld() { + return world; + } + + @Override public final int size() { + return blockChunks.size() + readRegion.size(); + } + + @Override public final void setModified(long modified) { + this.modified = modified; + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) { + return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z)); + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull BaseBlock id) { + if ((y > 255) || (y < 0)) { + return false; + } + LocalChunk chunk = getChunk(x >> 4, z >> 4); + chunk.setBlock(x & 15, y, z & 15, id); + return true; + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull BlockState id) { + // Trying to mix BlockState and BaseBlock leads to all kinds of issues. + // Since BaseBlock has more features than BlockState, simply convert + // all BlockStates to BaseBlocks + return setBlock(x, y, z, id.toBaseBlock()); + } + + @Override public boolean setBiome(int x, int z, @Nonnull BiomeType biomeType) { + LocalChunk chunk = getChunk(x >> 4, z >> 4); + for (int y = 0; y < 256; y++) { + chunk.setBiome(x & 15, y, z & 15, biomeType); + } + settingBiomes = true; + return true; + } + + @Override public final boolean setBiome(int x, int y, int z, @Nonnull BiomeType biomeType) { + LocalChunk chunk = getChunk(x >> 4, z >> 4); + chunk.setBiome(x & 15, y, z & 15, biomeType); + settingBiomes = true; + return true; + } + + @Override public boolean isSettingBiomes() { + return this.settingBiomes; + } + + @Override public boolean setTile(int x, int y, int z, @Nonnull CompoundTag tag) { + LocalChunk chunk = getChunk(x >> 4, z >> 4); + chunk.setTile(x, y, z, tag); + settingTiles = true; + return true; + } + + @Override public boolean isSettingTiles() { + return this.settingTiles; + } + + @Override public boolean setEntity(@Nonnull Entity entity) { + if (entity.getState() == null || entity.getState().getType() == EntityTypes.PLAYER) { + return false; + } + Location location = entity.getLocation(); + LocalChunk chunk = getChunk(location.getBlockX() >> 4, location.getBlockZ() >> 4); + chunk.setEntity(location, entity.getState()); + return true; + } + + @Override public @Nonnull List getReadChunks() { + return this.readRegion; + } + + @Override public void addReadChunk(@Nonnull BlockVector2 chunk) { + this.readRegion.add(chunk); + } + + @Override public void addReadChunks(@Nonnull Set readRegion) { + this.readRegion.addAll(readRegion); + } + + @Override public CuboidRegion getRegenRegion() { + return this.regenRegion != null ? this.regenRegion.clone() : null; + } + + @Override public void setRegenRegion(@Nonnull CuboidRegion regenRegion) { + this.regenRegion = regenRegion; + } + + @Override public void regenChunk(int x, int z) { + regen = true; + // There will never only be one nullified coordinate pair + if (regenStart == null) { + regenStart = new int[] {x, z}; + regenEnd = new int[] {x, z}; + return; + } + if (x < regenStart[0]) { + regenStart[0] = x; + } + if (z < regenStart[1]) { + regenStart[1] = z; + } + if (x > regenEnd[0]) { + regenEnd[0] = x; + } + if (z > regenEnd[1]) { + regenEnd[1] = z; + } + } + + @Override public boolean isUnloadAfter() { + return this.unloadAfter; + } + + @Override public void setUnloadAfter(boolean unloadAfter) { + this.unloadAfter = unloadAfter; + } + + /** + * Gets the int[x,z] chunk coordinates where regeneration should start from + */ + public int[] getRegenStart() { + return regenStart; + } + + /** + * Gets the int[x,z] chunk coordinates where regeneration should finish + */ + public int[] getRegenEnd() { + return regenEnd; + } + + /** + * Whether the queue has a start/end to chunk regeneration + */ + public boolean isRegen() { + return regen; + } + + /** + * Gets the map of ChunkCoordinates in {@link BlockVector2} form against the {@link LocalChunk} of cached chunks to be written + */ + @Nonnull public ConcurrentHashMap getBlockChunks() { + return this.blockChunks; + } + + /** + * Forces an {@link LocalChunk} into the list of chunks to be written. Overwrites existing chunks in the map + */ + public final void setChunk(@Nonnull LocalChunk chunk) { + this.blockChunks.put(BlockVector2.at(chunk.getX(), chunk.getZ()), chunk); + } + + @Override @Nullable public final Consumer getChunkConsumer() { + return this.consumer; + } + + @Override public final void setChunkConsumer(@Nonnull Consumer consumer) { + this.consumer = consumer; + } + + @Override public Runnable getCompleteTask() { + return this.whenDone; + } + + @Override public void setCompleteTask(Runnable whenDone) { + this.whenDone = whenDone; + } + + /** + * Get the {@link LocalChunk} from the queue at the given chunk coordinates. Returns a new instance if one doesn't exist + */ + @Nonnull private LocalChunk getChunk(final int chunkX, final int chunkZ) { + if (chunkX != lastX || chunkZ != lastZ) { + lastX = chunkX; + lastZ = chunkZ; + BlockVector2 pair = BlockVector2.at(chunkX, chunkZ); + lastWrappedChunk = this.blockChunks.get(pair); + if (lastWrappedChunk == null) { + lastWrappedChunk = new LocalChunk(this, chunkX, chunkZ); + LocalChunk previous = this.blockChunks.put(pair, lastWrappedChunk); + if (previous == null) { + return lastWrappedChunk; + } + lastWrappedChunk = previous; + } + } + return lastWrappedChunk; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinator.java new file mode 100644 index 000000000..28ed3dc74 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinator.java @@ -0,0 +1,62 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.queue; + +import com.plotsquared.core.util.task.PlotSquaredTask; + +public abstract class ChunkCoordinator implements PlotSquaredTask { + + @Override public abstract void runTask(); + + @Override public boolean isCancelled() { + return false; + } + + @Override public void cancel() { + // Do nothing + } + + /** + * Starts the chunk coordinator. This will usually (implementation-specific-permitting) mark chunks to be loaded in batches, + * then add them to a queue and apply tickets once loaded to prevent unloading. A repeating task will then iterate over loaded + * chunks, access them with a Consumer(BlockVector2) and remove the ticket once work has been completed on it. + */ + public abstract void start(); + + /** + * Get the amount of remaining chunks (at the time of the method call) + * + * @return Snapshot view of remaining chunk count + */ + public abstract int getRemainingChunks(); + + /** + * Get the amount of requested chunks + * + * @return Requested chunk count + */ + public abstract int getTotalChunks(); +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java new file mode 100644 index 000000000..2ead29881 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/ChunkCoordinatorBuilder.java @@ -0,0 +1,178 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.queue; + +import com.google.common.base.Preconditions; +import com.google.inject.Inject; +import com.plotsquared.core.inject.factory.ChunkCoordinatorFactory; +import com.plotsquared.core.location.Location; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Consumer; + +/** + * Builds a {@link ChunkCoordinator} instance + */ +public class ChunkCoordinatorBuilder { + + private final List requestedChunks = new LinkedList<>(); + private final ChunkCoordinatorFactory chunkCoordinatorFactory; + private Consumer throwableConsumer = Throwable::printStackTrace; + private World world; + private Consumer chunkConsumer; + private Runnable whenDone = () -> { + }; + private long maxIterationTime = 60; // A little over 1 tick; + private int initialBatchSize = 4; + private boolean unloadAfter = true; + + @Inject public ChunkCoordinatorBuilder(@Nonnull ChunkCoordinatorFactory chunkCoordinatorFactory) { + this.chunkCoordinatorFactory = chunkCoordinatorFactory; + } + + /** + * Set the world + */ + @Nonnull public ChunkCoordinatorBuilder inWorld(@Nonnull final World world) { + this.world = Preconditions.checkNotNull(world, "World may not be null"); + return this; + } + + /** + * Add a chunk to be accessed + */ + @Nonnull public ChunkCoordinatorBuilder withChunk(@Nonnull final BlockVector2 chunkLocation) { + this.requestedChunks.add(Preconditions.checkNotNull(chunkLocation, "Chunk location may not be null")); + return this; + } + + /** + * Add a Collection of chunks to be accessed + */ + @Nonnull public ChunkCoordinatorBuilder withChunks(@Nonnull final Collection chunkLocations) { + chunkLocations.forEach(this::withChunk); + return this; + } + + /** + * Add chunks within a region to be accessed + */ + @Nonnull public ChunkCoordinatorBuilder withRegion(@Nonnull Location pos1, @Nonnull Location pos2) { + final int p1x = pos1.getX(); + final int p1z = pos1.getZ(); + final int p2x = pos2.getX(); + final int p2z = pos2.getZ(); + final int bcx = p1x >> 4; + final int bcz = p1z >> 4; + final int tcx = p2x >> 4; + final int tcz = p2z >> 4; + final ArrayList chunks = new ArrayList<>(); + + for (int x = bcx; x <= tcx; x++) { + for (int z = bcz; z <= tcz; z++) { + chunks.add(BlockVector2.at(x, z)); + } + } + + chunks.forEach(this::withChunk); + return this; + } + + /** + * Set the consumer to be used when a chunk is loaded + */ + @Nonnull public ChunkCoordinatorBuilder withConsumer(@Nonnull final Consumer chunkConsumer) { + this.chunkConsumer = Preconditions.checkNotNull(chunkConsumer, "Chunk consumer may not be null"); + return this; + } + + /** + * Set the Runnable to run when all chunks have been accessed + */ + @Nonnull public ChunkCoordinatorBuilder withFinalAction(@Nullable final Runnable whenDone) { + if (whenDone == null) { + return this; + } + this.whenDone = whenDone; + return this; + } + + /** + * Set the max time taken while iterating over and accessing loaded chunks + */ + @Nonnull public ChunkCoordinatorBuilder withMaxIterationTime(final long maxIterationTime) { + Preconditions.checkArgument(maxIterationTime > 0, "Max iteration time must be positive"); + this.maxIterationTime = maxIterationTime; + return this; + } + + /** + * Set the initial batch size to be used for loading chunks + */ + @Nonnull public ChunkCoordinatorBuilder withInitialBatchSize(final int initialBatchSize) { + Preconditions.checkArgument(initialBatchSize > 0, "Initial batch size must be positive"); + this.initialBatchSize = initialBatchSize; + return this; + } + + /** + * Set the consumer to be used to handle {@link Throwable}s + */ + @Nonnull public ChunkCoordinatorBuilder withThrowableConsumer(@Nonnull final Consumer throwableConsumer) { + this.throwableConsumer = Preconditions.checkNotNull(throwableConsumer, "Throwable consumer may not be null"); + return this; + } + + /** + * Set whether the chunks should be allow to unload after being accessed. This should only be used where the chunks are read from + * and then written to from a separate queue where they're consequently unloaded. + */ + @Nonnull public ChunkCoordinatorBuilder unloadAfter(final boolean unloadAfter) { + this.unloadAfter = unloadAfter; + return this; + } + + /** + * Create a new {@link ChunkCoordinator} instance based on the values in the Builder instance. + */ + @Nonnull public ChunkCoordinator build() { + Preconditions.checkNotNull(this.world, "No world was supplied"); + Preconditions.checkNotNull(this.chunkConsumer, "No chunk consumer was supplied"); + Preconditions.checkNotNull(this.whenDone, "No final action was supplied"); + Preconditions.checkNotNull(this.throwableConsumer, "No throwable consumer was supplied"); + return chunkCoordinatorFactory + .create(this.maxIterationTime, this.initialBatchSize, this.chunkConsumer, this.world, this.requestedChunks, this.whenDone, + this.throwableConsumer, this.unloadAfter); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/ChunkBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java similarity index 62% rename from Core/src/main/java/com/plotsquared/core/queue/ChunkBlockQueue.java rename to Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java index 4fb47ed90..d04a0c798 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ChunkBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java @@ -28,65 +28,69 @@ package com.plotsquared.core.queue; import com.plotsquared.core.location.Location; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Arrays; -public class ChunkBlockQueue extends ScopedLocalBlockQueue { +/** + * Queue that is limited to a single chunk + */ +public class ChunkQueueCoordinator extends ScopedQueueCoordinator { - public final BiomeType[] biomeGrid; + public final BiomeType[][][] biomeResult; public final BlockState[][][] result; private final int width; private final int length; - @Deprecated private final int area; private final BlockVector3 bot; private final BlockVector3 top; - public ChunkBlockQueue(BlockVector3 bot, BlockVector3 top, boolean biomes) { + public ChunkQueueCoordinator(@Nonnull BlockVector3 bot, @Nonnull BlockVector3 top, boolean biomes) { super(null, Location.at("", 0, 0, 0), Location.at("", 15, 255, 15)); this.width = top.getX() - bot.getX() + 1; this.length = top.getZ() - bot.getZ() + 1; - this.area = width * length; this.result = new BlockState[256][][]; - this.biomeGrid = biomes ? new BiomeType[width * length] : null; + this.biomeResult = biomes ? new BiomeType[256][][] : null; this.bot = bot; this.top = top; } - public BlockState[][][] getBlocks() { + @Nonnull public BlockState[][][] getBlocks() { return result; } - @Override public void fillBiome(BiomeType biomeType) { - if (biomeGrid == null) { - return; - } - Arrays.fill(biomeGrid, biomeType); - } - - @Override public boolean setBiome(int x, int z, BiomeType biomeType) { - if (this.biomeGrid != null) { - biomeGrid[(z * width) + x] = biomeType; + @Override public boolean setBiome(int x, int z, @Nonnull BiomeType biomeType) { + if (this.biomeResult != null) { + for (int y = 0; y < 256; y++) { + this.storeCacheBiome(x, y, z, biomeType); + } return true; } return false; } - @Override public boolean setBlock(int x, int y, int z, BlockState id) { + @Override public boolean setBiome(int x, int y, int z, @Nonnull BiomeType biomeType) { + if (this.biomeResult != null) { + this.storeCacheBiome(x, y, z, biomeType); + return true; + } + return false; + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull BlockState id) { this.storeCache(x, y, z, id); return true; } - @Override public boolean setBlock(int x, int y, int z, Pattern pattern) { + @Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) { this.storeCache(x, y, z, pattern.apply(BlockVector3.at(x, y, z)).toImmutableState()); return true; } - private void storeCache(final int x, final int y, final int z, final BlockState id) { + private void storeCache(final int x, final int y, final int z, @Nonnull final BlockState id) { BlockState[][] resultY = result[y]; if (resultY == null) { result[y] = resultY = new BlockState[length][]; @@ -98,7 +102,19 @@ public class ChunkBlockQueue extends ScopedLocalBlockQueue { resultYZ[x] = id; } - @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { + private void storeCacheBiome(final int x, final int y, final int z, @Nonnull final BiomeType id) { + BiomeType[][] resultY = biomeResult[y]; + if (resultY == null) { + biomeResult[y] = resultY = new BiomeType[length][]; + } + BiomeType[] resultYZ = resultY[z]; + if (resultYZ == null) { + resultY[z] = resultYZ = new BiomeType[width]; + } + resultYZ[x] = id; + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull final BaseBlock id) { this.storeCache(x, y, z, id.toImmutableState()); return true; } @@ -114,15 +130,15 @@ public class ChunkBlockQueue extends ScopedLocalBlockQueue { return null; } - @Override @Nonnull public String getWorld() { - return ""; + @Override @Nullable public World getWorld() { + return super.getWorld(); } - @Override public Location getMax() { - return Location.at(getWorld(), top.getX(), top.getY(), top.getZ()); + @Override @Nonnull public Location getMax() { + return Location.at(getWorld().getName(), top.getX(), top.getY(), top.getZ()); } - @Override public Location getMin() { - return Location.at(getWorld(), bot.getX(), bot.getY(), bot.getZ()); + @Override @Nonnull public Location getMin() { + return Location.at(getWorld().getName(), bot.getX(), bot.getY(), bot.getZ()); } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/DelegateLocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/DelegateLocalBlockQueue.java deleted file mode 100644 index 22176671c..000000000 --- a/Core/src/main/java/com/plotsquared/core/queue/DelegateLocalBlockQueue.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * 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 . - */ -package com.plotsquared.core.queue; - -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; - -public class DelegateLocalBlockQueue extends LocalBlockQueue { - - private final LocalBlockQueue parent; - - public DelegateLocalBlockQueue(LocalBlockQueue parent) { - super(parent == null ? null : parent.getWorld()); - this.parent = parent; - - if (parent != null) { - this.setForceSync(parent.isForceSync()); - this.setChunkObject(parent.getChunkObject()); - } - } - - public LocalBlockQueue getParent() { - return parent; - } - - @Override public boolean next() { - return parent.next(); - } - - @Override public void startSet(boolean parallel) { - if (parent != null) { - parent.startSet(parallel); - } - } - - @Override public void endSet(boolean parallel) { - if (parent != null) { - parent.endSet(parallel); - } - } - - @Override public int size() { - if (parent != null) { - return parent.size(); - } - return 0; - } - - @Override public void optimize() { - if (parent != null) { - parent.optimize(); - } - } - - @Override public long getModified() { - if (parent != null) { - return parent.getModified(); - } - return 0; - } - - @Override public void setModified(long modified) { - if (parent != null) { - parent.setModified(modified); - } - } - - @Override public boolean setBlock(int x, int y, int z, Pattern pattern) { - return parent.setBlock(x, y, z, pattern); - } - - @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { - return parent.setBlock(x, y, z, id); - } - - @Override public boolean setBlock(int x, int y, int z, BlockState id) { - return parent.setBlock(x, y, z, id); - } - - @Override public BlockState getBlock(int x, int y, int z) { - return parent.getBlock(x, y, z); - } - - @Override public boolean setBiome(int x, int z, BiomeType biome) { - return parent.setBiome(x, z, biome); - } - - @Override public boolean setBiome() { - return parent.setBiome(); - } - - @Override public String getWorld() { - return parent.getWorld(); - } - - @Override public void flush() { - if (parent != null) { - parent.flush(); - } - } - - @Override public void refreshChunk(int x, int z) { - if (parent != null) { - parent.refreshChunk(x, z); - } - } - - @Override public void fixChunkLighting(int x, int z) { - if (parent != null) { - parent.fixChunkLighting(x, z); - } - } - - @Override public void regenChunk(int x, int z) { - if (parent != null) { - parent.regenChunk(x, z); - } - } - - @Override public boolean enqueue() { - if (parent != null) { - return parent.enqueue(); - } - return false; - } -} diff --git a/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java new file mode 100644 index 000000000..b3dea64e9 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/DelegateQueueCoordinator.java @@ -0,0 +1,251 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.queue; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; + +/** + * Queue that delegates to a parent queue. + */ +public class DelegateQueueCoordinator extends QueueCoordinator { + + private final QueueCoordinator parent; + + public DelegateQueueCoordinator(QueueCoordinator parent) { + super(parent == null ? null : parent.getWorld()); + this.parent = parent; + + if (parent != null) { + this.setForceSync(parent.isForceSync()); + } + } + + public QueueCoordinator getParent() { + return parent; + } + + @Override public int size() { + if (parent != null) { + return parent.size(); + } + return 0; + } + + @Override public void setModified(long modified) { + if (parent != null) { + parent.setModified(modified); + } + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) { + if (parent != null) { + return parent.setBlock(x, y, z, pattern); + } + return false; + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull BaseBlock id) { + if (parent != null) { + return parent.setBlock(x, y, z, id); + } + return false; + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull BlockState id) { + if (parent != null) { + return parent.setBlock(x, y, z, id); + } + return false; + } + + @Override @Nullable public BlockState getBlock(int x, int y, int z) { + if (parent != null) { + return parent.getBlock(x, y, z); + } + return null; + } + + @Override public boolean setBiome(int x, int z, @Nonnull BiomeType biome) { + if (parent != null) { + return parent.setBiome(x, z, biome); + } + return false; + } + + @Override public boolean setBiome(int x, int y, int z, @Nonnull BiomeType biome) { + if (parent != null) { + return parent.setBiome(x, y, z, biome); + } + return false; + } + + @Override public boolean isSettingBiomes() { + if (parent != null) { + return parent.isSettingBiomes(); + } + return false; + } + + @Override public boolean setEntity(@Nonnull Entity entity) { + if (parent != null) { + return parent.setEntity(entity); + } + return false; + } + + @Override public void regenChunk(int x, int z) { + if (parent != null) { + parent.regenChunk(x, z); + } + } + + @Override @Nullable public World getWorld() { + if (parent != null) { + return parent.getWorld(); + } + return null; + } + + @Override public boolean setTile(int x, int y, int z, @Nonnull CompoundTag tag) { + if (parent != null) { + return parent.setTile(x, y, z, tag); + } + return false; + } + + @Override public boolean isSettingTiles() { + if (parent != null) { + return parent.isSettingTiles(); + } + return false; + } + + @Override public boolean enqueue() { + if (parent != null) { + return parent.enqueue(); + } + return false; + } + + @Override public void start() { + if (parent != null) { + parent.start(); + } + } + + @Override public void cancel() { + if (parent != null) { + parent.cancel(); + } + } + + @Override public Runnable getCompleteTask() { + if (parent != null) { + return parent.getCompleteTask(); + } + return null; + } + + @Override public void setCompleteTask(Runnable whenDone) { + if (parent != null) { + parent.setCompleteTask(whenDone); + } + } + + @Nullable @Override public Consumer getChunkConsumer() { + if (parent != null) { + return parent.getChunkConsumer(); + } + return null; + } + + @Override public void setChunkConsumer(@Nonnull Consumer consumer) { + if (parent != null) { + parent.setChunkConsumer(consumer); + } + } + + @Override @Nonnull public List getReadChunks() { + if (parent != null) { + return parent.getReadChunks(); + } + return new ArrayList<>(); + } + + @Override public void addReadChunks(@Nonnull Set readChunks) { + if (parent != null) { + parent.addReadChunks(readChunks); + } + } + + @Override public void addReadChunk(@Nonnull BlockVector2 chunk) { + if (parent != null) { + parent.addReadChunk(chunk); + } + } + + @Override public boolean isUnloadAfter() { + if (parent != null) { + return parent.isUnloadAfter(); + } + return false; + } + + @Override public void setUnloadAfter(boolean setUnloadAfter) { + if (parent != null) { + parent.setUnloadAfter(setUnloadAfter); + } + } + + @Override @Nullable public CuboidRegion getRegenRegion() { + if (parent != null) { + return parent.getRegenRegion(); + } + return null; + } + + @Override public void setRegenRegion(@Nonnull CuboidRegion regenRegion) { + if (parent != null) { + parent.setRegenRegion(regenRegion); + } + + } +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java index 1ef62a4eb..a251aced7 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java @@ -26,326 +26,67 @@ package com.plotsquared.core.queue; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.util.task.RunnableVal2; -import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.task.TaskTime; +import com.sk89q.worldedit.world.World; +import javax.annotation.Nonnull; import java.util.ArrayList; -import java.util.ConcurrentModificationException; -import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.concurrent.atomic.AtomicBoolean; public class GlobalBlockQueue { - private final int PARALLEL_THREADS; - private final ConcurrentLinkedDeque activeQueues; - private final ConcurrentLinkedDeque inactiveQueues; - private final ConcurrentLinkedDeque runnables; - private final AtomicBoolean running; - private final int targetTime; + private final ConcurrentLinkedDeque activeQueues; private QueueProvider provider; - /** - * Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the - * server - */ - private long last; - private long secondLast; - private long lastSuccess; - private double lastPeriod = 0; - private final RunnableVal2 SET_TASK = - new RunnableVal2() { - @Override public void run(Long free, LocalBlockQueue queue) { - do { - boolean more = queue.next(); - if (!more) { - lastSuccess = last; - if (inactiveQueues.size() == 0 && activeQueues.size() == 0) { - runEmptyTasks(); - } - return; - } - } while ((lastPeriod = - ((GlobalBlockQueue.this.secondLast = System.currentTimeMillis()) - - GlobalBlockQueue.this.last)) < free); - } - }; - public GlobalBlockQueue(QueueProvider provider, int threads, int targetTime) { + public GlobalBlockQueue(@Nonnull QueueProvider provider) { this.provider = provider; this.activeQueues = new ConcurrentLinkedDeque<>(); - this.inactiveQueues = new ConcurrentLinkedDeque<>(); - this.runnables = new ConcurrentLinkedDeque<>(); - this.running = new AtomicBoolean(); - this.targetTime = targetTime; - this.PARALLEL_THREADS = threads; } - public QueueProvider getProvider() { - return provider; - } - - public void setProvider(QueueProvider provider) { - this.provider = provider; - } - - public LocalBlockQueue getNewQueue(String world, boolean autoQueue) { - LocalBlockQueue queue = provider.getNewQueue(world); + /** + * Get a new {@link QueueCoordinator} for the given world. + */ + @Nonnull public QueueCoordinator getNewQueue(@Nonnull World world) { + QueueCoordinator queue = provider.getNewQueue(world); // Auto-inject into the queue PlotSquared.platform().getInjector().injectMembers(queue); - if (autoQueue) { - inactiveQueues.add(queue); - } return queue; } - public boolean stop() { - if (!running.get()) { - return false; - } - running.set(false); - return true; + public QueueProvider getProvider() { + return this.provider; } - public boolean runTask() { - if (running.get()) { - return false; - } - running.set(true); - TaskManager.runTaskRepeat(new Runnable() { - @Override public void run() { - if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) { - lastSuccess = System.currentTimeMillis(); - lastPeriod = 0; - GlobalBlockQueue.this.runEmptyTasks(); - return; - } - // Server laggy? Skip. - if (lastPeriod > targetTime) { - lastPeriod -= targetTime; - return; - } - SET_TASK.value1 = 50 + Math.min( - (50 + GlobalBlockQueue.this.last) - (GlobalBlockQueue.this.last = - System.currentTimeMillis()), - GlobalBlockQueue.this.secondLast - System.currentTimeMillis()); - SET_TASK.value2 = GlobalBlockQueue.this.getNextQueue(); - if (SET_TASK.value2 == null) { - return; - } - if (!PlotSquared.get().isMainThread(Thread.currentThread())) { - throw new IllegalStateException( - "This shouldn't be possible for placement to occur off the main thread"); - } - // Disable the async catcher as it can't discern async vs parallel - SET_TASK.value2.startSet(true); - try { - if (PARALLEL_THREADS <= 1) { - SET_TASK.run(); - } else { - ArrayList threads = new ArrayList<>(); - for (int i = 0; i < PARALLEL_THREADS; i++) { - threads.add(new Thread(SET_TASK)); - } - for (Thread thread : threads) { - thread.start(); - } - for (Thread thread : threads) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } catch (Throwable e) { - e.printStackTrace(); - } finally { - // Enable it again (note that we are still on the main thread) - SET_TASK.value2.endSet(true); - } - } - }, TaskTime.ticks(1L)); - return true; - } - - public QueueStage getStage(LocalBlockQueue queue) { - if (activeQueues.contains(queue)) { - return QueueStage.ACTIVE; - } else if (inactiveQueues.contains(queue)) { - return QueueStage.INACTIVE; - } - return QueueStage.NONE; - } - - public boolean isStage(LocalBlockQueue queue, QueueStage stage) { - switch (stage) { - case ACTIVE: - return activeQueues.contains(queue); - case INACTIVE: - return inactiveQueues.contains(queue); - case NONE: - return !activeQueues.contains(queue) && !inactiveQueues.contains(queue); - } - return false; + public void setQueueProvider(@Nonnull QueueProvider provider) { + this.provider = provider; } /** - * TODO Documentation needed. + * Place an instance of {@link QueueCoordinator} into a list incase access is needed + * and then start it. * - * @param queue todo + * @param queue {@link QueueCoordinator} instance to start. * @return true if added to queue, false otherwise */ - public boolean enqueue(LocalBlockQueue queue) { + public boolean enqueue(@Nonnull QueueCoordinator queue) { boolean success = false; - success = inactiveQueues.remove(queue); if (queue.size() > 0 && !activeQueues.contains(queue)) { - queue.optimize(); success = activeQueues.add(queue); + queue.start(); } return success; } - public void dequeue(LocalBlockQueue queue) { - inactiveQueues.remove(queue); + public void dequeue(@Nonnull QueueCoordinator queue) { + queue.cancel(); activeQueues.remove(queue); } - public List getAllQueues() { - ArrayList list = - new ArrayList<>(activeQueues.size() + inactiveQueues.size()); - list.addAll(inactiveQueues); - list.addAll(activeQueues); - return list; - } - - public List getActiveQueues() { + @Nonnull public List getActiveQueues() { return new ArrayList<>(activeQueues); } - public List getInactiveQueues() { - return new ArrayList<>(inactiveQueues); - } - - public void flush(LocalBlockQueue queue) { - SET_TASK.value1 = Long.MAX_VALUE; - SET_TASK.value2 = queue; - if (SET_TASK.value2 == null) { - return; - } - if (PlotSquared.get().isMainThread(Thread.currentThread())) { - throw new IllegalStateException("Must be flushed on the main thread!"); - } - // Disable the async catcher as it can't discern async vs parallel - SET_TASK.value2.startSet(true); - try { - if (PARALLEL_THREADS <= 1) { - SET_TASK.run(); - } else { - ArrayList threads = new ArrayList<>(); - for (int i = 0; i < PARALLEL_THREADS; i++) { - Thread thread = new Thread(SET_TASK); - thread.setName("PlotSquared Flush Task"); - threads.add(thread); - } - for (Thread thread : threads) { - thread.start(); - } - for (Thread thread : threads) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } catch (Throwable e) { - e.printStackTrace(); - } finally { - // Enable it again (note that we are still on the main thread) - SET_TASK.value2.endSet(true); - dequeue(queue); - } - } - - public LocalBlockQueue getNextQueue() { - long now = System.currentTimeMillis(); - while (!activeQueues.isEmpty()) { - LocalBlockQueue queue = activeQueues.peek(); - if (queue != null && queue.size() > 0) { - queue.setModified(now); - return queue; - } else { - activeQueues.poll(); - } - } - int size = inactiveQueues.size(); - if (size > 0) { - Iterator iter = inactiveQueues.iterator(); - try { - int total = 0; - LocalBlockQueue firstNonEmpty = null; - while (iter.hasNext()) { - LocalBlockQueue queue = iter.next(); - long age = now - queue.getModified(); - total += queue.size(); - if (queue.size() == 0) { - if (age > 60000) { - iter.remove(); - } - continue; - } - if (firstNonEmpty == null) { - firstNonEmpty = queue; - } - if (total > 64) { - firstNonEmpty.setModified(now); - return firstNonEmpty; - } - if (age > 1000) { - queue.setModified(now); - return queue; - } - } - } catch (ConcurrentModificationException e) { - e.printStackTrace(); - } - } - return null; - } - public boolean isDone() { - return activeQueues.size() == 0 && inactiveQueues.size() == 0; - } - - public boolean addEmptyTask(final Runnable whenDone) { - if (this.isDone()) { - // Run - this.runEmptyTasks(); - if (whenDone != null) { - whenDone.run(); - } - return true; - } - if (whenDone != null) { - this.runnables.add(whenDone); - } - return false; - } - - private synchronized void runEmptyTasks() { - if (this.runnables.isEmpty()) { - return; - } - final ConcurrentLinkedDeque tmp = new ConcurrentLinkedDeque<>(this.runnables); - this.runnables.clear(); - for (final Runnable runnable : tmp) { - runnable.run(); - } - } - - public enum QueueStage { - INACTIVE, ACTIVE, NONE + return activeQueues.size() == 0; } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/LocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/LocalBlockQueue.java deleted file mode 100644 index c97013458..000000000 --- a/Core/src/main/java/com/plotsquared/core/queue/LocalBlockQueue.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * 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 . - */ -package com.plotsquared.core.queue; - -import com.google.inject.Inject; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.location.Location; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.util.PatternUtil; -import com.plotsquared.core.util.SchematicHandler; -import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.WorldUtil; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public abstract class LocalBlockQueue { - - private boolean forceSync = false; - @Nullable private Object chunkObject; - - @Inject private SchematicHandler schematicHandler; - @Inject private WorldUtil worldUtil; - @Inject private GlobalBlockQueue blockQueue; - - /** - * Needed for compatibility with FAWE. - * - * @param world unused - */ - @Deprecated public LocalBlockQueue(String world) { - PlotSquared.platform().getInjector().injectMembers(this); - } - - public ScopedLocalBlockQueue getForChunk(int x, int z) { - int bx = x << 4; - int bz = z << 4; - return new ScopedLocalBlockQueue(this, Location.at(getWorld(), bx, 0, bz), - Location.at(getWorld(), bx + 15, 255, bz + 255)); - } - - public abstract boolean next(); - - public abstract void startSet(boolean parallel); - - public abstract void endSet(boolean parallel); - - public abstract int size(); - - public abstract void optimize(); - - public abstract long getModified(); - - public abstract void setModified(long modified); - - /** - * Sets the block at the coordinates provided to the given id. - * - * @param x the x coordinate from from 0 to 15 inclusive - * @param y the y coordinate from from 0 (inclusive) - maxHeight(exclusive) - * @param z the z coordinate from 0 to 15 inclusive - * @param id the id to set the block to - */ - public abstract boolean setBlock(final int x, final int y, final int z, final BlockState id); - - public abstract boolean setBlock(final int x, final int y, final int z, final BaseBlock id); - - public boolean setBlock(final int x, final int y, final int z, @Nonnull final Pattern pattern) { - return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z)); - } - - public boolean setTile(int x, int y, int z, CompoundTag tag) { - this.schematicHandler.restoreTile(this, tag, x, y, z); - return true; - } - - public abstract BlockState getBlock(int x, int y, int z); - - public abstract boolean setBiome(int x, int z, BiomeType biome); - - public abstract boolean setBiome(); - - public abstract String getWorld(); - - public abstract void flush(); - - public final void setModified() { - setModified(System.currentTimeMillis()); - } - - public abstract void refreshChunk(int x, int z); - - public abstract void fixChunkLighting(int x, int z); - - public abstract void regenChunk(int x, int z); - - public final void regenChunkSafe(int x, int z) { - regenChunk(x, z); - fixChunkLighting(x, z); - BlockVector2 loc = BlockVector2.at(x, z); - - for (final PlotPlayer pp : PlotSquared.platform().getPlayerManager().getPlayers()) { - Location pLoc = pp.getLocation(); - if (!StringMan.isEqual(getWorld(), pLoc.getWorldName()) || !pLoc.getChunkLocation() - .equals(loc)) { - continue; - } - pp.teleport(pLoc.withY(this.worldUtil.getHighestBlockSynchronous(getWorld(), pLoc.getX(), pLoc.getZ()))); - } - } - - public boolean enqueue() { - return blockQueue.enqueue(this); - } - - public void setCuboid(Location pos1, Location pos2, BlockState block) { - int yMin = Math.min(pos1.getY(), pos2.getY()); - int yMax = Math.min(255, Math.max(pos1.getY(), pos2.getY())); - int xMin = Math.min(pos1.getX(), pos2.getX()); - int xMax = Math.max(pos1.getX(), pos2.getX()); - int zMin = Math.min(pos1.getZ(), pos2.getZ()); - int zMax = Math.max(pos1.getZ(), pos2.getZ()); - for (int y = yMin; y <= yMax; y++) { - for (int x = xMin; x <= xMax; x++) { - for (int z = zMin; z <= zMax; z++) { - setBlock(x, y, z, block); - } - } - } - } - - public void setCuboid(Location pos1, Location pos2, Pattern blocks) { - int yMin = Math.min(pos1.getY(), pos2.getY()); - int yMax = Math.min(255, Math.max(pos1.getY(), pos2.getY())); - int xMin = Math.min(pos1.getX(), pos2.getX()); - int xMax = Math.max(pos1.getX(), pos2.getX()); - int zMin = Math.min(pos1.getZ(), pos2.getZ()); - int zMax = Math.max(pos1.getZ(), pos2.getZ()); - for (int y = yMin; y <= yMax; y++) { - for (int x = xMin; x <= xMax; x++) { - for (int z = zMin; z <= zMax; z++) { - setBlock(x, y, z, blocks); - } - } - } - } - - public boolean isForceSync() { - return this.forceSync; - } - - @Nullable public Object getChunkObject() { - return this.chunkObject; - } - - public void setForceSync(boolean forceSync) { - this.forceSync = forceSync; - } - - public void setChunkObject(@Nullable Object chunkObject) { - this.chunkObject = chunkObject; - } -} diff --git a/Core/src/main/java/com/plotsquared/core/queue/LocalChunk.java b/Core/src/main/java/com/plotsquared/core/queue/LocalChunk.java new file mode 100644 index 000000000..999f36ccb --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/LocalChunk.java @@ -0,0 +1,117 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.queue; + +import com.plotsquared.core.util.ChunkUtil; +import com.plotsquared.core.util.MathMan; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; + +import javax.annotation.Nonnull; +import java.util.HashMap; + +public class LocalChunk { + private final QueueCoordinator parent; + private final int x; + private final int z; + + private final BaseBlock[][] baseblocks; + private final BiomeType[][] biomes; + private final HashMap tiles = new HashMap<>(); + private final HashMap entities = new HashMap<>(); + + public LocalChunk(@Nonnull QueueCoordinator parent, int x, int z) { + this.parent = parent; + this.x = x; + this.z = z; + baseblocks = new BaseBlock[16][]; + biomes = new BiomeType[16][]; + } + + @Nonnull public QueueCoordinator getParent() { + return this.parent; + } + + public int getX() { + return this.x; + } + + public int getZ() { + return this.z; + } + + @Nonnull public BaseBlock[][] getBaseblocks() { + return this.baseblocks; + } + + @Nonnull public BiomeType[][] getBiomes() { + return this.biomes; + } + + @Nonnull public HashMap getTiles() { + return this.tiles; + } + + public void setBiome(final int x, final int y, final int z, @Nonnull final BiomeType biomeType) { + final int i = y >> 4; + final int j = ChunkUtil.getJ(x, y, z); + BiomeType[] array = this.biomes[i]; + if (array == null) { + array = this.biomes[i] = new BiomeType[4096]; + } + array[j] = biomeType; + } + + @Override public int hashCode() { + return MathMan.pair((short) x, (short) z); + } + + public void setBlock(final int x, final int y, final int z, @Nonnull final BaseBlock baseBlock) { + final int i = y >> 4; + final int j = ChunkUtil.getJ(x, y, z); + BaseBlock[] array = baseblocks[i]; + if (array == null) { + array = (baseblocks[i] = new BaseBlock[4096]); + } + array[j] = baseBlock; + } + + public void setTile(final int x, final int y, final int z, @Nonnull final CompoundTag tag) { + tiles.put(BlockVector3.at(x, y, z), tag); + } + + public void setEntity(@Nonnull Location location, @Nonnull BaseEntity entity) { + this.entities.put(location, entity); + } + + @Nonnull public HashMap getEntities() { + return this.entities; + } +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateLocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateQueueCoordinator.java similarity index 57% rename from Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateLocalBlockQueue.java rename to Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateQueueCoordinator.java index eefae99d3..fd86f7eb2 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateLocalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/LocationOffsetDelegateQueueCoordinator.java @@ -25,40 +25,33 @@ */ package com.plotsquared.core.queue; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class LocationOffsetDelegateLocalBlockQueue extends DelegateLocalBlockQueue { - - private static final Logger logger = LoggerFactory.getLogger("P2/" + LocationOffsetDelegateLocalBlockQueue.class.getSimpleName()); +/** + * Offsets input coordinates and delegates to a parent queue + */ +public class LocationOffsetDelegateQueueCoordinator extends DelegateQueueCoordinator { private final boolean[][] canPlace; private final int blockX; private final int blockZ; - public LocationOffsetDelegateLocalBlockQueue(final boolean[][] canPlace, final int blockX, - final int blockZ, @Nullable LocalBlockQueue parent) { + public LocationOffsetDelegateQueueCoordinator(final boolean[][] canPlace, final int blockX, final int blockZ, @Nullable QueueCoordinator parent) { super(parent); this.canPlace = canPlace; this.blockX = blockX; this.blockZ = blockZ; } - @Override public boolean setBlock(int x, int y, int z, BlockState id) { - if (canPlace[x - blockX][z - blockZ]) { - return super.setBlock(x, y, z, id); - } - return false; - } - - @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { + @Override public boolean setBlock(int x, int y, int z, @Nonnull BlockState id) { try { if (canPlace[x - blockX][z - blockZ]) { return super.setBlock(x, y, z, id); @@ -69,13 +62,49 @@ public class LocationOffsetDelegateLocalBlockQueue extends DelegateLocalBlockQue return false; } - @Override public boolean setBlock(int x, int y, int z, Pattern pattern) { + @Override public boolean setBlock(int x, int y, int z, @Nonnull BaseBlock id) { + try { + if (canPlace[x - blockX][z - blockZ]) { + return super.setBlock(x, y, z, id); + } + } catch (final Exception e) { + throw e; + } + return false; + } + + @Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) { final BlockVector3 blockVector3 = BlockVector3.at(x + blockX, y, z + blockZ); return this.setBlock(x, y, z, pattern.apply(blockVector3)); } - @Override public boolean setBiome(int x, int y, BiomeType biome) { - return super.setBiome(x, y, biome); + @Override public boolean setBiome(int x, int z, @Nonnull BiomeType biome) { + boolean result = true; + for (int y = 0; y < 256; y++) { + result &= this.setBiome(x, z, biome); + } + return result; } + @Override public boolean setBiome(int x, int y, int z, @Nonnull BiomeType biome) { + try { + if (canPlace[x - blockX][z - blockZ]) { + return super.setBiome(x, y, z, biome); + } + } catch (final Exception e) { + throw e; + } + return false; + } + + @Override public boolean setTile(int x, int y, int z, @Nonnull CompoundTag tag) { + try { + if (canPlace[x - blockX][z - blockZ]) { + return super.setTile(x, y, z, tag); + } + } catch (final Exception e) { + throw e; + } + return false; + } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java new file mode 100644 index 000000000..b6a838990 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java @@ -0,0 +1,336 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.queue; + +import com.google.inject.Inject; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.util.PatternUtil; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; + +public abstract class QueueCoordinator { + + private boolean forceSync = false; + @Nullable private Object chunkObject; + + @Inject private GlobalBlockQueue blockQueue; + + /** + * Default constructor requires world to indicate any extents given to {@link QueueCoordinator} also need this constructor. + */ + public QueueCoordinator(@Nullable World world) { + PlotSquared.platform().getInjector().injectMembers(this); + } + + /** + * Get a {@link ScopedQueueCoordinator} limited to the chunk at the specific chunk Coordinates + */ + public ScopedQueueCoordinator getForChunk(int x, int z) { + int bx = x << 4; + int bz = z << 4; + return new ScopedQueueCoordinator(this, Location.at(getWorld().getName(), bx, 0, bz), + Location.at(getWorld().getName(), bx + 15, 255, bz + 255)); + } + + /** + * Get the size of the queue in chunks + */ + public abstract int size(); + + /** + * Set when the queue was last modified + */ + public abstract void setModified(long modified); + + /** + * Returns true if the queue should be forced to be synchronous when enqueued. + */ + public boolean isForceSync() { + return forceSync; + } + + /** + * Set whether the queue should be forced to be synchronous + */ + public void setForceSync(boolean forceSync) { + this.forceSync = forceSync; + } + + /** + * Get the Chunk Object set to the queue + */ + @Nullable public Object getChunkObject() { + return chunkObject; + } + + /** + * Set a chunk object (e.g. the Bukkit Chunk object) to the queue + */ + public void setChunkObject(@Nonnull Object chunkObject) { + this.chunkObject = chunkObject; + } + + /** + * Sets the block at the coordinates provided to the given id. + * + * @param x the x coordinate from from 0 to 15 inclusive + * @param y the y coordinate from from 0 (inclusive) - maxHeight(exclusive) + * @param z the z coordinate from 0 to 15 inclusive + * @param id the BlockState to set the block to + */ + public abstract boolean setBlock(final int x, final int y, final int z, @Nonnull final BlockState id); + + /** + * Sets the block at the coordinates provided to the given id. + * + * @param x the x coordinate from from 0 to 15 inclusive + * @param y the y coordinate from from 0 (inclusive) - maxHeight(exclusive) + * @param z the z coordinate from 0 to 15 inclusive + * @param id the BaseBlock to set the block to + */ + public abstract boolean setBlock(final int x, final int y, final int z, @Nonnull final BaseBlock id); + + /** + * Sets the block at the coordinates provided to the given id. + * + * @param x the x coordinate from from 0 to 15 inclusive + * @param y the y coordinate from from 0 (inclusive) - maxHeight(exclusive) + * @param z the z coordinate from 0 to 15 inclusive + * @param pattern the pattern to set the block to + */ + public boolean setBlock(final int x, final int y, final int z, @Nonnull final Pattern pattern) { + return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z)); + } + + /** + * Sets a tile entity at the coordinates provided to the given CompoundTag + * + * @param x the x coordinate from from 0 to 15 inclusive + * @param y the y coordinate from from 0 (inclusive) - maxHeight(exclusive) + * @param z the z coordinate from 0 to 15 inclusive + * @param tag the CompoundTag to set the tile to + */ + public abstract boolean setTile(int x, int y, int z, @Nonnull CompoundTag tag); + + /** + * Whether the queue has any tiles being set + */ + public abstract boolean isSettingTiles(); + + /** + * Get a block at the given coordinates. + */ + @Nullable public abstract BlockState getBlock(int x, int y, int z); + + /** + * Set a biome in XZ. This will likely set to the whole column + */ + @Deprecated public abstract boolean setBiome(int x, int z, @Nonnull BiomeType biome); + + /** + * Set a biome in XYZ + */ + public abstract boolean setBiome(int x, int y, int z, @Nonnull BiomeType biome); + + /** + * Whether the queue has any biomes to be set + */ + public abstract boolean isSettingBiomes(); + + /** + * Add entities to be created + */ + public void addEntities(@Nonnull List entities) { + for (Entity e : entities) { + this.setEntity(e); + } + } + + /** + * Add an entity to be created + */ + public abstract boolean setEntity(@Nonnull Entity entity); + + /** + * Get the list of chunks that are added manually. This usually indicated the queue is "read only". + */ + @Nonnull public abstract List getReadChunks(); + + /** + * Add a set of {@link BlockVector2} Chunk coordinates to the Read Chunks list + */ + public abstract void addReadChunks(@Nonnull Set readChunks); + + /** + * Add a {@link BlockVector2} Chunk coordinate to the Read Chunks list + */ + public abstract void addReadChunk(@Nonnull BlockVector2 chunk); + + /** + * Whether chunks should be unloaded after being accessed + */ + public abstract boolean isUnloadAfter(); + + /** + * Set whether chunks should be unloaded after being accessed + */ + public abstract void setUnloadAfter(boolean unloadAfter); + + /** + * Get the {@link CuboidRegion} designated for direct regeneration + */ + @Nullable public abstract CuboidRegion getRegenRegion(); + + /** + * Set the {@link CuboidRegion} designated for direct regeneration + */ + public abstract void setRegenRegion(@Nonnull CuboidRegion regenRegion); + + /** + * Set a specific chunk at the chunk coordinates XZ to be regenerated. + */ + public abstract void regenChunk(int x, int z); + + /** + * Get the world the queue is writing to + */ + @Nullable public abstract World getWorld(); + + /** + * Set the queue as having been modified now + */ + public final void setModified() { + setModified(System.currentTimeMillis()); + } + + /** + * Enqueue the queue with the {@link GlobalBlockQueue} + */ + public boolean enqueue() { + return blockQueue.enqueue(this); + } + + /** + * Start the queue + */ + public abstract void start(); + + /** + * Cancel the queue. Not yet implemented. + */ + public abstract void cancel(); + + /** + * Get the task to be run when all chunks have been accessed + */ + public abstract Runnable getCompleteTask(); + + /** + * Set the task to be run when all chunks have been accessed + */ + public abstract void setCompleteTask(@Nullable Runnable whenDone); + + /** + * Return the chunk consumer set to the queue or null if one is not set + */ + @Nullable public abstract Consumer getChunkConsumer(); + + /** + * Set the Consumer that will + */ + public abstract void setChunkConsumer(@Nonnull Consumer consumer); + + /** + * Fill a cuboid between two positions with a BlockState + */ + public void setCuboid(@Nonnull Location pos1, @Nonnull Location pos2, @Nonnull BlockState block) { + int yMin = Math.min(pos1.getY(), pos2.getY()); + int yMax = Math.min(255, Math.max(pos1.getY(), pos2.getY())); + int xMin = Math.min(pos1.getX(), pos2.getX()); + int xMax = Math.max(pos1.getX(), pos2.getX()); + int zMin = Math.min(pos1.getZ(), pos2.getZ()); + int zMax = Math.max(pos1.getZ(), pos2.getZ()); + for (int y = yMin; y <= yMax; y++) { + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { + setBlock(x, y, z, block); + } + } + } + } + + /** + * Fill a cuboid between two positions with a Pattern + */ + public void setCuboid(@Nonnull Location pos1, @Nonnull Location pos2, @Nonnull Pattern blocks) { + int yMin = Math.min(pos1.getY(), pos2.getY()); + int yMax = Math.min(255, Math.max(pos1.getY(), pos2.getY())); + int xMin = Math.min(pos1.getX(), pos2.getX()); + int xMax = Math.max(pos1.getX(), pos2.getX()); + int zMin = Math.min(pos1.getZ(), pos2.getZ()); + int zMax = Math.max(pos1.getZ(), pos2.getZ()); + for (int y = yMin; y <= yMax; y++) { + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { + setBlock(x, y, z, blocks); + } + } + } + } + + /** + * Fill a cuboid between two positions with a BiomeType + */ + public void setBiomeCuboid(@Nonnull Location pos1, @Nonnull Location pos2, @Nonnull BiomeType biome) { + int yMin = Math.min(pos1.getY(), pos2.getY()); + int yMax = Math.min(255, Math.max(pos1.getY(), pos2.getY())); + int xMin = Math.min(pos1.getX(), pos2.getX()); + int xMax = Math.max(pos1.getX(), pos2.getX()); + int zMin = Math.min(pos1.getZ(), pos2.getZ()); + int zMax = Math.max(pos1.getZ(), pos2.getZ()); + for (int y = yMin; y <= yMax; y++) { + for (int x = xMin; x <= xMax; x++) { + for (int z = zMin; z <= zMax; z++) { + setBiome(x, y, z, biome); + } + } + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/QueueProvider.java b/Core/src/main/java/com/plotsquared/core/queue/QueueProvider.java index 2fee2fa99..b31a7da45 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/QueueProvider.java +++ b/Core/src/main/java/com/plotsquared/core/queue/QueueProvider.java @@ -25,25 +25,29 @@ */ package com.plotsquared.core.queue; +import com.plotsquared.core.PlotSquared; +import com.sk89q.worldedit.world.World; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; + public abstract class QueueProvider { - public static QueueProvider of(final Class primary, - final Class fallback) { + + private static final Logger logger = LoggerFactory.getLogger("P2/" + PlotSquared.class.getSimpleName()); + + public static QueueProvider of(@Nonnull final Class primary) { return new QueueProvider() { - private boolean failed = false; - - @Override public LocalBlockQueue getNewQueue(String world) { - if (!failed) { - try { - return (LocalBlockQueue) primary.getConstructors()[0].newInstance(world); - } catch (Throwable e) { - e.printStackTrace(); - failed = true; - } - } + @Override public QueueCoordinator getNewQueue(@Nonnull World world) { try { - return (LocalBlockQueue) fallback.getConstructors()[0].newInstance(world); + return (QueueCoordinator) primary.getConstructors()[0].newInstance(world); } catch (Throwable e) { + logger.error("Error creating Queue: {} - Does it have the correct constructor(s)?", primary.getName()); + if (!primary.getName().contains("com.plotsquared")) { + logger.error("It looks like {} is a custom queue. Please look for a plugin in its classpath and report to them.", + primary.getSimpleName()); + } e.printStackTrace(); } return null; @@ -51,5 +55,8 @@ public abstract class QueueProvider { }; } - public abstract LocalBlockQueue getNewQueue(String world); + /** + * Get a queue for the given world + */ + public abstract QueueCoordinator getNewQueue(@Nonnull World world); } diff --git a/Core/src/main/java/com/plotsquared/core/queue/ScopedLocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java similarity index 59% rename from Core/src/main/java/com/plotsquared/core/queue/ScopedLocalBlockQueue.java rename to Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java index fc43e1ce0..b4fbc5e40 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ScopedLocalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java @@ -26,12 +26,19 @@ package com.plotsquared.core.queue; import com.plotsquared.core.location.Location; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -public class ScopedLocalBlockQueue extends DelegateLocalBlockQueue { +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Queue that only sets blocks with a designated area + */ +public class ScopedQueueCoordinator extends DelegateQueueCoordinator { private final int minX; private final int minY; private final int minZ; @@ -44,7 +51,7 @@ public class ScopedLocalBlockQueue extends DelegateLocalBlockQueue { private final int dy; private final int dz; - public ScopedLocalBlockQueue(LocalBlockQueue parent, Location min, Location max) { + public ScopedQueueCoordinator(@Nullable QueueCoordinator parent, @Nonnull Location min, @Nonnull Location max) { super(parent); this.minX = min.getX(); this.minY = min.getY(); @@ -59,39 +66,46 @@ public class ScopedLocalBlockQueue extends DelegateLocalBlockQueue { this.dz = maxZ - minZ; } - @Override public boolean setBiome(int x, int z, BiomeType biome) { + @Override public boolean setBiome(int x, int z, @Nonnull BiomeType biome) { return x >= 0 && x <= dx && z >= 0 && z <= dz && super.setBiome(x + minX, z + minZ, biome); } + @Override public boolean setBiome(int x, int y, int z, @Nonnull BiomeType biome) { + return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setBiome(x + minX, y + minY, z + minZ, biome); + } + public void fillBiome(BiomeType biome) { - for (int x = 0; x <= dx; x++) { - for (int z = 0; z < dz; z++) { - setBiome(x, z, biome); + for (int y = 0; y <= dy; y++) { + for (int x = 0; x <= dx; x++) { + for (int z = 0; z < dz; z++) { + setBiome(x, y, z, biome); + } } } } - @Override public boolean setBlock(int x, int y, int z, BaseBlock id) { - return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super - .setBlock(x + minX, y + minY, z + minZ, id); + @Override public boolean setBlock(int x, int y, int z, @Nonnull BaseBlock id) { + return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setBlock(x + minX, y + minY, z + minZ, id); } - @Override public boolean setBlock(int x, int y, int z, BlockState id) { - return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super - .setBlock(x + minX, y + minY, z + minZ, id); + @Override public boolean setBlock(int x, int y, int z, @Nonnull BlockState id) { + return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setBlock(x + minX, y + minY, z + minZ, id); } - @Override public boolean setBlock(int x, int y, int z, Pattern pattern) { - return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super - .setBlock(x + minX, y + minY, z + minZ, pattern); + @Override public boolean setBlock(int x, int y, int z, @Nonnull Pattern pattern) { + return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setBlock(x + minX, y + minY, z + minZ, pattern); } - public Location getMin() { - return Location.at(this.getWorld(), this.minX, this.minY, this.minZ); + @Override public boolean setTile(int x, int y, int z, @Nonnull CompoundTag tag) { + return x >= 0 && x <= dx && y >= 0 && y <= dy && z >= 0 && z <= dz && super.setTile(x + minX, y + minY, z + minZ, tag); } - public Location getMax() { - return Location.at(this.getWorld(), this.maxX, this.maxY, this.maxZ); + @Nonnull public Location getMin() { + return Location.at(this.getWorld().getName(), this.minX, this.minY, this.minZ); + } + + @Nonnull public Location getMax() { + return Location.at(this.getWorld().getName(), this.maxX, this.maxY, this.maxZ); } } diff --git a/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java b/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java index 438f60940..91d7a282f 100644 --- a/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java @@ -27,36 +27,30 @@ package com.plotsquared.core.util; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.location.Location; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.queue.LocalBlockQueue; -import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; +import com.plotsquared.core.queue.ScopedQueueCoordinator; import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.task.TaskTime; import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.regions.CuboidRegion; -import java.util.ArrayList; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; public abstract class ChunkManager { - private static final Map> forceChunks = - new ConcurrentHashMap<>(); - private static final Map> addChunks = - new ConcurrentHashMap<>(); + private static final Map> forceChunks = new ConcurrentHashMap<>(); + private static final Map> addChunks = new ConcurrentHashMap<>(); - public static void setChunkInPlotArea(RunnableVal force, - RunnableVal add, String world, BlockVector2 loc) { - LocalBlockQueue queue = PlotSquared.platform().getGlobalBlockQueue().getNewQueue(world, false); + public static void setChunkInPlotArea(RunnableVal force, + RunnableVal add, + String world, + BlockVector2 loc) { + QueueCoordinator queue = PlotSquared.platform().getGlobalBlockQueue().getNewQueue(PlotSquared.platform().getWorldUtil().getWeWorld(world)); if (PlotSquared.get().getPlotAreaManager().isAugmented(world) && PlotSquared.get().isNonStandardGeneration(world, loc)) { int blockX = loc.getX() << 4; int blockZ = loc.getZ() << 4; - ScopedLocalBlockQueue scoped = - new ScopedLocalBlockQueue(queue, Location.at(world, blockX, 0, blockZ), - Location.at(world, blockX + 15, 255, blockZ + 15)); + ScopedQueueCoordinator scoped = + new ScopedQueueCoordinator(queue, Location.at(world, blockX, 0, blockZ), Location.at(world, blockX + 15, 255, blockZ + 15)); if (force != null) { force.run(scoped); } else { @@ -65,7 +59,7 @@ public abstract class ChunkManager { add.run(scoped); } } - queue.flush(); + queue.enqueue(); } else { if (force != null) { forceChunks.put(loc, force); @@ -77,8 +71,8 @@ public abstract class ChunkManager { } } - public static boolean preProcessChunk(BlockVector2 loc, ScopedLocalBlockQueue queue) { - final RunnableVal forceChunk = forceChunks.get(loc); + public static boolean preProcessChunk(BlockVector2 loc, ScopedQueueCoordinator queue) { + final RunnableVal forceChunk = forceChunks.get(loc); if (forceChunk != null) { forceChunk.run(queue); forceChunks.remove(loc); @@ -87,8 +81,8 @@ public abstract class ChunkManager { return false; } - public static boolean postProcessChunk(BlockVector2 loc, ScopedLocalBlockQueue queue) { - final RunnableVal addChunk = forceChunks.get(loc); + public static boolean postProcessChunk(BlockVector2 loc, ScopedQueueCoordinator queue) { + final RunnableVal addChunk = forceChunks.get(loc); if (addChunk != null) { addChunk.run(queue); addChunks.remove(loc); @@ -97,107 +91,6 @@ public abstract class ChunkManager { return false; } - public static void chunkTask(final Plot plot, final RunnableVal task, - final Runnable whenDone, final int allocate) { - final ArrayList regions = new ArrayList<>(plot.getRegions()); - Runnable smallTask = new Runnable() { - @Override public void run() { - if (regions.isEmpty()) { - TaskManager.runTask(whenDone); - return; - } - CuboidRegion value = regions.remove(0); - Location pos1 = Location.at(plot.getWorldName(), value.getMinimumPoint().getX(), 0, - value.getMinimumPoint().getZ()); - Location pos2 = Location.at(plot.getWorldName(), value.getMaximumPoint().getX(), 0, - value.getMaximumPoint().getZ()); - chunkTask(pos1, pos2, task, this, allocate); - } - }; - smallTask.run(); - } - - /** - * The int[] will be in the form: [chunkX, chunkZ, pos1x, pos1z, pos2x, pos2z, isEdge] and will represent the bottom and top parts of the chunk - * - * @param pos1 - * @param pos2 - * @param task - * @param whenDone - */ - public static void chunkTask(Location pos1, Location pos2, final RunnableVal task, - final Runnable whenDone, final int allocate) { - final int p1x = pos1.getX(); - final int p1z = pos1.getZ(); - final int p2x = pos2.getX(); - final int p2z = pos2.getZ(); - final int bcx = p1x >> 4; - final int bcz = p1z >> 4; - final int tcx = p2x >> 4; - final int tcz = p2z >> 4; - final ArrayList chunks = new ArrayList<>(); - - for (int x = bcx; x <= tcx; x++) { - for (int z = bcz; z <= tcz; z++) { - chunks.add(BlockVector2.at(x, z)); - } - } - TaskManager.runTask(new Runnable() { - @Override public void run() { - long start = System.currentTimeMillis(); - while (!chunks.isEmpty() && ((System.currentTimeMillis() - start) < allocate)) { - BlockVector2 chunk = chunks.remove(0); - task.value = new int[7]; - task.value[0] = chunk.getX(); - task.value[1] = chunk.getZ(); - task.value[2] = task.value[0] << 4; - task.value[3] = task.value[1] << 4; - task.value[4] = task.value[2] + 15; - task.value[5] = task.value[3] + 15; - if (task.value[0] == bcx) { - task.value[2] = p1x; - task.value[6] = 1; - } - if (task.value[0] == tcx) { - task.value[4] = p2x; - task.value[6] = 1; - } - if (task.value[1] == bcz) { - task.value[3] = p1z; - task.value[6] = 1; - } - if (task.value[1] == tcz) { - task.value[5] = p2z; - task.value[6] = 1; - } - task.run(); - } - if (!chunks.isEmpty()) { - TaskManager.runTaskLater(this, TaskTime.ticks(1L)); - } else { - TaskManager.runTask(whenDone); - } - } - }); - } - - public abstract CompletableFuture loadChunk(String world, BlockVector2 loc, boolean force); - - public abstract void unloadChunk(String world, BlockVector2 loc, boolean save); - - public Plot hasPlot(String world, BlockVector2 chunk) { - int x1 = chunk.getX() << 4; - int z1 = chunk.getZ() << 4; - int x2 = x1 + 15; - int z2 = z1 + 15; - Location bot = Location.at(world, x1, 0, z1); - Plot plot = bot.getOwnedPlotAbs(); - if (plot != null) { - return plot; - } - Location top = Location.at(world, x2, 0, z2); - plot = top.getOwnedPlotAbs(); - return plot; - } + @Deprecated public abstract CompletableFuture loadChunk(String world, BlockVector2 loc, boolean force); } diff --git a/Core/src/main/java/com/plotsquared/core/util/ChunkUtil.java b/Core/src/main/java/com/plotsquared/core/util/ChunkUtil.java index 0a3b5f369..71fa058e0 100644 --- a/Core/src/main/java/com/plotsquared/core/util/ChunkUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/ChunkUtil.java @@ -25,6 +25,10 @@ */ package com.plotsquared.core.util; +import com.plotsquared.core.location.Location; +import com.sk89q.worldedit.math.BlockVector2; + +import javax.annotation.Nonnull; /** * This cache is used for world generation and just saves a bit of calculation time when checking if something is in the plot area. */ @@ -34,10 +38,10 @@ public class ChunkUtil { * Cache of mapping x,y,z coordinates to the chunk array
* - Used for efficient world generation
*/ - private static short[] x_loc; - private static short[][] y_loc; - private static short[] z_loc; - private static short[][][] CACHE_J = null; + private static final short[] x_loc; + private static final short[][] y_loc; + private static final short[] z_loc; + private static final short[][][] CACHE_J; static { x_loc = new short[4096]; @@ -78,8 +82,7 @@ public class ChunkUtil { * @param z Relative z coordinate * @return J value for xyz position in Array[4096]. */ - public static int getJ(int x, int y, - int z) { + public static int getJ(int x, int y, int z) { return CACHE_J[y][x][z]; } @@ -113,4 +116,22 @@ public class ChunkUtil { public static int getZ(int j) { return z_loc[j]; } + + /** + * Returns true if the region pos1-pos2 contains the chunk + * + * @param pos1 Region minimum point + * @param pos2 Region maximum point + * @param chunk BlockVector2 of chunk coordinates + * @return true if the region pos1-pos2 contains the chunk + */ + public static boolean isWholeChunk(@Nonnull Location pos1, @Nonnull Location pos2, @Nonnull BlockVector2 chunk) { + int x1 = pos1.getX(); + int z1 = pos1.getZ(); + int x2 = pos2.getX(); + int z2 = pos2.getZ(); + int cx = chunk.getX() << 4; + int cz = chunk.getZ() << 4; + return cx > x1 && cz > z1 && cx < x2 && cz < z2; + } } diff --git a/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java b/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java index 5429941c9..12421a71a 100644 --- a/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java @@ -42,7 +42,7 @@ import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; /** * Entity related general utility methods */ -public final class EntityUtil { +public class EntityUtil { private EntityUtil() { throw new UnsupportedOperationException( diff --git a/Core/src/main/java/com/plotsquared/core/util/EventDispatcher.java b/Core/src/main/java/com/plotsquared/core/util/EventDispatcher.java index 1234f05c6..931ed838f 100644 --- a/Core/src/main/java/com/plotsquared/core/util/EventDispatcher.java +++ b/Core/src/main/java/com/plotsquared/core/util/EventDispatcher.java @@ -106,6 +106,9 @@ public class EventDispatcher { eventBus.unregister(listener); } } + public void callGenericEvent(@Nonnull final Object event) { + eventBus.post(event); + } public void callEvent(@Nonnull final PlotEvent event) { eventBus.post(event); diff --git a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java index 49444123c..00e4bb43a 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java @@ -107,7 +107,7 @@ public abstract class PlayerManager

, T> { /** * Get a list of names given a list of UUIDs. - * - Uses the format {@link Captions#PLOT_USER_LIST} for the returned string + * - Uses the format {@link TranslatableCaption#of(String)} of "info.plot_user_list" for the returned string * * @param uuids UUIDs * @return Name list diff --git a/Core/src/main/java/com/plotsquared/core/util/RegionManager.java b/Core/src/main/java/com/plotsquared/core/util/RegionManager.java index 40906237d..f3e745c86 100644 --- a/Core/src/main/java/com/plotsquared/core/util/RegionManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/RegionManager.java @@ -25,26 +25,31 @@ */ package com.plotsquared.core.util; +import com.google.inject.Inject; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotManager; -import com.plotsquared.core.queue.LocalBlockQueue; -import com.plotsquared.core.util.task.RunnableVal; +import com.plotsquared.core.queue.BasicQueueCoordinator; +import com.plotsquared.core.queue.GlobalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.task.TaskTime; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.File; import java.util.Collection; -import java.util.HashSet; import java.util.Set; public abstract class RegionManager { @@ -52,6 +57,13 @@ public abstract class RegionManager { private static final Logger logger = LoggerFactory.getLogger("P2/" + RegionManager.class.getSimpleName()); public static RegionManager manager = null; + private final WorldUtil worldUtil; + private final GlobalBlockQueue blockQueue; + + @Inject public RegionManager(@Nonnull WorldUtil worldUtil, @Nonnull GlobalBlockQueue blockQueue) { + this.worldUtil = worldUtil; + this.blockQueue = blockQueue; + } public static BlockVector2 getRegion(Location location) { int x = location.getX() >> 9; @@ -59,52 +71,6 @@ public abstract class RegionManager { return BlockVector2.at(x, z); } - private final ChunkManager chunkManager; - - public RegionManager(@Nonnull final ChunkManager chunkManager) { - this.chunkManager = chunkManager; - } - - public void largeRegionTask(final String world, final CuboidRegion region, - final RunnableVal task, final Runnable whenDone) { - TaskManager.runTaskAsync(() -> { - HashSet chunks = new HashSet<>(); - Set mcrs = this.getChunkChunks(world); - for (BlockVector2 mcr : mcrs) { - int bx = mcr.getX() << 9; - int bz = mcr.getZ() << 9; - int tx = bx + 511; - int tz = bz + 511; - if (bx <= region.getMaximumPoint().getX() && tx >= region.getMinimumPoint().getX() - && bz <= region.getMaximumPoint().getZ() && tz >= region.getMinimumPoint() - .getZ()) { - for (int x = bx >> 4; x <= (tx >> 4); x++) { - int cbx = x << 4; - int ctx = cbx + 15; - if (cbx <= region.getMaximumPoint().getX() && ctx >= region - .getMinimumPoint().getX()) { - for (int z = bz >> 4; z <= (tz >> 4); z++) { - int cbz = z << 4; - int ctz = cbz + 15; - if (cbz <= region.getMaximumPoint().getZ() && ctz >= region - .getMinimumPoint().getZ()) { - chunks.add(BlockVector2.at(x, z)); - } - } - } - } - } - } - TaskManager.getPlatformImplementation().objectTask(chunks, new RunnableVal() { - @Override public void run(BlockVector2 value) { - chunkManager.loadChunk(world, value, false) - .thenRun(() -> task.run(value)); - } - }).thenAccept(ignore -> - TaskManager.getPlatformImplementation().taskLater(whenDone, TaskTime.ticks(1L))); - }); - } - /** * 0 = Entity * 1 = Animal @@ -112,48 +78,13 @@ public abstract class RegionManager { * 3 = Mob * 4 = Boat * 5 = Misc - * - * @param plot - * @return */ public abstract int[] countEntities(Plot plot); - public Set getChunkChunks(String world) { - File folder = - new File(PlotSquared.platform().getWorldContainer(), world + File.separator + "region"); - File[] regionFiles = folder.listFiles(); - if (regionFiles == null) { - throw new RuntimeException( - "Could not find worlds folder: " + folder + " ? (no read access?)"); - } - HashSet chunks = new HashSet<>(); - for (File file : regionFiles) { - String name = file.getName(); - if (name.endsWith("mca")) { - String[] split = name.split("\\."); - try { - int x = Integer.parseInt(split[1]); - int z = Integer.parseInt(split[2]); - BlockVector2 loc = BlockVector2.at(x, z); - chunks.add(loc); - } catch (NumberFormatException ignored) { - } - } - } - return chunks; - } - - public void deleteRegionFiles(String world, Collection chunks) { - deleteRegionFiles(world, chunks, null); - } - - public void deleteRegionFiles(final String world, final Collection chunks, - final Runnable whenDone) { + public void deleteRegionFiles(final String world, final Collection chunks, final Runnable whenDone) { TaskManager.runTaskAsync(() -> { for (BlockVector2 loc : chunks) { - String directory = - world + File.separator + "region" + File.separator + "r." + loc.getX() + "." - + loc.getZ() + ".mca"; + String directory = world + File.separator + "region" + File.separator + "r." + loc.getX() + "." + loc.getZ() + ".mca"; File file = new File(PlotSquared.platform().getWorldContainer(), directory); logger.info("[P2] - Deleting file: {} (max 1024 chunks)", file.getName()); if (file.exists()) { @@ -164,17 +95,30 @@ public abstract class RegionManager { }); } - public boolean setCuboids(final PlotArea area, final Set regions, - final Pattern blocks, int minY, int maxY) { - LocalBlockQueue queue = area.getQueue(false); + /** + * Set a number of cuboids to a certain block between two y values. + * + * @param queue Nullable {@link QueueCoordinator}. If null, creates own queue and enqueues, + * otherwise writes to the queue but does not enqueue. + * @return true if not enqueued, otherwise whether the created queue enqueued. + */ + public boolean setCuboids(final PlotArea area, + final Set regions, + final Pattern blocks, + int minY, + int maxY, + @Nullable QueueCoordinator queue) { + boolean enqueue = false; + if (queue == null) { + queue = area.getQueue(); + enqueue = true; + } for (CuboidRegion region : regions) { - Location pos1 = Location.at(area.getWorldName(), region.getMinimumPoint().getX(), minY, - region.getMinimumPoint().getZ()); - Location pos2 = Location.at(area.getWorldName(), region.getMaximumPoint().getX(), maxY, - region.getMaximumPoint().getZ()); + Location pos1 = Location.at(area.getWorldName(), region.getMinimumPoint().getX(), minY, region.getMinimumPoint().getZ()); + Location pos2 = Location.at(area.getWorldName(), region.getMaximumPoint().getX(), maxY, region.getMaximumPoint().getZ()); queue.setCuboid(pos1, pos2, blocks); } - return queue.enqueue(); + return !enqueue || queue.enqueue(); } /** @@ -196,27 +140,113 @@ public abstract class RegionManager { /** * Copy a region to a new location (in the same world) */ - public abstract boolean copyRegion(Location pos1, Location pos2, Location newPos, - Runnable whenDone); + public boolean copyRegion(final Location pos1, final Location pos2, final Location newPos, final Runnable whenDone) { + final int relX = newPos.getX() - pos1.getX(); + final int relZ = newPos.getZ() - pos1.getZ(); + final com.sk89q.worldedit.world.World oldWorld = worldUtil.getWeWorld(pos1.getWorldName()); + final com.sk89q.worldedit.world.World newWorld = worldUtil.getWeWorld(newPos.getWorldName()); + final QueueCoordinator copyFrom = blockQueue.getNewQueue(oldWorld); + final BasicQueueCoordinator copyTo = (BasicQueueCoordinator) blockQueue.getNewQueue(newWorld); + copyFromTo(pos1, pos2, relX, relZ, oldWorld, copyFrom, copyTo, false); + copyFrom.setCompleteTask(copyTo::enqueue); + copyFrom + .addReadChunks(new CuboidRegion(BlockVector3.at(pos1.getX(), 0, pos1.getZ()), BlockVector3.at(pos2.getX(), 0, pos2.getZ())).getChunks()); + copyTo.setCompleteTask(whenDone); + copyFrom.enqueue(); + return true; + } /** * Assumptions:
* - pos1 and pos2 are in the same plot
* It can be harmful to the world if parameters outside this scope are provided - * - * @param pos1 - * @param pos2 - * @param whenDone - * @return */ - public abstract boolean regenerateRegion(Location pos1, Location pos2, boolean ignoreAugment, - Runnable whenDone); + public abstract boolean regenerateRegion(Location pos1, Location pos2, boolean ignoreAugment, Runnable whenDone); public abstract void clearAllEntities(Location pos1, Location pos2); - public abstract void swap(Location bot1, Location top1, Location bot2, Location top2, - Runnable whenDone); + public void swap(Location pos1, Location pos2, Location swapPos, final Runnable whenDone) { + int relX = swapPos.getX() - pos1.getX(); + int relZ = swapPos.getZ() - pos1.getZ(); - public abstract void setBiome(CuboidRegion region, int extendBiome, BiomeType biome, - String world, Runnable whenDone); + World world1 = worldUtil.getWeWorld(pos1.getWorldName()); + World world2 = worldUtil.getWeWorld(swapPos.getWorldName()); + + QueueCoordinator fromQueue1 = blockQueue.getNewQueue(world1); + QueueCoordinator fromQueue2 = blockQueue.getNewQueue(world2); + fromQueue1.setUnloadAfter(false); + fromQueue2.setUnloadAfter(false); + fromQueue1.addReadChunks(new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()).getChunks()); + fromQueue2.addReadChunks(new CuboidRegion(swapPos.getBlockVector3(), + BlockVector3.at(swapPos.getX() + pos2.getX() - pos1.getX(), 0, swapPos.getZ() + pos2.getZ() - pos1.getZ())).getChunks()); + QueueCoordinator toQueue1 = blockQueue.getNewQueue(world1); + QueueCoordinator toQueue2 = blockQueue.getNewQueue(world2); + + copyFromTo(pos1, pos2, relX, relZ, world1, fromQueue1, toQueue2, true); + copyFromTo(pos1, pos2, relX, relZ, world1, fromQueue2, toQueue1, true); + fromQueue1.setCompleteTask(fromQueue2::enqueue); + fromQueue2.setCompleteTask(toQueue1::enqueue); + toQueue1.setCompleteTask(toQueue2::enqueue); + toQueue2.setCompleteTask(whenDone); + } + + private void copyFromTo(Location pos1, + Location pos2, + int relX, + int relZ, + World world1, + QueueCoordinator fromQueue, + QueueCoordinator toQueue, + boolean removeEntities) { + fromQueue.setChunkConsumer(chunk -> { + int cx = chunk.getX(); + int cz = chunk.getZ(); + int cbx = cx << 4; + int cbz = cz << 4; + int bx = Math.max(pos1.getX() & 15, 0); + int bz = Math.max(pos1.getZ() & 15, 0); + int tx = Math.min(pos2.getX() & 15, 15); + int tz = Math.min(pos2.getZ() & 15, 15); + for (int y = 0; y < 256; y++) { + for (int x = bx; x <= tx; x++) { + for (int z = bz; z <= tz; z++) { + int rx = cbx + x; + int rz = cbz + z; + BlockVector3 loc = BlockVector3.at(rx, y, rz); + toQueue.setBlock(rx + relX, y, rz + relZ, world1.getFullBlock(loc)); + toQueue.setBiome(rx + relX, y, rz + relZ, world1.getBiome(loc)); + } + } + } + Region region = new CuboidRegion(BlockVector3.at(cbx + bx, 0, cbz + bz), BlockVector3.at(cbx + tx, 255, cbz + tz)); + toQueue.addEntities(world1.getEntities(region)); + if (removeEntities) { + for (Entity entity : world1.getEntities(region)) { + entity.remove(); + } + } + }); + } + + public void setBiome(final CuboidRegion region, final int extendBiome, final BiomeType biome, final String world, final Runnable whenDone) { + Location pos1 = Location + .at(world, region.getMinimumPoint().getX() - extendBiome, region.getMinimumPoint().getY(), region.getMinimumPoint().getZ() - extendBiome); + Location pos2 = Location + .at(world, region.getMaximumPoint().getX() + extendBiome, region.getMaximumPoint().getY(), region.getMaximumPoint().getZ() + extendBiome); + final QueueCoordinator queue = blockQueue.getNewQueue(worldUtil.getWeWorld(world)); + + final int minX = pos1.getX(); + final int minZ = pos1.getZ(); + final int maxX = pos2.getX(); + final int maxZ = pos2.getZ(); + queue.addReadChunks(region.getChunks()); + queue.setChunkConsumer(blockVector2 -> { + final int cx = blockVector2.getX() << 4; + final int cz = blockVector2.getZ() << 4; + WorldUtil.setBiome(world, Math.max(minX, cx), Math.max(minZ, cz), Math.min(maxX, cx + 15), Math.min(maxZ, cz + 15), biome); + worldUtil.refreshChunk(blockVector2.getBlockX(), blockVector2.getBlockZ(), world); + }); + queue.setCompleteTask(whenDone); + queue.enqueue(); + } } diff --git a/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java b/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java index 09aebcd84..d02284930 100644 --- a/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java +++ b/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java @@ -32,7 +32,7 @@ import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.schematic.Schematic; -import com.plotsquared.core.queue.LocalBlockQueue; +import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.net.AbstractDelegateOutputStream; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; @@ -107,18 +107,18 @@ public abstract class SchematicHandler { private static final Logger logger = LoggerFactory.getLogger("P2/" + SchematicHandler.class.getSimpleName()); public static SchematicHandler manager; - - private boolean exportAll = false; - private final WorldUtil worldUtil; + private boolean exportAll = false; public SchematicHandler(@Nonnull final WorldUtil worldUtil) { this.worldUtil = worldUtil; } - public static void upload(@Nullable UUID uuid, @Nullable final String file, - @Nonnull final String extension, @Nullable final RunnableVal writeTask, - @Nonnull final RunnableVal whenDone) { + public static void upload(@Nullable UUID uuid, + @Nullable final String file, + @Nonnull final String extension, + @Nullable final RunnableVal writeTask, + @Nonnull final RunnableVal whenDone) { if (writeTask == null) { TaskManager.runTask(whenDone); return; @@ -148,23 +148,16 @@ public abstract class SchematicHandler { con.setDoOutput(true); con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); try (OutputStream output = con.getOutputStream(); - PrintWriter writer = new PrintWriter( - new OutputStreamWriter(output, StandardCharsets.UTF_8), true)) { + PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8), true)) { String CRLF = "\r\n"; writer.append("--" + boundary).append(CRLF); writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF); - writer.append( - "Content-Type: text/plain; charset=" + StandardCharsets.UTF_8.displayName()) - .append(CRLF); + writer.append("Content-Type: text/plain; charset=" + StandardCharsets.UTF_8.displayName()).append(CRLF); String param = "value"; writer.append(CRLF).append(param).append(CRLF).flush(); writer.append("--" + boundary).append(CRLF); - writer.append( - "Content-Disposition: form-data; name=\"schematicFile\"; filename=\"" - + filename + '"').append(CRLF); - writer - .append("Content-Type: " + URLConnection.guessContentTypeFromName(filename)) - .append(CRLF); + writer.append("Content-Disposition: form-data; name=\"schematicFile\"; filename=\"" + filename + '"').append(CRLF); + writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(filename)).append(CRLF); writer.append("Content-Transfer-Encoding: binary").append(CRLF); writer.append(CRLF).flush(); writeTask.value = new AbstractDelegateOutputStream(output) { @@ -194,8 +187,7 @@ public abstract class SchematicHandler { }); } - public boolean exportAll(Collection collection, final File outputDir, - final String namingScheme, final Runnable ifSuccess) { + public boolean exportAll(Collection collection, final File outputDir, final String namingScheme, final Runnable ifSuccess) { if (this.exportAll) { return false; } @@ -224,13 +216,10 @@ public abstract class SchematicHandler { final String name; if (namingScheme == null) { - name = - plot.getId().getX() + ";" + plot.getId().getY() + ',' + plot.getArea() + ',' + owner; + name = plot.getId().getX() + ";" + plot.getId().getY() + ',' + plot.getArea() + ',' + owner; } else { - name = namingScheme.replaceAll("%id%", plot.getId().toString()) - .replaceAll("%idx%", plot.getId().getX() + "") - .replaceAll("%idy%", plot.getId().getY() + "") - .replaceAll("%world%", plot.getArea().toString()); + name = namingScheme.replaceAll("%id%", plot.getId().toString()).replaceAll("%idx%", plot.getId().getX() + "") + .replaceAll("%idy%", plot.getId().getY() + "").replaceAll("%world%", plot.getArea().toString()); } final String directory; @@ -267,9 +256,13 @@ public abstract class SchematicHandler { * @param xOffset offset x to paste it from plot origin * @param zOffset offset z to paste it from plot origin */ - public void paste(final Schematic schematic, final Plot plot, final int xOffset, - final int yOffset, final int zOffset, final boolean autoHeight, - final RunnableVal whenDone) { + public void paste(final Schematic schematic, + final Plot plot, + final int xOffset, + final int yOffset, + final int zOffset, + final boolean autoHeight, + final RunnableVal whenDone) { TaskManager.runTask(() -> { if (whenDone != null) { @@ -280,17 +273,14 @@ public abstract class SchematicHandler { return; } try { - final LocalBlockQueue queue = plot.getArea().getQueue(false); BlockVector3 dimension = schematic.getClipboard().getDimensions(); final int WIDTH = dimension.getX(); final int LENGTH = dimension.getZ(); final int HEIGHT = dimension.getY(); // Validate dimensions CuboidRegion region = plot.getLargestRegion(); - if (((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset - + 1) < WIDTH) || ( - (region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset - + 1) < LENGTH) || (HEIGHT > 256)) { + if (((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || ( + (region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT > 256)) { TaskManager.runTask(whenDone); return; } @@ -306,9 +296,8 @@ public abstract class SchematicHandler { if (pw instanceof ClassicPlotWorld) { y_offset_actual = yOffset + ((ClassicPlotWorld) pw).PLOT_HEIGHT; } else { - y_offset_actual = yOffset + 1 + this.worldUtil - .getHighestBlockSynchronous(plot.getWorldName(), - region.getMinimumPoint().getX() + 1, + y_offset_actual = yOffset + 1 + this.worldUtil + .getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1, region.getMinimumPoint().getZ() + 1); } } @@ -316,8 +305,8 @@ public abstract class SchematicHandler { y_offset_actual = yOffset; } - final Location pos1 = Location.at(plot.getWorldName(), region.getMinimumPoint().getX() + xOffset, y_offset_actual, - region.getMinimumPoint().getZ() + zOffset); + final Location pos1 = Location + .at(plot.getWorldName(), region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset); final Location pos2 = pos1.add(WIDTH - 1, HEIGHT - 1, LENGTH - 1); final int p1x = pos1.getX(); @@ -328,58 +317,32 @@ public abstract class SchematicHandler { final int bcz = p1z >> 4; final int tcx = p2x >> 4; final int tcz = p2z >> 4; + // Paste schematic here + final QueueCoordinator queue = plot.getArea().getQueue(); - ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { - @Override public void run(int[] value) { - BlockVector2 chunk = BlockVector2.at(value[0], value[1]); - int x = chunk.getX(); - int z = chunk.getZ(); - int xxb = x << 4; - int zzb = z << 4; - int xxt = xxb + 15; - int zzt = zzb + 15; - if (x == bcx) { - xxb = p1x; - } - if (x == tcx) { - xxt = p2x; - } - if (z == bcz) { - zzb = p1z; - } - if (z == tcz) { - zzt = p2z; - } - // Paste schematic here - - for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) { - int yy = y_offset_actual + ry; - if (yy > 255) { - continue; - } - for (int rz = zzb - p1z; rz <= (zzt - p1z); rz++) { - for (int rx = xxb - p1x; rx <= (xxt - p1x); rx++) { - int xx = p1x + xOffset + rx; - int zz = p1z + zOffset + rz; - BaseBlock id = blockArrayClipboard - .getFullBlock(BlockVector3.at(rx, ry, rz)); - queue.setBlock(xx, yy, zz, id); - if (ry == 0) { - BiomeType biome = - blockArrayClipboard.getBiome(BlockVector2.at(rx, rz)); - queue.setBiome(xx, zz, biome); - } - } + for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) { + int yy = y_offset_actual + ry; + if (yy > 255) { + continue; + } + for (int rz = 0; rz <= blockArrayClipboard.getDimensions().getZ(); rz++) { + for (int rx = 0; rx < blockArrayClipboard.getDimensions().getX(); rx++) { + int xx = p1x + xOffset + rx; + int zz = p1z + zOffset + rz; + BaseBlock id = blockArrayClipboard.getFullBlock(BlockVector3.at(rx, ry, rz)); + queue.setBlock(xx, yy, zz, id); + if (ry == 0) { + BiomeType biome = blockArrayClipboard.getBiome(BlockVector3.at(rx, ry, rz)); + queue.setBiome(xx, yy, zz, biome); } } - queue.enqueue(); } - }, () -> { - if (whenDone != null) { - whenDone.value = true; - whenDone.run(); - } - }, 10); + } + if (whenDone != null) { + whenDone.value = true; + } + queue.setCompleteTask(whenDone); + queue.enqueue(); } catch (Exception e) { e.printStackTrace(); TaskManager.runTask(whenDone); @@ -387,8 +350,7 @@ public abstract class SchematicHandler { }); } - public abstract boolean restoreTile(LocalBlockQueue queue, CompoundTag tag, int x, int y, - int z); + public abstract boolean restoreTile(QueueCoordinator queue, CompoundTag tag, int x, int y, int z); /** * Get a schematic @@ -397,8 +359,7 @@ public abstract class SchematicHandler { * @return schematic if found, else null */ public Schematic getSchematic(String name) throws UnsupportedFormatException { - File parent = - FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS); + File parent = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS); if (!parent.exists()) { if (!parent.mkdir()) { throw new RuntimeException("Could not create schematic parent directory"); @@ -407,11 +368,9 @@ public abstract class SchematicHandler { if (!name.endsWith(".schem") && !name.endsWith(".schematic")) { name = name + ".schem"; } - File file = FileUtils.getFile(PlotSquared.platform().getDirectory(), - Settings.Paths.SCHEMATICS + File.separator + name); + File file = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS + File.separator + name); if (!file.exists()) { - file = FileUtils.getFile(PlotSquared.platform().getDirectory(), - Settings.Paths.SCHEMATICS + File.separator + name); + file = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS + File.separator + name); } return getSchematic(file); } @@ -422,12 +381,10 @@ public abstract class SchematicHandler { * @return Immutable collection with schematic names */ public Collection getSchematicNames() { - final File parent = - FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS); + final File parent = FileUtils.getFile(PlotSquared.platform().getDirectory(), Settings.Paths.SCHEMATICS); final List names = new ArrayList<>(); if (parent.exists()) { - final String[] rawNames = - parent.list((dir, name) -> name.endsWith(".schematic") || name.endsWith(".schem")); + final String[] rawNames = parent.list((dir, name) -> name.endsWith(".schematic") || name.endsWith(".schem")); if (rawNames != null) { final List transformed = Arrays.stream(rawNames) //.map(rawName -> rawName.substring(0, rawName.length() - 10)) @@ -457,8 +414,7 @@ public abstract class SchematicHandler { e.printStackTrace(); } } else { - throw new UnsupportedFormatException( - "This schematic format is not recognised or supported."); + throw new UnsupportedFormatException("This schematic format is not recognised or supported."); } return null; } @@ -476,14 +432,12 @@ public abstract class SchematicHandler { public Schematic getSchematic(@Nonnull InputStream is) { try { - SpongeSchematicReader schematicReader = - new SpongeSchematicReader(new NBTInputStream(new GZIPInputStream(is))); + SpongeSchematicReader schematicReader = new SpongeSchematicReader(new NBTInputStream(new GZIPInputStream(is))); Clipboard clip = schematicReader.read(); return new Schematic(clip); } catch (IOException ignored) { try { - MCEditSchematicReader schematicReader = - new MCEditSchematicReader(new NBTInputStream(new GZIPInputStream(is))); + MCEditSchematicReader schematicReader = new MCEditSchematicReader(new NBTInputStream(new GZIPInputStream(is))); Clipboard clip = schematicReader.read(); return new Schematic(clip); } catch (IOException e) { @@ -500,8 +454,7 @@ public abstract class SchematicHandler { URL url = new URL(website); URLConnection connection = new URL(url.toString()).openConnection(); connection.setRequestProperty("User-Agent", "Mozilla/5.0"); - try (BufferedReader reader = new BufferedReader( - new InputStreamReader(connection.getInputStream()))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { rawJSON = reader.lines().collect(Collectors.joining()); } JSONArray array = new JSONArray(rawJSON); @@ -524,8 +477,7 @@ public abstract class SchematicHandler { } upload(uuid, file, "schem", new RunnableVal() { @Override public void run(OutputStream output) { - try (NBTOutputStream nos = new NBTOutputStream( - new GZIPOutputStream(output, true))) { + try (NBTOutputStream nos = new NBTOutputStream(new GZIPOutputStream(output, true))) { nos.writeNamedTag("Schematic", tag); } catch (IOException e1) { e1.printStackTrace(); @@ -548,8 +500,7 @@ public abstract class SchematicHandler { try { File tmp = FileUtils.getFile(PlotSquared.platform().getDirectory(), path); tmp.getParentFile().mkdirs(); - try (NBTOutputStream nbtStream = new NBTOutputStream( - new GZIPOutputStream(new FileOutputStream(tmp)))) { + try (NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(new FileOutputStream(tmp)))) { nbtStream.writeNamedTag("Schematic", tag); } } catch (FileNotFoundException e) { @@ -561,8 +512,7 @@ public abstract class SchematicHandler { return true; } - public void getCompoundTag(final String world, final Set regions, - final RunnableVal whenDone) { + public void getCompoundTag(final String world, final Set regions, final RunnableVal whenDone) { // async TaskManager.runTaskAsync(() -> { // Main positions @@ -570,17 +520,15 @@ public abstract class SchematicHandler { final Location bot = corners[0]; final Location top = corners[1]; - CuboidRegion cuboidRegion = - new CuboidRegion(this.worldUtil.getWeWorld(world), bot.getBlockVector3(), - top.getBlockVector3()); + CuboidRegion cuboidRegion = new CuboidRegion(this.worldUtil.getWeWorld(world), bot.getBlockVector3(), top.getBlockVector3()); final int width = cuboidRegion.getWidth(); int height = cuboidRegion.getHeight(); final int length = cuboidRegion.getLength(); Map schematic = new HashMap<>(); schematic.put("Version", new IntTag(2)); - schematic.put("DataVersion", new IntTag(WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.WORLD_EDITING).getDataVersion())); + schematic.put("DataVersion", + new IntTag(WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); Map metadata = new HashMap<>(); metadata.put("WEOffsetX", new IntTag(0)); @@ -615,14 +563,12 @@ public abstract class SchematicHandler { schematic.put("Palette", new CompoundTag(paletteTag)); schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray())); - schematic - .put("TileEntities", new ListTag(CompoundTag.class, tileEntities)); + schematic.put("TileEntities", new ListTag(CompoundTag.class, tileEntities)); schematic.put("BiomePaletteMax", new IntTag(biomePalette.size())); Map biomePaletteTag = new HashMap<>(); - biomePalette.forEach( - (key, value) -> biomePaletteTag.put(key, new IntTag(value))); + biomePalette.forEach((key, value) -> biomePaletteTag.put(key, new IntTag(value))); schematic.put("BiomePalette", new CompoundTag(biomePaletteTag)); schematic.put("BiomeData", new ByteArrayTag(biomeBuffer.toByteArray())); @@ -653,33 +599,23 @@ public abstract class SchematicHandler { final Runnable zTask = new Runnable() { @Override public void run() { long zstart = System.currentTimeMillis(); - while (ziter.hasNext() - && System.currentTimeMillis() - zstart < 20) { + while (ziter.hasNext() && System.currentTimeMillis() - zstart < 20) { final int z = ziter.next(); - Iterator xiter = - IntStream.range(p1x, p2x + 1).iterator(); + Iterator xiter = IntStream.range(p1x, p2x + 1).iterator(); final Runnable xTask = new Runnable() { @Override public void run() { long xstart = System.currentTimeMillis(); final int ry = y - sy; final int rz = z - p1z; - while (xiter.hasNext() - && System.currentTimeMillis() - xstart - < 20) { + while (xiter.hasNext() && System.currentTimeMillis() - xstart < 20) { final int x = xiter.next(); final int rx = x - p1x; - BlockVector3 point = - BlockVector3.at(x, y, z); - BaseBlock block = cuboidRegion.getWorld() - .getFullBlock(point); + BlockVector3 point = BlockVector3.at(x, y, z); + BaseBlock block = cuboidRegion.getWorld().getFullBlock(point); if (block.getNbtData() != null) { - Map values = - new HashMap<>(); - for (Map.Entry entry : block - .getNbtData().getValue() - .entrySet()) { - values.put(entry.getKey(), - entry.getValue()); + Map values = new HashMap<>(); + for (Map.Entry entry : block.getNbtData().getValue().entrySet()) { + values.put(entry.getKey(), entry.getValue()); } // Remove 'id' if it exists. We want 'Id' values.remove("id"); @@ -689,16 +625,12 @@ public abstract class SchematicHandler { values.remove("y"); values.remove("z"); - values.put("Id", - new StringTag(block.getNbtId())); - values.put("Pos", new IntArrayTag( - new int[] {rx, ry, rz})); + values.put("Id", new StringTag(block.getNbtId())); + values.put("Pos", new IntArrayTag(new int[] {rx, ry, rz})); - tileEntities - .add(new CompoundTag(values)); + tileEntities.add(new CompoundTag(values)); } - String blockKey = - block.toImmutableState().getAsString(); + String blockKey = block.toImmutableState().getAsString(); int blockId; if (palette.containsKey(blockKey)) { blockId = palette.get(blockKey); @@ -717,8 +649,7 @@ public abstract class SchematicHandler { continue; } BlockVector2 pt = BlockVector2.at(x, z); - BiomeType biome = - cuboidRegion.getWorld().getBiome(pt); + BiomeType biome = cuboidRegion.getWorld().getBiome(pt); String biomeStr = biome.getId(); int biomeId; if (biomePalette.containsKey(biomeStr)) { diff --git a/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java b/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java index b0d9b9158..0cd1f93cd 100644 --- a/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java @@ -56,6 +56,7 @@ import java.io.IOException; import java.io.OutputStream; import java.net.URL; import java.util.Collection; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -68,20 +69,14 @@ import java.util.zip.ZipOutputStream; public abstract class WorldUtil { - private final RegionManager regionManager; - - public WorldUtil(@Nonnull final RegionManager regionManager) { - this.regionManager = regionManager; - } - /** * Set the biome in a region * * @param world World name - * @param p1x Min X - * @param p1z Min Z - * @param p2x Max X - * @param p2z Max Z + * @param p1x Min X + * @param p1z Min Z + * @param p2x Max X + * @param p2z Max Z * @param biome Biome */ public static void setBiome(String world, int p1x, int p1z, int p2x, int p2z, BiomeType biome) { @@ -135,8 +130,7 @@ public abstract class WorldUtil { * @param name Block name * @return Comparison result containing the closets matching block */ - @Nonnull public abstract StringComparison.ComparisonResult getClosestBlock( - @Nonnull String name); + @Nonnull public abstract StringComparison.ComparisonResult getClosestBlock(@Nonnull String name); /** * Set the block at the specified location to a sign, with given text @@ -156,8 +150,7 @@ public abstract class WorldUtil { * @param z Chunk Z coordinate * @param result Result consumer */ - public abstract void getBiome(@Nonnull String world, int x, int z, - @Nonnull Consumer result); + public abstract void getBiome(@Nonnull String world, int x, int z, @Nonnull Consumer result); /** * Get the biome in a given chunk, asynchronously @@ -168,8 +161,7 @@ public abstract class WorldUtil { * @return Biome * @deprecated Use {@link #getBiome(String, int, int, Consumer)} */ - @Deprecated @Nonnull public abstract BiomeType getBiomeSynchronous(@Nonnull String world, int x, - int z); + @Deprecated @Nonnull public abstract BiomeType getBiomeSynchronous(@Nonnull String world, int x, int z); /** * Get the block at a given location (asynchronously) @@ -196,8 +188,7 @@ public abstract class WorldUtil { * @param z Z coordinate * @param result Result consumer */ - public abstract void getHighestBlock(@Nonnull String world, int x, int z, - @Nonnull IntConsumer result); + public abstract void getHighestBlock(@Nonnull String world, int x, int z, @Nonnull IntConsumer result); /** @@ -209,8 +200,7 @@ public abstract class WorldUtil { * @return Result * @deprecated Use {@link #getHighestBlock(String, int, int, IntConsumer)} */ - @Deprecated @Nonnegative - public abstract int getHighestBlockSynchronous(@Nonnull String world, int x, int z); + @Deprecated @Nonnegative public abstract int getHighestBlockSynchronous(@Nonnull String world, int x, int z); /** * Set the biome in a region @@ -219,8 +209,7 @@ public abstract class WorldUtil { * @param region Region * @param biome New biome */ - public abstract void setBiomes(@Nonnull String world, @Nonnull CuboidRegion region, - @Nonnull BiomeType biome); + public abstract void setBiomes(@Nonnull String world, @Nonnull CuboidRegion region, @Nonnull BiomeType biome); /** * Get the WorldEdit {@link com.sk89q.worldedit.world.World} corresponding to a world name @@ -230,8 +219,16 @@ public abstract class WorldUtil { */ @Nonnull public abstract com.sk89q.worldedit.world.World getWeWorld(@Nonnull String world); - public void upload(@Nonnull final Plot plot, @Nullable final UUID uuid, - @Nullable final String file, @Nonnull final RunnableVal whenDone) { + /** + * Refresh (resend) chunk to player. Usually after setting the biome + * + * @param x Chunk x location + * @param z Chunk z location + * @param world World of the chunk + */ + public abstract void refreshChunk(int x, int z, String world); + + public void upload(@Nonnull final Plot plot, @Nullable final UUID uuid, @Nullable final String file, @Nonnull final RunnableVal whenDone) { plot.getHome(home -> SchematicHandler.upload(uuid, file, "zip", new RunnableVal() { @Override public void run(OutputStream output) { try (final ZipOutputStream zos = new ZipOutputStream(output)) { @@ -240,8 +237,7 @@ public abstract class WorldUtil { if (dat != null) { ZipEntry ze = new ZipEntry("world" + File.separator + dat.getName()); zos.putNextEntry(ze); - try (NBTInputStream nis = new NBTInputStream( - new GZIPInputStream(new FileInputStream(dat)))) { + try (NBTInputStream nis = new NBTInputStream(new GZIPInputStream(new FileInputStream(dat)))) { CompoundTag tag = (CompoundTag) nis.readNamedTag().getTag(); CompoundTag data = (CompoundTag) tag.getValue().get("Data"); Map map = ReflectionUtils.getMap(data.getValue()); @@ -249,8 +245,7 @@ public abstract class WorldUtil { map.put("SpawnY", new IntTag(home.getY())); map.put("SpawnZ", new IntTag(home.getZ())); try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { - try (NBTOutputStream out = new NBTOutputStream( - new GZIPOutputStream(baos, true))) { + try (NBTOutputStream out = new NBTOutputStream(new GZIPOutputStream(baos, true))) { //TODO Find what this should be called out.writeNamedTag("Schematic????", tag); } @@ -267,18 +262,14 @@ public abstract class WorldUtil { int brz = bot.getZ() >> 9; int trx = top.getX() >> 9; int trz = top.getZ() >> 9; - Set files = regionManager.getChunkChunks(bot.getWorldName()); + Set files = getChunkChunks(bot.getWorldName()); for (BlockVector2 mca : files) { - if (mca.getX() >= brx && mca.getX() <= trx && mca.getZ() >= brz - && mca.getZ() <= trz) { - final File file = - getMcr(plot.getWorldName(), mca.getX(), mca.getZ()); + if (mca.getX() >= brx && mca.getX() <= trx && mca.getZ() >= brz && mca.getZ() <= trz) { + final File file = getMcr(plot.getWorldName(), mca.getX(), mca.getZ()); if (file != null) { //final String name = "r." + (x - cx) + "." + (z - cz) + ".mca"; String name = file.getName(); - final ZipEntry ze = new ZipEntry( - "world" + File.separator + "region" + File.separator - + name); + final ZipEntry ze = new ZipEntry("world" + File.separator + "region" + File.separator + name); zos.putNextEntry(ze); try (FileInputStream in = new FileInputStream(file)) { int len; @@ -302,9 +293,7 @@ public abstract class WorldUtil { } @Nullable final File getDat(@Nonnull final String world) { - File file = new File( - PlotSquared.platform().getWorldContainer() + File.separator + world + File.separator - + "level.dat"); + File file = new File(PlotSquared.platform().getWorldContainer() + File.separator + world + File.separator + "level.dat"); if (file.exists()) { return file; } @@ -312,14 +301,38 @@ public abstract class WorldUtil { } @Nullable private File getMcr(@Nonnull final String world, final int x, final int z) { - final File file = new File(PlotSquared.platform().getWorldContainer(), - world + File.separator + "region" + File.separator + "r." + x + '.' + z + ".mca"); + final File file = + new File(PlotSquared.platform().getWorldContainer(), world + File.separator + "region" + File.separator + "r." + x + '.' + z + ".mca"); if (file.exists()) { return file; } return null; } + + public Set getChunkChunks(String world) { + File folder = new File(PlotSquared.platform().getWorldContainer(), world + File.separator + "region"); + File[] regionFiles = folder.listFiles(); + if (regionFiles == null) { + throw new RuntimeException("Could not find worlds folder: " + folder + " ? (no read access?)"); + } + HashSet chunks = new HashSet<>(); + for (File file : regionFiles) { + String name = file.getName(); + if (name.endsWith("mca")) { + String[] split = name.split("\\."); + try { + int x = Integer.parseInt(split[1]); + int z = Integer.parseInt(split[2]); + BlockVector2 loc = BlockVector2.at(x, z); + chunks.add(loc); + } catch (NumberFormatException ignored) { + } + } + } + return chunks; + } + /** * Check if two blocks are the same type) * @@ -383,7 +396,6 @@ public abstract class WorldUtil { * @param chunk Chunk coordinates * @return Tile entity count */ - @Nonnegative public abstract int getTileEntityCount(@Nonnull String world, - @Nonnull BlockVector2 chunk); + @Nonnegative public abstract int getTileEntityCount(@Nonnull String world, @Nonnull BlockVector2 chunk); } diff --git a/Core/src/main/java/com/plotsquared/core/util/placeholders/Placeholder.java b/Core/src/main/java/com/plotsquared/core/util/placeholders/Placeholder.java new file mode 100644 index 000000000..a6e42fbdb --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/placeholders/Placeholder.java @@ -0,0 +1,60 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.util.placeholders; + +import com.google.common.base.Preconditions; +import com.plotsquared.core.player.PlotPlayer; +import org.jetbrains.annotations.NotNull; + +/** + * A placeholder is a keyed value that gets replaced by a {@link PlotPlayer player}-specific value at runtime + */ +public abstract class Placeholder { + + private final String key; + + public Placeholder(@NotNull final String key) { + this.key = Preconditions.checkNotNull(key, "Key may not be null"); + } + + /** + * Get the value of the placeholder for a particular player + * + * @param player Player + * @return Placeholder value. Return {@code ""} if no placeholder value can be returned + */ + @NotNull public abstract String getValue(@NotNull final PlotPlayer player); + + /** + * Get the placeholder key + * + * @return Placeholder key + */ + @NotNull public final String getKey() { + return this.key; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/placeholders/PlaceholderRegistry.java b/Core/src/main/java/com/plotsquared/core/util/placeholders/PlaceholderRegistry.java new file mode 100644 index 000000000..b45a1032f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/placeholders/PlaceholderRegistry.java @@ -0,0 +1,234 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.util.placeholders; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.flag.GlobalFlagContainer; +import com.plotsquared.core.plot.flag.PlotFlag; +import com.plotsquared.core.util.EventDispatcher; +import com.plotsquared.core.util.PlayerManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiFunction; + +/** + * Registry that contains {@link Placeholder placeholders} + */ +public final class PlaceholderRegistry { + + private final Map placeholders; + private final EventDispatcher eventDispatcher; + + public PlaceholderRegistry(@NotNull final EventDispatcher eventDispatcher) { + this.placeholders = Maps.newHashMap(); + this.eventDispatcher = eventDispatcher; + this.registerDefault(); + } + + private void registerDefault() { + final GlobalFlagContainer globalFlagContainer = GlobalFlagContainer.getInstance(); + for (final PlotFlag flag : globalFlagContainer.getRecognizedPlotFlags()) { + this.registerPlaceholder(new PlotFlagPlaceholder(flag, true)); + this.registerPlaceholder(new PlotFlagPlaceholder(flag, false)); + } + GlobalFlagContainer.getInstance().subscribe((flag, type) -> { + this.registerPlaceholder(new PlotFlagPlaceholder(flag, true)); + this.registerPlaceholder(new PlotFlagPlaceholder(flag, false)); + }); + this.createPlaceholder("currentplot_world", player -> player.getLocation().getWorldName()); + this.createPlaceholder("has_plot", player -> player.getPlotCount() > 0 ? "true" : "false"); + this.createPlaceholder("allowed_plot_count", player -> Integer.toString(player.getAllowedPlots())); + this.createPlaceholder("plot_count", player -> Integer.toString(player.getPlotCount())); + this.createPlaceholder("currentplot_alias", (player, plot) -> plot.getAlias()); + this.createPlaceholder("currentplot_owner", (player, plot) -> { + final UUID plotOwner = plot.getOwnerAbs(); + if (plotOwner == null) { + return ""; + } + + try { + return PlayerManager.getName(plotOwner, false); + } catch (final Exception ignored) {} + + return "unknown"; + }); + this.createPlaceholder("currentplot_members", (player, plot) -> { + if (plot.getMembers() == null && plot.getTrusted() == null) { + return "0"; + } + return String.valueOf(plot.getMembers().size() + plot.getTrusted().size()); + }); + this.createPlaceholder("currentplot_members_added", (player, plot) -> { + if (plot.getMembers() == null) { + return "0"; + } + return String.valueOf(plot.getMembers().size()); + }); + this.createPlaceholder("currentplot_members_trusted", (player, plot) -> { + if (plot.getTrusted() == null) { + return "0"; + } + return String.valueOf(plot.getTrusted().size()); + }); + this.createPlaceholder("currentplot_members_denied", (player, plot) -> { + if (plot.getDenied() == null) { + return "0"; + } + return String.valueOf(plot.getDenied().size()); + }); + this.createPlaceholder("has_build_rights", (player, plot) -> + plot.isAdded(player.getUUID()) ? "true" : "false"); + this.createPlaceholder("currentplot_x", (player, plot) -> Integer.toString(plot.getId().getX())); + this.createPlaceholder("currentplot_y", (player, plot) -> Integer.toString(plot.getId().getY())); + this.createPlaceholder("currentplot_xy", (player, plot) -> plot.getId().toString()); + this.createPlaceholder("currentplot_rating", (player, plot) -> Double.toString(plot.getAverageRating())); + this.createPlaceholder("currentplot_biome", (player, plot) -> plot.getBiomeSynchronous().toString()); + } + + /** + * Create a functional placeholder + * + * @param key Placeholder key + * @param placeholderFunction Placeholder generator. Cannot return null + */ + @SuppressWarnings("ALL") public void createPlaceholder(@NotNull final String key, + @NotNull final Function, String> placeholderFunction) { + this.registerPlaceholder(new Placeholder(key) { + @Override @NotNull public String getValue(@NotNull final PlotPlayer player) { + return placeholderFunction.apply(player); + } + }); + } + + /** + * Create a functional placeholder + * + * @param key Placeholder key + * @param placeholderFunction Placeholder generator. Cannot return null + */ + public void createPlaceholder(@NotNull final String key, + @NotNull final BiFunction, Plot, String> placeholderFunction) { + this.registerPlaceholder(new PlotSpecificPlaceholder(key) { + @Override @NotNull public String getValue(@NotNull final PlotPlayer player, @NotNull final Plot plot) { + return placeholderFunction.apply(player, plot); + } + }); + } + + /** + * Register a placeholder + * + * @param placeholder Placeholder instance + */ + public void registerPlaceholder(@NotNull final Placeholder placeholder) { + final Placeholder previous = this.placeholders + .put(placeholder.getKey().toLowerCase(Locale.ENGLISH), + Preconditions.checkNotNull(placeholder, "Placeholder may not be null")); + if (previous == null) { + this.eventDispatcher.callGenericEvent(new PlaceholderAddedEvent(placeholder)); + } + } + + /** + * Get a placeholder instance from its key + * + * @param key Placeholder key + * @return Placeholder value + */ + @Nullable public Placeholder getPlaceholder(@NotNull final String key) { + return this.placeholders.get( + Preconditions.checkNotNull(key, "Key may not be null").toLowerCase(Locale.ENGLISH)); + } + + /** + * Get the placeholder value evaluated for a player, and catch and deal with any problems + * occurring while doing so + * + * @param key Placeholder key + * @param player Player to evaluate for + * @return Replacement value + */ + @NotNull public String getPlaceholderValue(@NotNull final String key, + @NotNull final PlotPlayer player) { + final Placeholder placeholder = getPlaceholder(key); + if (placeholder == null) { + return ""; + } + String placeholderValue = ""; + try { + placeholderValue = placeholder.getValue(player); + // If a placeholder for some reason decides to be disobedient, we catch it here + if (placeholderValue == null) { + new RuntimeException(String + .format("Placeholder '%s' returned null for player '%s'", placeholder.getKey(), + player.getName())).printStackTrace(); + } + } catch (final Exception exception) { + new RuntimeException(String + .format("Placeholder '%s' failed to evalulate for player '%s'", + placeholder.getKey(), player.getName()), exception).printStackTrace(); + } + return placeholderValue; + } + + /** + * Get all placeholders + * + * @return Unmodifiable collection of placeholders + */ + @NotNull public Collection getPlaceholders() { + return Collections.unmodifiableCollection(this.placeholders.values()); + } + + + /** + * Event called when a new {@link Placeholder} has been added + */ + public static class PlaceholderAddedEvent { + + private final Placeholder placeholder; + + public PlaceholderAddedEvent(Placeholder placeholder) { + this.placeholder = placeholder; + } + + public Placeholder getPlaceholder() { + return this.placeholder; + } + + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/placeholders/PlotFlagPlaceholder.java b/Core/src/main/java/com/plotsquared/core/util/placeholders/PlotFlagPlaceholder.java new file mode 100644 index 000000000..4a3d1876a --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/placeholders/PlotFlagPlaceholder.java @@ -0,0 +1,76 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.util.placeholders; + +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.flag.GlobalFlagContainer; +import com.plotsquared.core.plot.flag.PlotFlag; +import org.jetbrains.annotations.NotNull; + +public final class PlotFlagPlaceholder extends PlotSpecificPlaceholder { + + private final PlotFlag flag; + private final boolean local; + + public PlotFlagPlaceholder(@NotNull final PlotFlag flag, final boolean local) { + super(String.format("currentplot_%sflag_%s", local ? "local": "", flag.getName())); + this.flag = flag; + this.local = local; + } + + @Override @NotNull public String getValue(@NotNull final PlotPlayer player, @NotNull final Plot plot) { + return this.getFlagValue(plot, this.flag.getName(), !this.local); + } + + /** + * Return the flag value from its name on the current plot. + * If the flag doesn't exist it returns an empty string. + * If the flag exists but it is not set on current plot and the parameter inherit is set to true, + * it returns the default value. + * + * @param plot Current plot where the player is + * @param flagName Name of flag to get from current plot + * @param inherit Define if it returns only the flag set on the current plot or also inherited flags + * @return The value of flag serialized in string + */ + @NotNull private String getFlagValue(@NotNull final Plot plot, @NotNull final String flagName, final boolean inherit) { + if (flagName.isEmpty()) { + return ""; + } + final PlotFlag flag = GlobalFlagContainer.getInstance().getFlagFromString(flagName); + if (flag == null) { + return ""; + } + if (inherit) { + return plot.getFlag(flag).toString(); + } else { + final PlotFlag plotFlag = plot.getFlagContainer().queryLocal(flag.getClass()); + return (plotFlag != null) ? plotFlag.getValue().toString() : ""; + } + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/placeholders/PlotSpecificPlaceholder.java b/Core/src/main/java/com/plotsquared/core/util/placeholders/PlotSpecificPlaceholder.java new file mode 100644 index 000000000..92285238d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/placeholders/PlotSpecificPlaceholder.java @@ -0,0 +1,59 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * 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 . + */ +package com.plotsquared.core.util.placeholders; + +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import org.jetbrains.annotations.NotNull; + +/** + * A {@link Placeholder placeholder} that requires a {@link com.plotsquared.core.plot.Plot plot} + */ +public abstract class PlotSpecificPlaceholder extends Placeholder { + + public PlotSpecificPlaceholder(@NotNull final String key) { + super(key); + } + + @Override @NotNull public final String getValue(@NotNull final PlotPlayer player) { + final Plot plot = player.getCurrentPlot(); + if (plot == null) { + return ""; + } + return this.getValue(player, plot); + } + + /** + * Get the value of the placeholder for the {@link PlotPlayer player} in a specific {@link Plot plot} + * + * @param player Player that the placeholder is evaluated for + * @param plot Plot that the player is in + * @return Placeholder value, or {@code ""} if the placeholder does not apply + */ + @NotNull public abstract String getValue(@NotNull final PlotPlayer player, + @NotNull final Plot plot); + +} diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index e5a2e3ba8..426a6dc0b 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -171,8 +171,10 @@ public class UUIDPipeline { } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } catch (TimeoutException ignored) { - logger.warn("[P2] (UUID) Request for {} timed out", username); // This is completely valid, we just don't care anymore + if (Settings.DEBUG) { + logger.warn("[P2] (UUID) Request for {} timed out", username); + } } return null; } @@ -194,8 +196,10 @@ public class UUIDPipeline { } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } catch (TimeoutException ignored) { - logger.warn("[P2] (UUID) Request for {} timed out", uuid); // This is completely valid, we just don't care anymore + if (Settings.DEBUG) { + logger.warn("[P2] (UUID) Request for {} timed out", uuid); + } } return null; } @@ -206,20 +210,19 @@ public class UUIDPipeline { * @param username Username * @param uuid UUID consumer */ - public void getSingle(@Nonnull final String username, - @Nonnull final BiConsumer uuid) { + public void getSingle(@Nonnull final String username, @Nonnull final BiConsumer uuid) { this.getUUIDs(Collections.singletonList(username)).applyToEither(timeoutAfter(Settings.UUID.NON_BLOCKING_TIMEOUT), Function.identity()) .whenComplete((uuids, throwable) -> { - if (throwable != null) { - uuid.accept(null, throwable); - } else { - if (!uuids.isEmpty()) { - uuid.accept(uuids.get(0).getUuid(), null); + if (throwable != null) { + uuid.accept(null, throwable); } else { - uuid.accept(null, null); + if (!uuids.isEmpty()) { + uuid.accept(uuids.get(0).getUuid(), null); + } else { + uuid.accept(null, null); + } } - } - }); + }); } /** @@ -228,20 +231,19 @@ public class UUIDPipeline { * @param uuid UUID * @param username Username consumer */ - public void getSingle(@Nonnull final UUID uuid, - @Nonnull final BiConsumer username) { + public void getSingle(@Nonnull final UUID uuid, @Nonnull final BiConsumer username) { this.getNames(Collections.singletonList(uuid)).applyToEither(timeoutAfter(Settings.UUID.NON_BLOCKING_TIMEOUT), Function.identity()) .whenComplete((uuids, throwable) -> { - if (throwable != null) { - username.accept(null, throwable); - } else { - if (!uuids.isEmpty()) { - username.accept(uuids.get(0).getUsername(), null); + if (throwable != null) { + username.accept(null, throwable); } else { - username.accept(null, null); + if (!uuids.isEmpty()) { + username.accept(uuids.get(0).getUsername(), null); + } else { + username.accept(null, null); + } } - } - }); + }); } /** @@ -254,8 +256,7 @@ public class UUIDPipeline { * @param timeout Timeout in milliseconds * @return Mappings */ - public CompletableFuture> getNames(@Nonnull final Collection requests, - final long timeout) { + public CompletableFuture> getNames(@Nonnull final Collection requests, final long timeout) { return this.getNames(requests).applyToEither(timeoutAfter(timeout), Function.identity()); } @@ -269,8 +270,7 @@ public class UUIDPipeline { * @param timeout Timeout in milliseconds * @return Mappings */ - public CompletableFuture> getUUIDs(@Nonnull final Collection requests, - final long timeout) { + public CompletableFuture> getUUIDs(@Nonnull final Collection requests, final long timeout) { return this.getUUIDs(requests).applyToEither(timeoutAfter(timeout), Function.identity()); } @@ -349,8 +349,7 @@ public class UUIDPipeline { * @param requests Names * @return Mappings */ - public CompletableFuture> getUUIDs( - @Nonnull final Collection requests) { + public CompletableFuture> getUUIDs(@Nonnull final Collection requests) { if (requests.isEmpty()) { return CompletableFuture.completedFuture(Collections.emptyList()); } diff --git a/Core/src/main/resources/lang/messages_en.json b/Core/src/main/resources/lang/messages_en.json index e933c2067..b944d20e0 100644 --- a/Core/src/main/resources/lang/messages_en.json +++ b/Core/src/main/resources/lang/messages_en.json @@ -181,6 +181,8 @@ "core.prefix": "[P2] ", "core.enabled": " is now enabled.", + + "placeholder.hooked": "PlotSquared hooked into MVdWPlaceholderAPI", "reload.reloaded_configs": "Translations and world settings have been reloaded successfully.", "reload.reload_failed": "Failed to reload file configurations.", diff --git a/build.gradle b/build.gradle index 32b17ef31..1806aa090 100644 --- a/build.gradle +++ b/build.gradle @@ -79,7 +79,7 @@ subprojects { subproject -> dependencies { compile group: 'org.json', name: 'json', version: '20200518' - implementation("com.sk89q.worldedit:worldedit-core:7.0.0") { + implementation("com.sk89q.worldedit:worldedit-core:7.2.0-SNAPSHOT") { exclude(module: "bukkit-classloader-check") exclude(module: "mockito-core") exclude(module: "dummypermscompat") @@ -100,6 +100,7 @@ subprojects { subproject -> } repositories { + mavenLocal() mavenCentral() maven { url = "https://maven.enginehub.org/repo/" } maven { url = "https://repo.maven.apache.org/maven2" } @@ -110,6 +111,8 @@ subprojects { subproject -> dependencies { include(dependency("org.json:json:20200518")) include(dependency("net.kyori:text-api:3.0.2")) + include(dependency("javax.inject:javax.inject:1")) + include(dependency("aopalliance:aopalliance:1.0")) } relocate("io.papermc.lib", "com.plotsquared.bukkit.paperlib") relocate("org.json", "com.plotsquared.json") {