From 6adf0e6435a341a21685cce8fa0a3427326389e0 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 27 Apr 2019 11:15:08 +1000 Subject: [PATCH] some structure --- .../fawe/bukkit/v1_13/IQueueExtent.java | 42 +++++ .../fawe/bukkit/v1_13/beta/CachedChunk.java | 29 ---- .../fawe/bukkit/v1_13/beta/CharGetBlocks.java | 18 +++ .../v1_13/beta/DelegateQueueExtent.java | 7 + .../boydti/fawe/bukkit/v1_13/beta/Filter.java | 50 ++++++ .../bukkit/v1_13/beta/FullCharBlocks.java | 6 + .../boydti/fawe/bukkit/v1_13/beta/IChunk.java | 18 ++- .../fawe/bukkit/v1_13/beta/IGetBlocks.java | 9 ++ .../fawe/bukkit/v1_13/beta/ISetBlocks.java | 6 + .../fawe/bukkit/v1_13/beta/QueueHandler.java | 83 ++++++++++ .../bukkit/v1_13/beta/RegionCachedChunk.java | 9 -- .../bukkit/v1_13/beta/ReusableExtent.java | 150 ------------------ .../v1_13/beta/SingleThreadQueueExtent.java | 104 ++++++++++++ .../beta/bukkit/BukkitReusableExtent.java | 30 ++++ .../bukkit/v1_13/beta/holder/ChunkHolder.java | 20 ++- .../v1_13/beta/holder/DelegateChunk.java | 19 +++ .../v1_13/beta/holder/FinalizedChunk.java | 16 ++ .../bukkit/v1_13/beta/holder/FullChunk.java | 44 +++++ .../bukkit/v1_13/beta/holder/GetChunk.java | 34 ++++ .../v1_13/beta/holder/IDelegateChunk.java | 76 +++++++++ .../bukkit/v1_13/beta/holder/InitChunk.java | 47 ++++++ .../v1_13/beta/holder/ReferenceChunk.java | 23 +++ .../bukkit/v1_13/beta/holder/SetChunk.java | 25 ++- .../bukkit/v1_13/beta/holder/SoftChunk.java | 18 +++ .../bukkit/v1_13/beta/holder/WeakChunk.java | 17 ++ .../main/java/com/boydti/fawe/FaweCache.java | 78 +++++++++ 26 files changed, 781 insertions(+), 197 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java delete mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java create mode 100644 worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java new file mode 100644 index 000000000..7a0148ea3 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/IQueueExtent.java @@ -0,0 +1,42 @@ +package com.boydti.fawe.bukkit.v1_13; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.boydti.fawe.bukkit.v1_13.beta.holder.ChunkHolder; +import com.boydti.fawe.bukkit.v1_13.beta.holder.IDelegateChunk; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +public interface IQueueExtent { + void init(World world); + + IChunk getCachedChunk(int X, int Z); + + default boolean setBlock(int x, int y, int z, BlockStateHolder state) { + IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.setBlock(x & 15, y, z & 15, state); + } + + default boolean setBiome(int x, int y, int z, BiomeType biome) { + IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.setBiome(x & 15, y, z & 15, biome); + } + + default BlockState getBlock(int x, int y, int z) { + IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getBlock(x & 15, y, z & 15); + } + + default BiomeType getBiome(int x, int z) { + IChunk chunk = getCachedChunk(x >> 4, z >> 4); + return chunk.getBiome(x & 15, z & 15); + } + + // Return ChunkHolder + ChunkHolder create(boolean full); + + // Region restrictions + IDelegateChunk wrap(IChunk root); +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java deleted file mode 100644 index 3a2df1006..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CachedChunk.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import com.sk89q.jnbt.CompoundTag; -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.BlockStateHolder; -import net.minecraft.server.v1_13_R2.Chunk; -import net.minecraft.server.v1_13_R2.ChunkSection; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.UUID; - -public class CachedChunk { - private GetBlocks get; - private SetBlocks set; - - public CachedChunk(ReusableExtent parent) { - - } - - - public void init(int X, int Z) { - - } - - -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java index 62a05b707..c33ef3100 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/CharGetBlocks.java @@ -1,7 +1,25 @@ package com.boydti.fawe.bukkit.v1_13.beta; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.server.v1_13_R2.ChunkSection; public class CharGetBlocks extends CharBlocks implements IGetBlocks { private ChunkSection[] sections; + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return null; + } + + @Override + public BiomeType getBiome(int x, int z) { + return null; + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return null; + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java new file mode 100644 index 000000000..72ac950cf --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/DelegateQueueExtent.java @@ -0,0 +1,7 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.boydti.fawe.bukkit.v1_13.IQueueExtent; + +public interface IDelegateQueueExtent { + IQueueExtent getParent(); +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java new file mode 100644 index 000000000..e2bb721c1 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/Filter.java @@ -0,0 +1,50 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.sk89q.worldedit.world.block.BaseBlock; + +public class Filter { + /** + * Check whether a chunk should be read + * + * @param cx + * @param cz + * @return + */ + public boolean appliesChunk(int cx, int cz) { + return true; + } + + /** + * Do something with the IChunk
+ * - Return null if you don't want to filter blocks
+ * - Return the chunk if you do want to filter blocks
+ * + * @param chunk + * @return + */ + public IChunk applyChunk(IChunk chunk) { + return chunk; + } + + /** + * Make changes to the block here
+ * - e.g. block.setId(...)
+ * - Note: Performance is critical here
+ * + * @param x + * @param y + * @param z + * @param block + */ + public void applyBlock(int x, int y, int z, BaseBlock block) { + } + + /** + * Do something with the IChunk after block filtering
+ * + * @param chunk + * @return + */ + public void finishChunk(IChunk chunk) { + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java new file mode 100644 index 000000000..e07e6e5b0 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/FullCharBlocks.java @@ -0,0 +1,6 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +public class FullCharBlocks implements IBlocks { + public final boolean[] hasSections = new boolean[16]; + public final char[] blocks = new char[65536]; +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java index b9372b0d2..21452e0b0 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IChunk.java @@ -7,9 +7,9 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; public interface IChunk { /* set */ - void setBiome(int x, int z, BiomeType biome); + boolean setBiome(int x, int y, int z, BiomeType biome); - void setBlock(int x, int y, int z, BlockStateHolder holder); + boolean setBlock(int x, int y, int z, BlockStateHolder holder); /* get */ BiomeType getBiome(int x, int z); @@ -17,4 +17,18 @@ public interface IChunk { BlockState getBlock(int x, int y, int z); BaseBlock getFullBlock(int x, int y, int z); + + void init(SingleThreadQueueExtent extent, int X, int Z); + + int getX(); + + int getZ(); + + void apply(); + + default IChunk getRoot() { + return this; + } + + void filter(Filter filter); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java index 446a6a4d6..f0c1346d4 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/IGetBlocks.java @@ -1,4 +1,13 @@ package com.boydti.fawe.bukkit.v1_13.beta; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + public interface IGetBlocks extends IBlocks { + BaseBlock getFullBlock(int x, int y, int z); + + BiomeType getBiome(int x, int z); + + BlockState getBlock(int x, int y, int z); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java index 90f45b8c8..6793775b1 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ISetBlocks.java @@ -1,4 +1,10 @@ package com.boydti.fawe.bukkit.v1_13.beta; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + public interface ISetBlocks extends IBlocks { + void setBiome(int x, int z, BiomeType biome); + + void setBlock(int x, int y, int z, BlockStateHolder holder); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java new file mode 100644 index 000000000..9461531ab --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/QueueHandler.java @@ -0,0 +1,83 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.TaskManager; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.regions.Region; + +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; + +public class QueueHandler { + private SingleThreadQueueExtent mainExtent; + private SingleThreadQueueExtent[] pool; + + + + public static void apply(Region region, Filter filter) { // TODO not MCAFilter, but another similar class + // The chunks positions to iterate over + Set chunks = region.getChunks(); + Iterator chunksIter = chunks.iterator(); + + // Get a pool, to operate on the chunks in parallel + ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); + int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS); + ForkJoinTask[] tasks = new ForkJoinTask[size]; + + for (int i = 0; i < size; i++) { + tasks[i] = pool.submit(new Runnable() { + @Override + public void run() { + // Create a chunk that we will reuse/reset for each operation + IChunk chunk = create(true); + + while (true) { + // Get the next chunk pos + BlockVector2 pos; + synchronized (chunksIter) { + if (!chunksIter.hasNext()) return; + pos = chunksIter.next(); + } + int X = pos.getX(); + int Z = pos.getZ(); + long pair = MathMan.pairInt(X, Z); + + // Initialize + chunk.init(SingleThreadQueueExtent.this, X, Z); + + { // Start set + lastPair = pair; + lastChunk = chunk; + } + try { + if (!filter.appliesChunk(X, Z)) { + continue; + } + chunk = filter.applyChunk(chunk); + + if (chunk == null) continue; + + chunk.filter(filter); + + filter.finishChunk(chunk); + + chunk.apply(); + } finally + { // End set + lastPair = Long.MAX_VALUE; + lastChunk = null; + } + } + } + }); + } + + // Join the tasks + for (ForkJoinTask task : tasks) { + task.join(); + } + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java deleted file mode 100644 index 7984a0b80..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/RegionCachedChunk.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import net.minecraft.server.v1_13_R2.Chunk; - -public class RegionCachedChunk extends CachedChunk { - public RegionCachedChunk(Chunk chunk) { - super(chunk); - } -} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java deleted file mode 100644 index e095eb27c..000000000 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/ReusableExtent.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.boydti.fawe.bukkit.v1_13.beta; - -import com.boydti.fawe.Fawe; -import com.boydti.fawe.jnbt.anvil.MCAFilter; -import com.boydti.fawe.util.TaskManager; -import com.boydti.fawe.wrappers.WorldWrapper; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import net.minecraft.server.v1_13_R2.WorldServer; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; - -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.ForkJoinPool; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class ReusableExtent { - private WorldWrapper wrapped; - private World world; - private org.bukkit.World bukkitWorld; - private WorldServer nmsWorld; - - private void reset() { - if (world != null) { - wrapped = null; - world = null; - bukkitWorld = null; - nmsWorld = null; - lowMemory = false; - } - } - - public void init(World world) { - reset(); - checkNotNull(world); - if (world instanceof EditSession) { - world = ((EditSession) world).getWorld(); - } - checkNotNull(world); - if (world instanceof WorldWrapper) { - this.wrapped = (WorldWrapper) world; - world = WorldWrapper.unwrap(world); - } else { - this.world = WorldWrapper.wrap(world); - } - this.world = world; - if (world instanceof BukkitWorld) { - this.bukkitWorld = ((BukkitWorld) world).getWorld(); - } else { - this.bukkitWorld = Bukkit.getWorld(world.getName()); - } - checkNotNull(this.bukkitWorld); - CraftWorld craftWorld = ((CraftWorld) bukkitWorld); - this.nmsWorld = craftWorld.getHandle(); - // Save world - } - - private boolean lowMemory; - - public void setLowMemory() { - lowMemory = true; - // set queue state to active - // trim cached chunks - } - - private CachedChunk getCachedChunk(int x, int z) { - // check last - // otherwise create/load - // get cached chunk from bukkit - // otherwise load - // TODO load async (with paper) - if (lowMemory) { - if (Fawe.isMainThread()) { - // submit other chunks - next(); - } else { - // wait until empty - } - } - } - - void setBlock(int x, int y, int z, BlockStateHolder holder) { - CachedChunk chunk = getCachedChunk(x, z); - chunk.setBlock(x & 15, y, z & 15, holder); - } - - void setBiome(int x, int z, BiomeType biome) { - CachedChunk chunk = getCachedChunk(x, z); - chunk.setBiome(x, z, biome); - } - - BlockState getBlock(int x, int y, int z) { - CachedChunk chunk = getCachedChunk(x, z); - return chunk.getBlock(x & 15, y, z & 15); - } - - BiomeType getBiome(int x, int z) { - CachedChunk chunk = getCachedChunk(x, z); - return chunk.getBiome(x, z); - } - - public void apply(Region region, MCAFilter filter) { // TODO not MCAFilter, but another similar class - // TODO iterate by mca file - Set chunks = region.getChunks(); - Iterator chunksIter = chunks.iterator(); - ForkJoinPool pool = TaskManager.IMP.getPublicForkJoinPool(); - for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) { - pool.submit(new Runnable() { - @Override - public void run() { - while (true) { - BlockVector2 pos; - synchronized (chunksIter) { - if (!chunksIter.hasNext()) return; - pos = chunksIter.next(); - } - int cx = pos.getX(); - int cz = pos.getZ(); - CachedChunk chunk = getCachedChunk(cx, cz); - try { - if (!filter.appliesChunk(cx, cz)) { - continue; - } - T value = filter.get(); - chunk = filter.applyChunk(chunk, value); - - if (chunk == null) continue; - - // TODO if region contains all parts - chunk.filter(filter); - // else - chunk.filter(region, filter); - } finally { - // TODO submit chunk - } - } - } - }); - } - } -} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java new file mode 100644 index 000000000..53f1984e4 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/SingleThreadQueueExtent.java @@ -0,0 +1,104 @@ +package com.boydti.fawe.bukkit.v1_13.beta; + +import com.boydti.fawe.bukkit.v1_13.IQueueExtent; +import com.boydti.fawe.bukkit.v1_13.beta.holder.ChunkHolder; +import com.boydti.fawe.bukkit.v1_13.beta.holder.IDelegateChunk; +import com.boydti.fawe.bukkit.v1_13.beta.holder.ReferenceChunk; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.util.MathMan; +import com.boydti.fawe.util.MemUtil; +import com.boydti.fawe.wrappers.WorldWrapper; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.world.World; +import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; + +import static com.google.common.base.Preconditions.checkNotNull; + +public abstract class SingleThreadQueueExtent implements IQueueExtent { + private WorldWrapper wrapped; + private World world; + + public World getWorld() { + return world; + } + + public WorldWrapper getWrappedWorld() { + return wrapped; + } + + private void reset() { + wrapped = null; + world = null; + chunks.clear(); + lastChunk = null; + lastPair = Long.MAX_VALUE; + } + + public synchronized void init(World world) { + if (world != null) { + reset(); + } + checkNotNull(world); + if (world instanceof EditSession) { + world = ((EditSession) world).getWorld(); + } + checkNotNull(world); + if (world instanceof WorldWrapper) { + this.wrapped = (WorldWrapper) world; + world = WorldWrapper.unwrap(world); + } else { + this.wrapped = WorldWrapper.wrap(world); + } + this.world = world; + } + + private IChunk lastChunk; + private long lastPair = Long.MAX_VALUE; + private final Long2ObjectLinkedOpenHashMap chunks = new Long2ObjectLinkedOpenHashMap<>(); + + private final IDelegateChunk getCachedChunk2(long pair) { + IDelegateChunk chunk = chunks.get(pair); + if (chunk instanceof ReferenceChunk) { + chunk = (ReferenceChunk) (chunk).getParent(); + } + if (chunk != null) { + lastPair = pair; + lastChunk = chunk; + } + return chunk; + } + + public final IChunk getCachedChunk(int X, int Z) { + long pair = MathMan.pairInt(X, Z); + if (pair == lastPair) { + return lastChunk; + } + + IDelegateChunk chunk = getCachedChunk2(pair); + if (chunk != null) return chunk; + + chunk = getCachedChunk2(pair); + if (chunk != null) return chunk; + + int size = chunks.size(); + if (size > Settings.IMP.QUEUE.TARGET_SIZE || MemUtil.isMemoryLimited()) { + if (size > Settings.IMP.QUEUE.PARALLEL_THREADS * 2 + 16) { + chunk = chunks.removeFirst(); + chunk.apply(); + chunk = (IDelegateChunk) chunk.findParent(ChunkHolder.class); + chunk.init(this, X, Z); + } else { + chunk = create(false); + } + } else { + chunk = create(false); + } + chunk = wrap(chunk); + + chunks.put(pair, chunk); + lastPair = pair; + lastChunk = chunk; + + return chunk; + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java new file mode 100644 index 000000000..90f34b5dd --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/bukkit/BukkitReusableExtent.java @@ -0,0 +1,30 @@ +package com.boydti.fawe.bukkit.v1_13.beta.bukkit; + +import com.boydti.fawe.bukkit.v1_13.beta.SingleThreadQueueExtent; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.world.World; +import net.minecraft.server.v1_13_R2.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class BukkitReusableExtent extends SingleThreadQueueExtent { + private org.bukkit.World bukkitWorld; + private WorldServer nmsWorld; + + public void init(World world) { + super.init(world); + world = getWorld(); + + if (world instanceof BukkitWorld) { + this.bukkitWorld = ((BukkitWorld) world).getWorld(); + } else { + this.bukkitWorld = Bukkit.getWorld(world.getName()); + } + checkNotNull(this.bukkitWorld); + CraftWorld craftWorld = ((CraftWorld) bukkitWorld); + this.nmsWorld = craftWorld.getHandle(); + } + +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java index cba2c2e3a..cf4ebf092 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ChunkHolder.java @@ -1,13 +1,21 @@ package com.boydti.fawe.bukkit.v1_13.beta.holder; -import com.boydti.fawe.bukkit.v1_13.beta.IChunk; - -public class ChunkHolder implements IChunk { - private ChunkHolder implementation; +import com.boydti.fawe.bukkit.v1_13.beta.CharGetBlocks; +import com.boydti.fawe.bukkit.v1_13.beta.CharSetBlocks; +import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; +import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; +public class ChunkHolder extends DelegateChunk { public ChunkHolder() { - + super(new InitChunk(null)); + getParent().setParent(this); } - public ChunkHolder(IChunkH) + protected final IGetBlocks get() { + return new CharGetBlocks(); + } + + protected final ISetBlocks set() { + return new CharSetBlocks(); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java new file mode 100644 index 000000000..19ddffbc0 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/DelegateChunk.java @@ -0,0 +1,19 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +public class DelegateChunk implements IDelegateChunk { + private T parent; + + public DelegateChunk(T parent) { + this.parent = parent; + } + + public final T getParent() { + return parent; + } + + public final void setParent(T parent) { + this.parent = parent; + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java new file mode 100644 index 000000000..bd2e9092f --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FinalizedChunk.java @@ -0,0 +1,16 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +public class FinalizedChunk extends DelegateChunk { + public FinalizedChunk(IChunk parent) { + super(parent); + } + + @Override + protected void finalize() throws Throwable { + apply(); + setParent(null); + super.finalize(); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java new file mode 100644 index 000000000..c5c7b3272 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/FullChunk.java @@ -0,0 +1,44 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; +import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; +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.BlockStateHolder; + +public class FullChunk extends DelegateChunk { + private final ISetBlocks set; + private final IGetBlocks get; + + public FullChunk(ChunkHolder parent, IGetBlocks get, ISetBlocks set) { + super(parent); + this.set = set == null ? parent.set() : set; + this.get = get == null ? parent.get() : get; + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return get.getFullBlock(x, y, z); + } + + @Override + public BiomeType getBiome(int x, int z) { + return get.getBiome(x, z); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return get.getBlock(x, y, z); + } + + @Override + public void setBiome(int x, int z, BiomeType biome) { + set.setBiome(x, z, biome); + } + + @Override + public void setBlock(int x, int y, int z, BlockStateHolder holder) { + set.setBlock(x, y, z, holder); + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java new file mode 100644 index 000000000..d6747c328 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/GetChunk.java @@ -0,0 +1,34 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IGetBlocks; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; + +public class GetChunk extends InitChunk { + private final IGetBlocks get; + + public GetChunk(ChunkHolder parent) { + super(parent); + this.get = parent.get(); + } + + protected void init() { + getParent().setParent(new FullChunk(getParent(), get, null)); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + return get.getFullBlock(x, y, z); + } + + @Override + public BiomeType getBiome(int x, int z) { + return get.getBiome(x, z); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + return get.getBlock(x, y, z); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java new file mode 100644 index 000000000..e71172bc4 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/IDelegateChunk.java @@ -0,0 +1,76 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.boydti.fawe.bukkit.v1_13.beta.SingleThreadQueueExtent; +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.BlockStateHolder; + +public interface IDelegateChunk extends IChunk { + T getParent(); + + default IChunk getRoot() { + IChunk root = getParent(); + while (root instanceof IDelegateChunk) { + root = ((IDelegateChunk) root).getParent(); + } + return root; + } + + @Override + default void setBiome(int x, int z, BiomeType biome) { + getParent().setBiome(x, z, biome); + } + + @Override + default void setBlock(int x, int y, int z, BlockStateHolder holder) { + getParent().setBlock(x, y, z, holder); + } + + @Override + default BiomeType getBiome(int x, int z) { + return getParent().getBiome(x, z); + } + + @Override + default BlockState getBlock(int x, int y, int z) { + return getParent().getBlock(x, y, z); + } + + @Override + default BaseBlock getFullBlock(int x, int y, int z) { + return getParent().getFullBlock(x, y, z); + } + + @Override + default void init(SingleThreadQueueExtent extent, int X, int Z) { + getParent().init(extent, X, Z); + } + + @Override + default int getX() { + return getParent().getX(); + } + + @Override + default int getZ() { + return getParent().getZ(); + } + + @Override + default void apply() { + getParent().apply(); + } + + default IChunk findParent(Class clazz) { + IChunk root = getParent(); + if (clazz.isAssignableFrom(root.getClass())) return root; + while (root instanceof IDelegateChunk) { + root = ((IDelegateChunk) root).getParent(); + if (clazz.isAssignableFrom(root.getClass())) return root; + } + return null; + } + +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java new file mode 100644 index 000000000..d2a9599b2 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/InitChunk.java @@ -0,0 +1,47 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +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.BlockStateHolder; + +public class InitChunk extends DelegateChunk { + public InitChunk(ChunkHolder parent) { + super(parent); + } + + protected void init() { + getParent().setParent(new SetChunk(getParent())); + } + + @Override + public void setBiome(int x, int z, BiomeType biome) { + init(); + super.setBiome(x, z, biome); + } + + @Override + public void setBlock(int x, int y, int z, BlockStateHolder holder) { + init(); + super.setBlock(x, y, z, holder); + } + + @Override + public BiomeType getBiome(int x, int z) { + init(); + return super.getBiome(x, z); + } + + @Override + public BlockState getBlock(int x, int y, int z) { + init(); + return super.getBlock(x, y, z); + } + + @Override + public BaseBlock getFullBlock(int x, int y, int z) { + init(); + return super.getFullBlock(x, y, z); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java new file mode 100644 index 000000000..24607335a --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/ReferenceChunk.java @@ -0,0 +1,23 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; + +public abstract class ReferenceChunk implements IDelegateChunk { + private final Reference ref; + + public ReferenceChunk(IChunk parent) { + this.ref = toRef(new FinalizedChunk(parent)); + } + + protected abstract Reference toRef(FinalizedChunk parent); + + @Override + public IChunk getParent() { + FinalizedChunk finalized = ref.get(); + return finalized != null ? finalized.getParent() : null; + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java index 6d58ef8c4..3b34c7617 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SetChunk.java @@ -1,7 +1,30 @@ package com.boydti.fawe.bukkit.v1_13.beta.holder; import com.boydti.fawe.bukkit.v1_13.beta.IChunk; +import com.boydti.fawe.bukkit.v1_13.beta.ISetBlocks; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; -public class SetChunk extends ChunkHolder { +public class SetChunk extends InitChunk { + private final ISetBlocks set; + + public SetChunk(ChunkHolder parent) { + super(parent); + this.set = parent.set(); + } + + protected void init() { + getParent().setParent(new FullChunk(getParent(), null, set)); + } + + @Override + public void setBiome(int x, int z, BiomeType biome) { + set.setBiome(x, z, biome); + } + + @Override + public void setBlock(int x, int y, int z, BlockStateHolder holder) { + set.setBlock(x, y, z, holder); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java new file mode 100644 index 000000000..5c435d7a6 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/SoftChunk.java @@ -0,0 +1,18 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; + +public class SoftChunk extends ReferenceChunk { + + public SoftChunk(IChunk parent) { + super(parent); + } + + @Override + protected Reference toRef(FinalizedChunk parent) { + return new SoftReference<>(parent); + } +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java new file mode 100644 index 000000000..b574ed010 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/v1_13/beta/holder/WeakChunk.java @@ -0,0 +1,17 @@ +package com.boydti.fawe.bukkit.v1_13.beta.holder; + +import com.boydti.fawe.bukkit.v1_13.beta.IChunk; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; + +public class WeakChunk extends ReferenceChunk { + public WeakChunk(IChunk parent) { + super(parent); + } + + @Override + protected Reference toRef(FinalizedChunk parent) { + return new WeakReference<>(parent); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java index c3ed20bf8..bf8369411 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -1,14 +1,40 @@ package com.boydti.fawe; +import com.boydti.fawe.jnbt.anvil.BitArray4096; import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.*; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import java.lang.reflect.Field; import java.util.*; public class FaweCache { + public static final IterableThreadLocal BLOCK_TO_PALETTE_CHAR = new IterableThreadLocal() { + @Override + public char[] init() { + char[] result = new char[BlockTypes.states.length]; + Arrays.fill(result, Character.MAX_VALUE); + return result; + } + }; + + public static final IterableThreadLocal PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal() { + @Override + public char[] init() { + return new char[Character.MAX_VALUE]; + } + }; + + public static final IterableThreadLocal SECTION_BLOCKS_CHAR = new IterableThreadLocal() { + @Override + public char[] init() { + return new char[4096]; + } + }; + public static final IterableThreadLocal BLOCK_TO_PALETTE = new IterableThreadLocal() { @Override public int[] init() { @@ -179,4 +205,56 @@ public class FaweCache { if (clazz == null) clazz = EndTag.class; return new ListTag(clazz, list); } + + private static final class Palette { + + } + + public void toPalette(int layer, char[] blocks) { + int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get(); + int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get(); + long[] blockstates = FaweCache.BLOCK_STATES.get(); + int[] blocksCopy = FaweCache.SECTION_BLOCKS.get(); + + int blockIndexStart = layer << 12; + int blockIndexEnd = blockIndexStart + 4096; + int num_palette = 0; + try { + for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) { + int ordinal = blocks[i]; + int palette = blockToPalette[ordinal]; + if (palette == Integer.MAX_VALUE) { + BlockState state = BlockTypes.states[ordinal]; + blockToPalette[ordinal] = palette = num_palette; + paletteToBlock[num_palette] = ordinal; + num_palette++; + } + blocksCopy[j] = palette; + } + + for (int i = 0; i < num_palette; i++) { + blockToPalette[paletteToBlock[i]] = Integer.MAX_VALUE; + } + + // BlockStates + int bitsPerEntry = MathMan.log2nlz(num_palette - 1); + int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; + if (num_palette == 1) { + // Set a value, because minecraft needs it for some reason + blockstates[0] = 0; + blockBitArrayEnd = 1; + } else { + BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry); + bitArray.fromRaw(blocksCopy); + } + + // num_palette + // paletteToBlock + // blockstates (range: blockBitArrayEnd) + } catch (Throwable e) { + Arrays.fill(blockToPalette, Integer.MAX_VALUE); + e.printStackTrace(); + throw e; + } + } }