From c6ae2456f21d985ca41fbde612cf7553769b1dad Mon Sep 17 00:00:00 2001 From: Sauilitired Date: Tue, 26 Mar 2019 09:27:20 +0100 Subject: [PATCH] Add support for Paper async chunk generation --- .../plotsquared/bukkit/BukkitMain.java | 1 + .../bukkit/generator/BukkitPlotGenerator.java | 167 +++--------------- .../generator/DelegatePlotGenerator.java | 91 ++++++++++ .../bukkit/generator/PlotBlockPopulator.java | 34 ++++ .../bukkit/util/block/GenChunk.java | 5 +- .../plotsquared/plot/generator/HybridGen.java | 3 - .../plotsquared/plot/util/ChunkManager.java | 36 ++-- 7 files changed, 173 insertions(+), 164 deletions(-) create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/DelegatePlotGenerator.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/PlotBlockPopulator.java diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java index 352326a43..22d0b14b5 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java @@ -63,6 +63,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain Settings.load(new File("plugins/PlotSquared/config/settings.yml")); } catch (Throwable ignored) { } + // Force WorldEdit to load try { System.out.println("[P2] Force loading WorldEdit"); diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/BukkitPlotGenerator.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/BukkitPlotGenerator.java index 947f1c3bb..14a7e400e 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/BukkitPlotGenerator.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/BukkitPlotGenerator.java @@ -4,21 +4,19 @@ import com.github.intellectualsites.plotsquared.bukkit.util.BukkitUtil; import com.github.intellectualsites.plotsquared.bukkit.util.block.GenChunk; import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.generator.GeneratorWrapper; -import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotWorld; import com.github.intellectualsites.plotsquared.plot.generator.IndependentPlotGenerator; -import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.object.ChunkLoc; +import com.github.intellectualsites.plotsquared.plot.object.ChunkWrapper; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; import com.github.intellectualsites.plotsquared.plot.object.worlds.SingleWorldGenerator; import com.github.intellectualsites.plotsquared.plot.util.ChunkManager; import com.github.intellectualsites.plotsquared.plot.util.MainUtil; -import com.github.intellectualsites.plotsquared.plot.util.MathMan; -import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue; -import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue; import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue; -import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -28,7 +26,8 @@ import java.util.Set; public class BukkitPlotGenerator extends ChunkGenerator implements GeneratorWrapper { - private final GenChunk chunkSetter; + @SuppressWarnings("unused") public final boolean PAPER_ASYNC_SAFE = true; + private final IndependentPlotGenerator plotGenerator; private final ChunkGenerator platformGenerator; private final boolean full; @@ -41,24 +40,8 @@ public class BukkitPlotGenerator extends ChunkGenerator } this.plotGenerator = generator; this.platformGenerator = this; - populators = new ArrayList<>(); - this.populators.add(new BlockPopulator() { - - private LocalBlockQueue queue; - - @Override public void populate(World world, Random random, Chunk source) { - if (queue == null) { - queue = GlobalBlockQueue.IMP.getNewQueue(world.getName(), false); - } - PlotArea area = PlotSquared.get().getPlotArea(world.getName(), null); - ChunkWrapper wrap = new ChunkWrapper(area.worldname, source.getX(), source.getZ()); - ScopedLocalBlockQueue chunk = queue.getForChunk(wrap.x, wrap.z); - if (BukkitPlotGenerator.this.plotGenerator.populateChunk(chunk, area)) { - queue.flush(); - } - } - }); - this.chunkSetter = new GenChunk(null, null); + this.populators = new ArrayList<>(); + this.populators.add(new PlotBlockPopulator(this.plotGenerator)); this.full = true; MainUtil.initCache(); } @@ -69,108 +52,8 @@ public class BukkitPlotGenerator extends ChunkGenerator + " is already a BukkitPlotGenerator!"); } this.full = false; - //todo figure out why this was put here in the first place: - //PlotSquared.debug("BukkitPlotGenerator does not fully support: " + cg); this.platformGenerator = cg; - this.plotGenerator = new IndependentPlotGenerator() { - @Override public void initialize(PlotArea area) { - } - - @Override public PlotManager getNewPlotManager() { - return PlotSquared.get().IMP.getDefaultGenerator().getNewPlotManager(); - } - - @Override public String getName() { - return cg.getClass().getName(); - } - - @Override - public PlotArea getNewPlotArea(String world, String id, PlotId min, PlotId max) { - return PlotSquared.get().IMP.getDefaultGenerator() - .getNewPlotArea(world, id, min, max); - } - - @Override public BlockBucket[][] generateBlockBucketChunk(PlotArea settings) { - BlockBucket[][] blockBuckets = new BlockBucket[16][]; - HybridPlotWorld hpw = (HybridPlotWorld) settings; - // Bedrock - if (hpw.PLOT_BEDROCK) { - for (short x = 0; x < 16; x++) { - for (short z = 0; z < 16; z++) { - blockBuckets[0][(z << 4) | x] = - BlockBucket.withSingle(PlotBlock.get("bedrock")); - } - } - } - for (short x = 0; x < 16; x++) { - for (short z = 0; z < 16; z++) { - for (int y = 1; y < hpw.PLOT_HEIGHT; y++) { - blockBuckets[y >> 4][((y & 0xF) << 8) | (z << 4) | x] = hpw.MAIN_BLOCK; - } - blockBuckets[hpw.PLOT_HEIGHT >> 4][((hpw.PLOT_HEIGHT & 0xF) << 8) | (z << 4) - | x] = hpw.MAIN_BLOCK; - } - } - return blockBuckets; - } - - @Override - public void generateChunk(final ScopedLocalBlockQueue result, PlotArea settings) { - World w = BukkitUtil.getWorld(world); - Location min = result.getMin(); - int cx = min.getX() >> 4; - int cz = min.getZ() >> 4; - Random r = new Random(MathMan.pair((short) cx, (short) cz)); - BiomeGrid grid = new BiomeGrid() { - @Override public void setBiome(int x, int z, Biome biome) { - result.setBiome(x, z, biome.name()); - } - - @Override public Biome getBiome(int x, int z) { - return Biome.FOREST; - } - }; - try { - // ChunkData will spill a bit - ChunkData data = cg.generateChunkData(w, r, cx, cz, grid); - if (data != null) { - return; - } - } catch (Throwable ignored) { - } - /* TODO: Redo this - // Populator spillage - short[][] tmp = cg.generateExtBlockSections(w, r, cx, cz, biomeGrid); - if (tmp != null) { - for (int i = 0; i < tmp.length; i++) { - short[] section = tmp[i]; - if (section == null) { - if (i < 7) { - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = i << 4; y < (i << 4) + 16; y++) { - result.setBlock(x, y, z, PlotBlock.get("air")); - } - } - } - } - continue; - } - for (int j = 0; j < section.length; j++) { - int x = MainUtil.x_loc[i][j]; - int y = MainUtil.y_loc[i][j]; - int z = MainUtil.z_loc[i][j]; - result.setBlock(x, y, z, section[j], (byte) 0); - } - } - } - */ - for (BlockPopulator populator : cg.getDefaultPopulators(w)) { - populator.populate(w, r, w.getChunkAt(cx, cz)); - } - } - }; - this.chunkSetter = new GenChunk(null, new ChunkWrapper(world, 0, 0)); + this.plotGenerator = new DelegatePlotGenerator(cg, world); MainUtil.initCache(); } @@ -190,7 +73,7 @@ public class BukkitPlotGenerator extends ChunkGenerator return this.platformGenerator; } - @Override public List getDefaultPopulators(World world) { + @Override @NotNull public List getDefaultPopulators(@NotNull World world) { try { if (!this.loaded) { String name = world.getName(); @@ -224,17 +107,20 @@ public class BukkitPlotGenerator extends ChunkGenerator if (populators == null && platformGenerator != null) { populators = new ArrayList<>(platformGenerator.getDefaultPopulators(world)); } - for (BlockPopulator populator : this.populators) { - if (!existing.contains(populator)) { - toAdd.add(populator); + if (populators != null) { + for (BlockPopulator populator : this.populators) { + if (!existing.contains(populator)) { + toAdd.add(populator); + } } } return toAdd; } - @Override - public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome) { - GenChunk result = this.chunkSetter; + @Override @NotNull public ChunkData generateChunkData(@NotNull World world, @NotNull Random random, + int x, int z, @NotNull BiomeGrid biome) { + + GenChunk result = new GenChunk(); if (this.getPlotGenerator() instanceof SingleWorldGenerator) { if (result.getCd() != null) { for (int cx = 0; cx < 16; cx++) { @@ -258,7 +144,7 @@ public class BukkitPlotGenerator extends ChunkGenerator if (this.platformGenerator != this) { return this.platformGenerator.generateChunkData(world, random, x, z, biome); } else { - generate(world, result); + generate(new ChunkLoc(x, z), world, result); } } catch (Throwable e) { e.printStackTrace(); @@ -267,7 +153,7 @@ public class BukkitPlotGenerator extends ChunkGenerator return result.getCd(); } - private void generate(World world, ScopedLocalBlockQueue result) { + private void generate(ChunkLoc loc, World world, ScopedLocalBlockQueue result) { // Load if improperly loaded if (!this.loaded) { String name = world.getName(); @@ -275,17 +161,17 @@ public class BukkitPlotGenerator extends ChunkGenerator this.loaded = true; } // Process the chunk - if (ChunkManager.preProcessChunk(result)) { + if (ChunkManager.preProcessChunk(loc, result)) { return; } PlotArea area = PlotSquared.get().getPlotArea(world.getName(), null); try { - this.plotGenerator.generateChunk(this.chunkSetter, area); + this.plotGenerator.generateChunk(result, area); } catch (Throwable e) { // Recover from generator error e.printStackTrace(); } - ChunkManager.postProcessChunk(result); + ChunkManager.postProcessChunk(loc, result); } /** @@ -296,7 +182,7 @@ public class BukkitPlotGenerator extends ChunkGenerator * @param z Ignored * @return always true */ - @Override public boolean canSpawn(World world, int x, int z) { + @Override public boolean canSpawn(@NotNull final World world, final int x, final int z) { return true; } @@ -311,10 +197,11 @@ public class BukkitPlotGenerator extends ChunkGenerator } } - @Override public boolean equals(Object obj) { + @Override public boolean equals(final Object obj) { if (obj == null) { return false; } return toString().equals(obj.toString()) || toString().equals(obj.getClass().getName()); } + } diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/DelegatePlotGenerator.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/DelegatePlotGenerator.java new file mode 100644 index 000000000..36ef53a5a --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/DelegatePlotGenerator.java @@ -0,0 +1,91 @@ +package com.github.intellectualsites.plotsquared.bukkit.generator; + +import com.github.intellectualsites.plotsquared.bukkit.util.BukkitUtil; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotWorld; +import com.github.intellectualsites.plotsquared.plot.generator.IndependentPlotGenerator; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.MathMan; +import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue; +import lombok.RequiredArgsConstructor; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.ChunkGenerator; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +@RequiredArgsConstructor final class DelegatePlotGenerator extends IndependentPlotGenerator { + + private final ChunkGenerator chunkGenerator; + private final String world; + + @Override public void initialize(PlotArea area) { + } + + @Override public PlotManager getNewPlotManager() { + return PlotSquared.get().IMP.getDefaultGenerator().getNewPlotManager(); + } + + @Override public String getName() { + return this.chunkGenerator.getClass().getName(); + } + + @Override + public PlotArea getNewPlotArea(String world, String id, PlotId min, PlotId max) { + return PlotSquared.get().IMP.getDefaultGenerator() + .getNewPlotArea(world, id, min, max); + } + + @Override public BlockBucket[][] generateBlockBucketChunk(PlotArea settings) { + BlockBucket[][] blockBuckets = new BlockBucket[16][]; + HybridPlotWorld hpw = (HybridPlotWorld) settings; + // Bedrock + if (hpw.PLOT_BEDROCK) { + for (short x = 0; x < 16; x++) { + for (short z = 0; z < 16; z++) { + blockBuckets[0][(z << 4) | x] = + BlockBucket.withSingle(PlotBlock.get("bedrock")); + } + } + } + for (short x = 0; x < 16; x++) { + for (short z = 0; z < 16; z++) { + for (int y = 1; y < hpw.PLOT_HEIGHT; y++) { + blockBuckets[y >> 4][((y & 0xF) << 8) | (z << 4) | x] = hpw.MAIN_BLOCK; + } + blockBuckets[hpw.PLOT_HEIGHT >> 4][((hpw.PLOT_HEIGHT & 0xF) << 8) | (z << 4) + | x] = hpw.MAIN_BLOCK; + } + } + return blockBuckets; + } + + @Override + public void generateChunk(final ScopedLocalBlockQueue result, PlotArea settings) { + World w = BukkitUtil.getWorld(world); + Location min = result.getMin(); + int cx = min.getX() >> 4; + int cz = min.getZ() >> 4; + Random r = new Random(MathMan.pair((short) cx, (short) cz)); + ChunkGenerator.BiomeGrid grid = new ChunkGenerator.BiomeGrid() { + @Override public void setBiome(int x, int z, Biome biome) { + result.setBiome(x, z, biome.name()); + } + + @Override @NotNull public Biome getBiome(int x, int z) { + return Biome.FOREST; + } + }; + try { + chunkGenerator.generateChunkData(w, r, cx, cz, grid); + return; + } catch (Throwable ignored) { + } + for (BlockPopulator populator : chunkGenerator.getDefaultPopulators(w)) { + populator.populate(w, r, w.getChunkAt(cx, cz)); + } + } + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/PlotBlockPopulator.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/PlotBlockPopulator.java new file mode 100644 index 000000000..4e2fee0b5 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/generator/PlotBlockPopulator.java @@ -0,0 +1,34 @@ +package com.github.intellectualsites.plotsquared.bukkit.generator; + +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.generator.IndependentPlotGenerator; +import com.github.intellectualsites.plotsquared.plot.object.ChunkWrapper; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue; +import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue; +import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue; +import lombok.RequiredArgsConstructor; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.generator.BlockPopulator; + +import java.util.Random; + +@RequiredArgsConstructor final class PlotBlockPopulator extends BlockPopulator { + + private final IndependentPlotGenerator plotGenerator; + private LocalBlockQueue queue; + + @Override public void populate(final World world, final Random random, final Chunk source) { + if (this.queue == null) { + this.queue = GlobalBlockQueue.IMP.getNewQueue(world.getName(), false); + } + final PlotArea area = PlotSquared.get().getPlotArea(world.getName(), null); + final ChunkWrapper wrap = new ChunkWrapper(area.worldname, source.getX(), source.getZ()); + final ScopedLocalBlockQueue chunk = this.queue.getForChunk(wrap.x, wrap.z); + if (this.plotGenerator.populateChunk(chunk, area)) { + this.queue.flush(); + } + } + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/block/GenChunk.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/block/GenChunk.java index 90a42db9b..020348ec5 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/block/GenChunk.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/block/GenChunk.java @@ -30,7 +30,7 @@ public class GenChunk extends ScopedLocalBlockQueue { public int cz; @Getter @Setter private ChunkData cd = null; - public GenChunk(Chunk chunk, ChunkWrapper wrap) { + public GenChunk() { super(null, new Location(null, 0, 0, 0), new Location(null, 15, 255, 15)); this.biomes = Biome.values(); } @@ -167,8 +167,7 @@ public class GenChunk extends ScopedLocalBlockQueue { } public GenChunk clone() { - GenChunk toReturn = - new GenChunk(chunk, new ChunkWrapper(getWorld(), chunk.getX(), chunk.getZ())); + GenChunk toReturn = new GenChunk(); if (this.result != null) { for (int i = 0; i < this.result.length; i++) { PlotBlock[] matrix = this.result[i]; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java index f2098036d..8c6f2c765 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java @@ -7,8 +7,6 @@ import com.github.intellectualsites.plotsquared.plot.util.MathMan; import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue; import com.sk89q.worldedit.world.block.BaseBlock; -import java.util.HashMap; - public class HybridGen extends IndependentPlotGenerator { @Override public String getName() { @@ -121,7 +119,6 @@ public class HybridGen extends IndependentPlotGenerator { } } // generation - HashMap sch = hpw.G_SCH; for (short x = 0; x < 16; x++) { if (gx[x]) { for (short z = 0; z < 16; z++) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java index b692dc04e..c8beb8ba5 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java @@ -7,16 +7,14 @@ import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue; import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue; import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; public abstract class ChunkManager { public static ChunkManager manager = null; - private static RunnableVal CURRENT_FORCE_CHUNK; - private static RunnableVal CURRENT_ADD_CHUNK; + private static final Map> forceChunks = new ConcurrentHashMap<>(); + private static final Map> addChunks = new ConcurrentHashMap<>(); public static ChunkLoc getChunkChunk(Location location) { int x = location.getX() >> 9; @@ -43,27 +41,29 @@ public abstract class ChunkManager { } queue.flush(); } else { - CURRENT_FORCE_CHUNK = force; - CURRENT_ADD_CHUNK = add; + forceChunks.put(loc, force); + addChunks.put(loc, add); queue.regenChunk(loc.x, loc.z); - CURRENT_FORCE_CHUNK = null; - CURRENT_ADD_CHUNK = null; + forceChunks.remove(loc); + addChunks.remove(loc); } } - public static boolean preProcessChunk(ScopedLocalBlockQueue queue) { - if (CURRENT_FORCE_CHUNK != null) { - CURRENT_FORCE_CHUNK.run(queue); - CURRENT_FORCE_CHUNK = null; + public static boolean preProcessChunk(ChunkLoc loc, ScopedLocalBlockQueue queue) { + final RunnableVal forceChunk = forceChunks.get(loc); + if (forceChunk != null) { + forceChunk.run(queue); + forceChunks.remove(loc); return true; } return false; } - public static boolean postProcessChunk(ScopedLocalBlockQueue queue) { - if (CURRENT_ADD_CHUNK != null) { - CURRENT_ADD_CHUNK.run(queue); - CURRENT_ADD_CHUNK = null; + public static boolean postProcessChunk(ChunkLoc loc, ScopedLocalBlockQueue queue) { + final RunnableVal addChunk = forceChunks.get(loc); + if (addChunk != null) { + addChunk.run(queue); + addChunks.remove(loc); return true; } return false;