diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index cd7dc4c7f..af6faf26f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -513,8 +513,10 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl this.backgroundPipeline.registerService(essentialsUUIDService); } - final SquirrelIdUUIDService impromptuMojangService = new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT); - this.impromptuPipeline.registerService(impromptuMojangService); + if (Settings.UUID.IMPROMPTU_SERVICE_MOJANG_API) { + final SquirrelIdUUIDService impromptuMojangService = new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT); + this.impromptuPipeline.registerService(impromptuMojangService); + } final SquirrelIdUUIDService backgroundMojangService = new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT); this.backgroundPipeline.registerService(backgroundMojangService); } else { 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 93d60997b..0ce6554d8 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/generator/DelegatePlotGenerator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/generator/DelegatePlotGenerator.java @@ -80,7 +80,8 @@ final class DelegatePlotGenerator extends IndependentPlotGenerator { result.setBiome(x, z, BukkitAdapter.adapt(biome)); } - //do not annotate with Override until we discontinue support for 1.4.4 + //do not annotate with Override until we discontinue support for 1.4.4 (we no longer support 1.4.4) + @Override public void setBiome(int x, int y, int z, @NonNull Biome biome) { result.setBiome(x, z, BukkitAdapter.adapt(biome)); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java index f7e6f16a3..d639f74ad 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitQueueCoordinator.java @@ -51,6 +51,7 @@ 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; @@ -266,7 +267,13 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { } catch (WorldEditException ignored) { // Fallback to not so nice method BlockData blockData = BukkitAdapter.adapt(block); - Block existing = getBukkitWorld().getBlockAt(x, y, z); + Block existing; + // Assume a chunk object has been given only when it should have been. + if (getChunkObject() instanceof Chunk chunkObject) { + existing = chunkObject.getBlock(x & 15, y, z & 15); + } else { + existing = getBukkitWorld().getBlockAt(x, y, z); + } final BlockState existingBaseBlock = BukkitAdapter.adapt(existing.getBlockData()); if (BukkitBlockUtil.get(existing).equals(existingBaseBlock) && existing.getBlockData().matches(blockData)) { return; @@ -282,7 +289,7 @@ public class BukkitQueueCoordinator extends BasicQueueCoordinator { CompoundTag tag = block.getNbtData(); StateWrapper sw = new StateWrapper(tag); - sw.restoreTag(getWorld().getName(), existing.getX(), existing.getY(), existing.getZ()); + sw.restoreTag(existing); } } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/schematic/StateWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/schematic/StateWrapper.java index 84f8efb4a..c320ded27 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/schematic/StateWrapper.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/schematic/StateWrapper.java @@ -44,6 +44,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.checkerframework.checker.nullness.qual.NonNull; import java.util.ArrayList; import java.util.HashMap; @@ -166,14 +167,32 @@ public class StateWrapper { return str; } - @SuppressWarnings("deprecation") // #setLine is needed for Spigot compatibility + /** + * Restore the TileEntity data to the given world at the given coordinates. + * + * @param worldName World name + * @param x x position + * @param y y position + * @param z z position + * @return true if successful + */ public boolean restoreTag(String worldName, int x, int y, int z) { - if (this.tag == null) { + World world = BukkitUtil.getWorld(worldName); + if (world == null) { return false; } - World world = BukkitUtil.getWorld(worldName); - Block block = world.getBlockAt(x, y, z); - if (block == null) { + return restoreTag(world.getBlockAt(x, y, z)); + } + + /** + * Restore the TileEntity data to the given block + * + * @param block Block to restore to + * @return true if successful + */ + @SuppressWarnings("deprecation") // #setLine is needed for Spigot compatibility + public boolean restoreTag(@NonNull Block block) { + if (this.tag == null) { return false; } org.bukkit.block.BlockState state = block.getState(); 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 74b5c1372..76725c4df 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java @@ -278,7 +278,7 @@ public class BukkitRegionManager extends RegionManager { int minY = value.getMin().getY(); for (int yIndex = 0; yIndex < ids.length; yIndex++) { int y = yIndex + minY; - BaseBlock id = ids[y]; + BaseBlock id = ids[yIndex]; if (id != null) { value.setBlock(x1, y, z1, id); } else { diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 872d1bd68..9c9bb09f3 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -889,8 +889,8 @@ public class PlotSquared { e.printStackTrace(); } LOGGER.info("| generator: {}>{}", baseGenerator, areaGen); - LOGGER.info("| plot world: {}", pa); - LOGGER.info("| manager: {}", pa); + LOGGER.info("| plot world: {}", pa.getClass().getCanonicalName()); + LOGGER.info("| manager: {}", pa.getPlotManager().getClass().getCanonicalName()); LOGGER.info("Note: Area created for cluster '{}' (invalid or old configuration?)", name); areaGen.getPlotGenerator().initialize(pa); areaGen.augment(pa); @@ -906,6 +906,13 @@ public class PlotSquared { throw new IllegalArgumentException("Invalid Generator: " + gen_string); } PlotArea pa = areaGen.getPlotGenerator().getNewPlotArea(world, null, null, null); + LOGGER.info("- generator: {}>{}", baseGenerator, areaGen); + LOGGER.info("- plot world: {}", pa.getClass().getCanonicalName()); + LOGGER.info("- plot area manager: {}", pa.getPlotManager().getClass().getCanonicalName()); + if (!this.worldConfiguration.contains(path)) { + this.worldConfiguration.createSection(path); + worldSection = this.worldConfiguration.getConfigurationSection(path); + } pa.saveConfiguration(worldSection); pa.loadDefaultConfiguration(worldSection); try { @@ -913,9 +920,6 @@ public class PlotSquared { } catch (IOException e) { e.printStackTrace(); } - LOGGER.info("- generator: {}>{}", baseGenerator, areaGen); - LOGGER.info("- plot world: {}", pa); - LOGGER.info("- plot area manager: {}", pa.getPlotManager()); areaGen.getPlotGenerator().initialize(pa); areaGen.augment(pa); addPlotArea(pa); diff --git a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java index e6a2ae91d..8fe2fd46c 100644 --- a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java @@ -32,6 +32,7 @@ import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.CaptionHolder; import com.plotsquared.core.configuration.caption.Templates; import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.permissions.Permission; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -39,6 +40,7 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.expiration.ExpireManager; import com.plotsquared.core.plot.flag.implementations.DoneFlag; import com.plotsquared.core.plot.flag.implementations.PriceFlag; +import com.plotsquared.core.plot.flag.implementations.ServerPlotFlag; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.MathMan; @@ -418,7 +420,7 @@ public class ListCmd extends SubCommand { Caption color; if (plot.getOwner() == null) { color = TranslatableCaption.of("info.plot_list_no_owner"); - } else if (plot.isOwner(player.getUUID())) { + } else if (plot.isOwner(player.getUUID()) || plot.getOwner().equals(DBFunc.EVERYONE)) { color = TranslatableCaption.of("info.plot_list_owned_by"); } else if (plot.isAdded(player.getUUID())) { color = TranslatableCaption.of("info.plot_list_added_to"); @@ -456,37 +458,60 @@ public class ListCmd extends SubCommand { String prefix = ""; String online = TranslatableCaption.of("info.plot_list_player_online").getComponent(player); String offline = TranslatableCaption.of("info.plot_list_player_offline").getComponent(player); + String unknown = TranslatableCaption.of("info.plot_list_player_unknown").getComponent(player); + String server = TranslatableCaption.of("info.plot_list_player_server").getComponent(player); + String everyone = TranslatableCaption.of("info.plot_list_player_everyone").getComponent(player); TextComponent.Builder builder = Component.text(); - try { - final List names = PlotSquared.get().getImpromptuUUIDPipeline().getNames(plot.getOwners()) - .get(Settings.UUID.BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS); - for (final UUIDMapping uuidMapping : names) { - PlotPlayer pp = PlotSquared.platform().playerManager().getPlayerIfExists(uuidMapping.getUuid()); - Template prefixTemplate = Template.of("prefix", prefix); - Template playerTemplate = Template.of("player", uuidMapping.getUsername()); - if (pp != null) { - builder.append(MINI_MESSAGE.parse(online, prefixTemplate, playerTemplate)); - } else { - builder.append(MINI_MESSAGE.parse(offline, prefixTemplate, playerTemplate)); - } - prefix = ", "; - } - } catch (InterruptedException | ExecutionException e) { - final StringBuilder playerBuilder = new StringBuilder(); - final Iterator uuidIterator = plot.getOwners().iterator(); - while (uuidIterator.hasNext()) { - final UUID uuid = uuidIterator.next(); - playerBuilder.append(uuid); - if (uuidIterator.hasNext()) { - playerBuilder.append(", "); - } - } - player.sendMessage( - TranslatableCaption.of("errors.invalid_player"), - Templates.of("value", playerBuilder.toString()) + if (plot.getFlag(ServerPlotFlag.class)) { + Template serverTemplate = Template.of( + "info.server", + TranslatableCaption.of("info.server").getComponent(player) ); - } catch (TimeoutException e) { - player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout")); + builder.append(MINI_MESSAGE.parse(server, serverTemplate)); + } else { + try { + final List names = PlotSquared.get().getImpromptuUUIDPipeline().getNames(plot.getOwners()) + .get(Settings.UUID.BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS); + for (final UUIDMapping uuidMapping : names) { + PlotPlayer pp = PlotSquared.platform().playerManager().getPlayerIfExists(uuidMapping.getUuid()); + Template prefixTemplate = Template.of("prefix", prefix); + Template playerTemplate = Template.of("player", uuidMapping.getUsername()); + if (pp != null) { + builder.append(MINI_MESSAGE.parse(online, prefixTemplate, playerTemplate)); + } else if (uuidMapping.getUsername().equalsIgnoreCase("unknown")) { + Template unknownTemplate = Template.of( + "info.unknown", + TranslatableCaption.of("info.unknown").getComponent(player) + ); + builder.append(MINI_MESSAGE.parse(unknown, unknownTemplate)); + } else if (uuidMapping.getUuid().equals(DBFunc.EVERYONE)) { + Template everyoneTemplate = Template.of( + "info.everyone", + TranslatableCaption.of("info.everyone").getComponent(player) + ); + builder.append(MINI_MESSAGE.parse(everyone, everyoneTemplate)); + } else { + builder.append(MINI_MESSAGE.parse(offline, prefixTemplate, playerTemplate)); + } + prefix = ", "; + } + } catch (InterruptedException | ExecutionException e) { + final StringBuilder playerBuilder = new StringBuilder(); + final Iterator uuidIterator = plot.getOwners().iterator(); + while (uuidIterator.hasNext()) { + final UUID uuid = uuidIterator.next(); + playerBuilder.append(uuid); + if (uuidIterator.hasNext()) { + playerBuilder.append(", "); + } + } + player.sendMessage( + TranslatableCaption.of("errors.invalid_player"), + Templates.of("value", playerBuilder.toString()) + ); + } catch (TimeoutException e) { + player.sendMessage(TranslatableCaption.of("players.fetching_players_timeout")); + } } Template players = Template.of("players", builder.asComponent()); caption.set(TranslatableCaption.of("info.plot_list_item")); diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java index 817550e64..4f64fbbac 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java @@ -249,6 +249,9 @@ public class Settings extends Config { public static int UUID_CACHE_SIZE = 100000; @Comment("Rate limit (per 10 minutes) for background UUID fetching from the Mojang API") public static int BACKGROUND_LIMIT = 200; + @Comment("Whether the Mojang API service is enabled for impromptu api calls. If false only the Background task will use" + + " http requests to fill the UUID cache (requires restart)") + public static boolean IMPROMPTU_SERVICE_MOJANG_API = true; @Comment("Rate limit (per 10 minutes) for random UUID fetching from the Mojang API") public static int IMPROMPTU_LIMIT = 300; @Comment("Timeout (in milliseconds) for non-blocking UUID requests (mostly commands)") @@ -691,6 +694,7 @@ public class Settings extends Config { @Comment({"If blocks at the edges of queued operations should be set causing updates", " - Slightly slower, but prevents issues such as fences left connected to nothing"}) public static boolean UPDATE_EDGES = true; + } @Comment("Settings related to tab completion") 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 0eab11c71..a1b688151 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java @@ -41,7 +41,7 @@ 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.ChunkQueueCoordinator; +import com.plotsquared.core.queue.BlockArrayCacheScopedQueueCoordinator; import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.QueueCoordinator; import com.plotsquared.core.util.ChunkManager; @@ -83,6 +83,7 @@ import java.util.concurrent.atomic.AtomicInteger; public class HybridUtils { private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + HybridUtils.class.getSimpleName()); + private static final BlockState AIR = BlockTypes.AIR.getDefaultState(); public static HybridUtils manager; public static Set regions; @@ -136,6 +137,11 @@ public class HybridUtils { * */ TaskManager.runTaskAsync(() -> { + final PlotArea area = this.plotAreaManager.getPlotArea(world, null); + if (!(area instanceof HybridPlotWorld hpw)) { + return; + } + final BlockVector3 bot = region.getMinimumPoint(); final BlockVector3 top = region.getMaximumPoint(); @@ -152,37 +158,28 @@ public class HybridUtils { final int height = area.getMaxGenHeight() - area.getMinGenHeight() + 1; final int minHeight = area.getMinGenHeight(); - final PlotArea area = this.plotAreaManager.getPlotArea(world, null); - - if (!(area instanceof HybridPlotWorld hpw)) { - return; - } - - ChunkQueueCoordinator chunk = new ChunkQueueCoordinator(worldUtil.getWeWorld(world), bot, top, false); - hpw.getGenerator().generateChunk(chunk, hpw); - - final BlockState airBlock = BlockTypes.AIR.getDefaultState(); - final BlockState[][][] oldBlocks = chunk.getBlocks(); final BlockState[][][] newBlocks = new BlockState[height][width][length]; - for (final BlockState[][] newBlock : newBlocks) { - for (final BlockState[] blockStates : newBlock) { - Arrays.fill(blockStates, airBlock); - } - } - for (final BlockState[][] oldBlock : oldBlocks) { - for (final BlockState[] blockStates : oldBlock) { - Arrays.fill(blockStates, airBlock); - } - } - System.gc(); - System.gc(); + BlockArrayCacheScopedQueueCoordinator oldBlockQueue = new BlockArrayCacheScopedQueueCoordinator( + Location.at("", region.getMinimumPoint().withY(hpw.getMinGenHeight())), + Location.at("", region.getMaximumPoint().withY(hpw.getMaxGenHeight())) + ); + + region.getChunks().forEach(chunkPos -> { + int relChunkX = chunkPos.getX() - cbx; + int relChunkZ = chunkPos.getZ() - cbz; + oldBlockQueue.setOffsetX(relChunkX << 4); + oldBlockQueue.setOffsetZ(relChunkZ << 4); + hpw.getGenerator().generateChunk(oldBlockQueue, hpw); + }); + + final BlockState[][][] oldBlocks = oldBlockQueue.getBlockStates(); QueueCoordinator queue = area.getQueue(); queue.addReadChunks(region.getChunks()); - queue.setChunkConsumer(blockVector2 -> { - int X = blockVector2.getX(); - int Z = blockVector2.getZ(); + queue.setChunkConsumer(chunkPos -> { + int X = chunkPos.getX(); + int Z = chunkPos.getZ(); int minX; if (X == cbx) { minX = bx & 15; @@ -220,6 +217,9 @@ public class HybridUtils { for (int yIndex = 0; yIndex < height; yIndex++) { int y = yIndex + minHeight; BlockState block = queue.getBlock(xx, y, zz); + if (block == null) { + block = AIR; + } int xr = xb + x; int zr = zb + z; newBlocks[yIndex][xr][zr] = block; @@ -240,10 +240,10 @@ public class HybridUtils { for (int z = 0; z < length; z++) { Set types = new HashSet<>(); for (int yIndex = 0; yIndex < height; yIndex++) { - BlockState old = oldBlocks[yIndex][x][z]; + BlockState old = oldBlocks[yIndex][x][z]; // Nullable try { - BlockState now = newBlocks[yIndex][x][z]; - if (!old.equals(now)) { + BlockState now = newBlocks[yIndex][x][z]; // Not null + if (!now.equals(old) && !(old == null && now.getBlockType().equals(BlockTypes.AIR))) { changes[i]++; } if (now.getBlockType().getMaterial().isAir()) { @@ -301,8 +301,6 @@ public class HybridUtils { analysis.data_sd = (int) (MathMan.getSD(data, analysis.data) * 100); analysis.air_sd = (int) (MathMan.getSD(air, analysis.air) * 100); analysis.variety_sd = (int) (MathMan.getSD(variety, analysis.variety) * 100); - System.gc(); - System.gc(); whenDone.value = analysis; whenDone.run(); }); 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 b709de857..ff707953a 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -1420,15 +1420,7 @@ public class Plot { 0 ); } - Location location = Location - .at( - bottom.getWorldName(), - bottom.getX() + home.getX(), - bottom.getY() + home.getY(), - bottom.getZ() + home.getZ(), - home.getYaw(), - home.getPitch() - ); + Location location = toHomeLocation(bottom, home); if (!this.worldUtil.getBlockSynchronous(location).getBlockType().getMaterial().isAir()) { location = location.withY( Math.max(1 + this.worldUtil.getHighestBlockSynchronous( @@ -1461,15 +1453,7 @@ public class Plot { return; } Location bottom = this.getBottomAbs(); - Location location = Location - .at( - bottom.getWorldName(), - bottom.getX() + home.getX(), - home.getY(), // y is absolute - bottom.getZ() + home.getZ(), - home.getYaw(), - home.getPitch() - ); + Location location = toHomeLocation(bottom, home); this.worldUtil.getBlock(location, block -> { if (!block.getBlockType().getMaterial().isAir()) { this.worldUtil.getHighestBlock(this.getWorldName(), location.getX(), location.getZ(), @@ -1482,6 +1466,17 @@ public class Plot { } } + private Location toHomeLocation(Location bottom, BlockLoc relativeHome) { + return Location.at( + bottom.getWorldName(), + bottom.getX() + relativeHome.getX(), + relativeHome.getY(), // y is absolute + bottom.getZ() + relativeHome.getZ(), + relativeHome.getYaw(), + relativeHome.getPitch() + ); + } + /** * Sets the home location * diff --git a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpiryTask.java b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpiryTask.java index 03a9c010b..c0e2b8a1a 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpiryTask.java +++ b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpiryTask.java @@ -75,9 +75,9 @@ public class ExpiryTask { plots = plots != null ? plots : getPlotsToCheck(); int diff = settings.REQUIRED_PLOTS; boolean min = true; - if (settings.REQUIRED_PLOTS - plots.size() < settings.REQUIRED_PLOTS) { + if (plots.size() > settings.REQUIRED_PLOTS) { min = false; - diff = settings.REQUIRED_PLOTS - plots.size(); + diff = plots.size() - settings.REQUIRED_PLOTS; } List entireList = plots.stream().map(plot -> ExpireManager.IMP.getAge(plot, settings.DELETE_IF_OWNER_IS_UNKNOWN)) diff --git a/Core/src/main/java/com/plotsquared/core/queue/BlockArrayCacheScopedQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/BlockArrayCacheScopedQueueCoordinator.java new file mode 100644 index 000000000..043e6e0ff --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/queue/BlockArrayCacheScopedQueueCoordinator.java @@ -0,0 +1,175 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2014 - 2022 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.location.Location; +import com.plotsquared.core.util.AnnotationHelper; +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.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * {@link QueueCoordinator} that caches all blocks set to it in a given array of form BlockState[][][]. An offset can be + * applied to blocks set to it, and the scope limited. This should have blocks set to it one chunk at a time, based on the + * result of {@link BlockArrayCacheScopedQueueCoordinator#getMin()} and {@link BlockArrayCacheScopedQueueCoordinator#getMax()}. + * The min and max points of this queue are offset according to the minimum point given in the constructor, and the offsets set + * in {@link BlockArrayCacheScopedQueueCoordinator#setOffsetX(int)} and + * {@link BlockArrayCacheScopedQueueCoordinator#setOffsetZ(int)} + */ +@AnnotationHelper.ApiDescription(info = "Internal use only. Subject to change at any time and created for specific use cases.") +public class BlockArrayCacheScopedQueueCoordinator extends ScopedQueueCoordinator { + + private final BlockState[][][] blockStates; + private final int height; + private final int width; + private final int length; + private final int minY; + private final int maxY; + private final int scopeMinX; + private final int scopeMinZ; + private final int scopeMaxX; + private final int scopeMaxZ; + private int offsetX = 0; + private int offsetZ = 0; + /** + * Construct a new instance + * + * @param min Inclusive location of the minimum point to limit the scope to. + * @param max Inclusive location of the maximum point to limit the scope to. + * @since TODO + */ + public BlockArrayCacheScopedQueueCoordinator(Location min, Location max) { + super(null, min, max); + this.width = max.getX() - min.getX() + 1; + this.length = max.getZ() - min.getZ() + 1; + this.minY = min.getY(); + this.maxY = max.getY(); + this.height = maxY - minY + 1; + + this.scopeMinX = min.getX() & 15; + this.scopeMinZ = min.getZ() & 15; + this.scopeMaxX = scopeMinX + width; + this.scopeMaxZ = scopeMinZ + length; + this.blockStates = new BlockState[height][width][length]; + } + + public BlockState[][][] getBlockStates() { + return blockStates; + } + + @Override + public boolean setBlock(int x, final int y, int z, final @NonNull BlockState id) { + x += offsetX; + z += offsetZ; + if (x >= scopeMinX && x < scopeMaxX && y >= minY && y <= maxY && z >= scopeMinZ && z < scopeMaxZ) { + blockStates[y - minY][x - scopeMinX][z - scopeMinZ] = id; + } + return false; + } + + @Override + public boolean setBlock(final int x, final int y, final int z, @NonNull final Pattern pattern) { + int rx = x + offsetX; + int rz = z + offsetZ; + if (rx >= scopeMinX && rx < scopeMaxX && y >= minY && y <= maxY && rz >= scopeMinZ && rz < scopeMaxZ) { + BlockState state = pattern + .applyBlock(super.getMin().getBlockVector3().add(BlockVector3.at(x, y, z))) + .toImmutableState(); + blockStates[y - minY][rx - scopeMinX][rz - scopeMinZ] = state; + } + return false; + } + + @Override + public @NonNull Location getMin() { + return super.getMin().add(offsetX - scopeMinX, 0, offsetZ - scopeMinZ); + } + + @Override + public @NonNull Location getMax() { + return getMin().add(15, 0, 15).withY(maxY); + } + + @Override + public boolean setBlock(int x, int y, int z, final @NonNull BaseBlock id) { + x += offsetX; + z += offsetZ; + if (x >= scopeMinX && x < scopeMaxX && y >= minY && y <= maxY && z >= scopeMinZ && z < scopeMaxZ) { + blockStates[y - minY][x][z] = id.toImmutableState(); + } + return false; + } + + @Override + public @Nullable BlockState getBlock(final int x, final int y, final int z) { + if (x >= 0 && x < width && y >= minY && y <= maxY && z >= 0 && z < length) { + return blockStates[y - minY][x][z]; + } + return null; + } + + public void setOffsetX(final int offsetX) { + this.offsetX = offsetX; + } + + public void setOffsetZ(final int offsetZ) { + this.offsetZ = offsetZ; + } + + @Override + public int size() { + return height * width * length; + } + + @Override + public boolean setBiome(final int x, final int z, @NonNull final BiomeType biome) { + //do nothing + return false; + } + + @Override + public boolean setBiome(final int x, final int y, final int z, @NonNull final BiomeType biome) { + //do nothing + return false; + } + + @Override + public void fillBiome(final BiomeType biome) { + //do nothing + } + + @Override + public boolean setTile(final int x, final int y, final int z, @NonNull final CompoundTag tag) { + //do nothing + return false; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java index ad68de264..65b35e8da 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ChunkQueueCoordinator.java @@ -36,8 +36,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** - * Queue that is limited to a single chunk + * Queue that is limited to a single chunk. It does not allow a delegate queue and should be treated as a cache for changes to + * be set to. Does not support tile entities or entities. + * + * @deprecated This class is poorly designed and will no longer be used in P2 */ +@Deprecated(forRemoval = true, since = "TODO") public class ChunkQueueCoordinator extends ScopedQueueCoordinator { public final BiomeType[][][] biomeResult; diff --git a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java index 7853f89eb..609434174 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/QueueCoordinator.java @@ -143,7 +143,8 @@ public abstract class QueueCoordinator { } /** - * Set a chunk object (e.g. the Bukkit Chunk object) to the queue + * Set a chunk object (e.g. the Bukkit Chunk object) to the queue. This will be used as fallback in case of WNA failure. + * Should ONLY be used in specific cases (i.e. generation, where a chunk is being populated) * * @param chunkObject chunk object. Usually the implementation-specific chunk (e.g. bukkit Chunk) */ diff --git a/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java b/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java index cba1f8a2a..0eda75df2 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java +++ b/Core/src/main/java/com/plotsquared/core/queue/ScopedQueueCoordinator.java @@ -35,8 +35,12 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; /** - * Queue that only sets blocks with a designated area + * Queue that only sets blocks with a designated X-Z area, will accept any Y values. Requires all blocks be set normalized in + * the x and z directions, i.e. starting from 0,0. An offset of the minimum point of the region will then be applied to x and z. + * + * @deprecated This should be renamed to NormalizedScopedQueueCoordinator or something. */ +@Deprecated(forRemoval = true, since = "TODO") public class ScopedQueueCoordinator extends DelegateQueueCoordinator { private final Location min; diff --git a/Core/src/main/resources/lang/messages_en.json b/Core/src/main/resources/lang/messages_en.json index bc189c8c9..85c829d8c 100644 --- a/Core/src/main/resources/lang/messages_en.json +++ b/Core/src/main/resources/lang/messages_en.json @@ -381,6 +381,9 @@ "info.plot_list_default": "", "info.plot_list_player_online": "Online\">", "info.plot_list_player_offline": "Offline\">", + "info.plot_list_player_unknown": "The owner of this plot is unknown\">", + "info.plot_list_player_server": "The plot is owned by the server\">", + "info.plot_list_player_everyone": "The plot is owned by everyone\">", "info.area_info_format": "
\nName: \nType: \nTerrain: \nUsage: %\nClaimed: \nClusters: \nRegion: \nGenerator: \n