Merge pull request #2312 from IntellectualSites/async-gen

Add support for Paper async chunk generation
This commit is contained in:
Alexander Söderberg 2019-03-29 19:31:02 +01:00 committed by GitHub
commit d9407d6329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 173 additions and 164 deletions

View File

@ -63,6 +63,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain
Settings.load(new File("plugins/PlotSquared/config/settings.yml")); Settings.load(new File("plugins/PlotSquared/config/settings.yml"));
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
// Force WorldEdit to load // Force WorldEdit to load
try { try {
System.out.println("[P2] Force loading WorldEdit"); System.out.println("[P2] Force loading WorldEdit");

View File

@ -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.bukkit.util.block.GenChunk;
import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.PlotSquared;
import com.github.intellectualsites.plotsquared.plot.generator.GeneratorWrapper; 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.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.object.worlds.SingleWorldGenerator;
import com.github.intellectualsites.plotsquared.plot.util.ChunkManager; import com.github.intellectualsites.plotsquared.plot.util.ChunkManager;
import com.github.intellectualsites.plotsquared.plot.util.MainUtil; 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 com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue;
import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -28,7 +26,8 @@ import java.util.Set;
public class BukkitPlotGenerator extends ChunkGenerator public class BukkitPlotGenerator extends ChunkGenerator
implements GeneratorWrapper<ChunkGenerator> { implements GeneratorWrapper<ChunkGenerator> {
private final GenChunk chunkSetter; @SuppressWarnings("unused") public final boolean PAPER_ASYNC_SAFE = true;
private final IndependentPlotGenerator plotGenerator; private final IndependentPlotGenerator plotGenerator;
private final ChunkGenerator platformGenerator; private final ChunkGenerator platformGenerator;
private final boolean full; private final boolean full;
@ -41,24 +40,8 @@ public class BukkitPlotGenerator extends ChunkGenerator
} }
this.plotGenerator = generator; this.plotGenerator = generator;
this.platformGenerator = this; this.platformGenerator = this;
populators = new ArrayList<>(); this.populators = new ArrayList<>();
this.populators.add(new BlockPopulator() { this.populators.add(new PlotBlockPopulator(this.plotGenerator));
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.full = true; this.full = true;
MainUtil.initCache(); MainUtil.initCache();
} }
@ -69,108 +52,8 @@ public class BukkitPlotGenerator extends ChunkGenerator
+ " is already a BukkitPlotGenerator!"); + " is already a BukkitPlotGenerator!");
} }
this.full = false; 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.platformGenerator = cg;
this.plotGenerator = new IndependentPlotGenerator() { this.plotGenerator = new DelegatePlotGenerator(cg, world);
@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));
MainUtil.initCache(); MainUtil.initCache();
} }
@ -190,7 +73,7 @@ public class BukkitPlotGenerator extends ChunkGenerator
return this.platformGenerator; return this.platformGenerator;
} }
@Override public List<BlockPopulator> getDefaultPopulators(World world) { @Override @NotNull public List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
try { try {
if (!this.loaded) { if (!this.loaded) {
String name = world.getName(); String name = world.getName();
@ -224,17 +107,20 @@ public class BukkitPlotGenerator extends ChunkGenerator
if (populators == null && platformGenerator != null) { if (populators == null && platformGenerator != null) {
populators = new ArrayList<>(platformGenerator.getDefaultPopulators(world)); populators = new ArrayList<>(platformGenerator.getDefaultPopulators(world));
} }
if (populators != null) {
for (BlockPopulator populator : this.populators) { for (BlockPopulator populator : this.populators) {
if (!existing.contains(populator)) { if (!existing.contains(populator)) {
toAdd.add(populator); toAdd.add(populator);
} }
} }
}
return toAdd; return toAdd;
} }
@Override @Override @NotNull public ChunkData generateChunkData(@NotNull World world, @NotNull Random random,
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome) { int x, int z, @NotNull BiomeGrid biome) {
GenChunk result = this.chunkSetter;
GenChunk result = new GenChunk();
if (this.getPlotGenerator() instanceof SingleWorldGenerator) { if (this.getPlotGenerator() instanceof SingleWorldGenerator) {
if (result.getCd() != null) { if (result.getCd() != null) {
for (int cx = 0; cx < 16; cx++) { for (int cx = 0; cx < 16; cx++) {
@ -258,7 +144,7 @@ public class BukkitPlotGenerator extends ChunkGenerator
if (this.platformGenerator != this) { if (this.platformGenerator != this) {
return this.platformGenerator.generateChunkData(world, random, x, z, biome); return this.platformGenerator.generateChunkData(world, random, x, z, biome);
} else { } else {
generate(world, result); generate(new ChunkLoc(x, z), world, result);
} }
} catch (Throwable e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
@ -267,7 +153,7 @@ public class BukkitPlotGenerator extends ChunkGenerator
return result.getCd(); return result.getCd();
} }
private void generate(World world, ScopedLocalBlockQueue result) { private void generate(ChunkLoc loc, World world, ScopedLocalBlockQueue result) {
// Load if improperly loaded // Load if improperly loaded
if (!this.loaded) { if (!this.loaded) {
String name = world.getName(); String name = world.getName();
@ -275,17 +161,17 @@ public class BukkitPlotGenerator extends ChunkGenerator
this.loaded = true; this.loaded = true;
} }
// Process the chunk // Process the chunk
if (ChunkManager.preProcessChunk(result)) { if (ChunkManager.preProcessChunk(loc, result)) {
return; return;
} }
PlotArea area = PlotSquared.get().getPlotArea(world.getName(), null); PlotArea area = PlotSquared.get().getPlotArea(world.getName(), null);
try { try {
this.plotGenerator.generateChunk(this.chunkSetter, area); this.plotGenerator.generateChunk(result, area);
} catch (Throwable e) { } catch (Throwable e) {
// Recover from generator error // Recover from generator error
e.printStackTrace(); e.printStackTrace();
} }
ChunkManager.postProcessChunk(result); ChunkManager.postProcessChunk(loc, result);
} }
/** /**
@ -296,7 +182,7 @@ public class BukkitPlotGenerator extends ChunkGenerator
* @param z Ignored * @param z Ignored
* @return always true * @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; 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) { if (obj == null) {
return false; return false;
} }
return toString().equals(obj.toString()) || toString().equals(obj.getClass().getName()); return toString().equals(obj.toString()) || toString().equals(obj.getClass().getName());
} }
} }

View File

@ -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));
}
}
}

View File

@ -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();
}
}
}

View File

@ -30,7 +30,7 @@ public class GenChunk extends ScopedLocalBlockQueue {
public int cz; public int cz;
@Getter @Setter private ChunkData cd = null; @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)); super(null, new Location(null, 0, 0, 0), new Location(null, 15, 255, 15));
this.biomes = Biome.values(); this.biomes = Biome.values();
} }
@ -167,8 +167,7 @@ public class GenChunk extends ScopedLocalBlockQueue {
} }
public GenChunk clone() { public GenChunk clone() {
GenChunk toReturn = GenChunk toReturn = new GenChunk();
new GenChunk(chunk, new ChunkWrapper(getWorld(), chunk.getX(), chunk.getZ()));
if (this.result != null) { if (this.result != null) {
for (int i = 0; i < this.result.length; i++) { for (int i = 0; i < this.result.length; i++) {
PlotBlock[] matrix = this.result[i]; PlotBlock[] matrix = this.result[i];

View File

@ -7,8 +7,6 @@ import com.github.intellectualsites.plotsquared.plot.util.MathMan;
import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue; import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import java.util.HashMap;
public class HybridGen extends IndependentPlotGenerator { public class HybridGen extends IndependentPlotGenerator {
@Override public String getName() { @Override public String getName() {
@ -121,7 +119,6 @@ public class HybridGen extends IndependentPlotGenerator {
} }
} }
// generation // generation
HashMap<Integer, BaseBlock[]> sch = hpw.G_SCH;
for (short x = 0; x < 16; x++) { for (short x = 0; x < 16; x++) {
if (gx[x]) { if (gx[x]) {
for (short z = 0; z < 16; z++) { for (short z = 0; z < 16; z++) {

View File

@ -7,16 +7,14 @@ import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue; import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.*;
import java.util.Collection; import java.util.concurrent.ConcurrentHashMap;
import java.util.HashSet;
import java.util.Set;
public abstract class ChunkManager { public abstract class ChunkManager {
public static ChunkManager manager = null; public static ChunkManager manager = null;
private static RunnableVal<ScopedLocalBlockQueue> CURRENT_FORCE_CHUNK; private static final Map<ChunkLoc, RunnableVal<ScopedLocalBlockQueue>> forceChunks = new ConcurrentHashMap<>();
private static RunnableVal<ScopedLocalBlockQueue> CURRENT_ADD_CHUNK; private static final Map<ChunkLoc, RunnableVal<ScopedLocalBlockQueue>> addChunks = new ConcurrentHashMap<>();
public static ChunkLoc getChunkChunk(Location location) { public static ChunkLoc getChunkChunk(Location location) {
int x = location.getX() >> 9; int x = location.getX() >> 9;
@ -43,27 +41,29 @@ public abstract class ChunkManager {
} }
queue.flush(); queue.flush();
} else { } else {
CURRENT_FORCE_CHUNK = force; forceChunks.put(loc, force);
CURRENT_ADD_CHUNK = add; addChunks.put(loc, add);
queue.regenChunk(loc.x, loc.z); queue.regenChunk(loc.x, loc.z);
CURRENT_FORCE_CHUNK = null; forceChunks.remove(loc);
CURRENT_ADD_CHUNK = null; addChunks.remove(loc);
} }
} }
public static boolean preProcessChunk(ScopedLocalBlockQueue queue) { public static boolean preProcessChunk(ChunkLoc loc, ScopedLocalBlockQueue queue) {
if (CURRENT_FORCE_CHUNK != null) { final RunnableVal<ScopedLocalBlockQueue> forceChunk = forceChunks.get(loc);
CURRENT_FORCE_CHUNK.run(queue); if (forceChunk != null) {
CURRENT_FORCE_CHUNK = null; forceChunk.run(queue);
forceChunks.remove(loc);
return true; return true;
} }
return false; return false;
} }
public static boolean postProcessChunk(ScopedLocalBlockQueue queue) { public static boolean postProcessChunk(ChunkLoc loc, ScopedLocalBlockQueue queue) {
if (CURRENT_ADD_CHUNK != null) { final RunnableVal<ScopedLocalBlockQueue> addChunk = forceChunks.get(loc);
CURRENT_ADD_CHUNK.run(queue); if (addChunk != null) {
CURRENT_ADD_CHUNK = null; addChunk.run(queue);
addChunks.remove(loc);
return true; return true;
} }
return false; return false;