Add support for Paper async chunk generation

This commit is contained in:
Sauilitired 2019-03-26 09:27:20 +01:00
parent c9f38430c6
commit c6ae2456f2
No known key found for this signature in database
GPG Key ID: C0207FF7EA146678
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"));
} catch (Throwable ignored) {
}
// Force WorldEdit to load
try {
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.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<ChunkGenerator> {
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<BlockPopulator> getDefaultPopulators(World world) {
@Override @NotNull public List<BlockPopulator> 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));
}
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());
}
}

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;
@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];

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.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<Integer, BaseBlock[]> sch = hpw.G_SCH;
for (short x = 0; x < 16; x++) {
if (gx[x]) {
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 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<ScopedLocalBlockQueue> CURRENT_FORCE_CHUNK;
private static RunnableVal<ScopedLocalBlockQueue> CURRENT_ADD_CHUNK;
private static final Map<ChunkLoc, RunnableVal<ScopedLocalBlockQueue>> forceChunks = new ConcurrentHashMap<>();
private static final Map<ChunkLoc, RunnableVal<ScopedLocalBlockQueue>> 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<ScopedLocalBlockQueue> 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<ScopedLocalBlockQueue> addChunk = forceChunks.get(loc);
if (addChunk != null) {
addChunk.run(queue);
addChunks.remove(loc);
return true;
}
return false;