diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/NMSAdapter.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/NMSAdapter.java index 38284966c..e15a8a9c5 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/NMSAdapter.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/NMSAdapter.java @@ -4,6 +4,7 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypesCache; import java.util.Map; import java.util.function.Function; @@ -49,6 +50,8 @@ public class NMSAdapter { int air = 0; int num_palette = 0; char[] getArr = null; + char lastOrdinal = BlockID.__RESERVED__; + boolean lastticking = false; for (int i = 0; i < 4096; i++) { char ordinal = set[i]; switch (ordinal) { @@ -75,8 +78,16 @@ public class NMSAdapter { air++; break; } - BlockState state = BlockState.getFromOrdinal(ordinal); - if (state.getMaterial().isTicksRandomly()) { + boolean ticking; + if (ordinal != lastOrdinal) { + ticking = BlockTypesCache.ticking[ordinal]; + lastOrdinal = ordinal; + lastticking = ticking; + } else { + ticking = lastticking; + } + if (ticking) { + BlockState state = BlockState.getFromOrdinal(ordinal); ticking_blocks.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15), WorldEditPlugin.getInstance().getBukkitImplAdapter() .getInternalBlockStateId(state).orElse(0)); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java index 6514b8053..bbe859074 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_14/BukkitGetBlocks_1_14.java @@ -5,6 +5,7 @@ import static org.slf4j.LoggerFactory.getLogger; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.blocks.CharBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.queue.QueueHandler; import com.boydti.fawe.bukkit.adapter.DelegateLock; @@ -620,7 +621,37 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks { if (aggressive) { sections = null; nmsChunk = null; + return super.trim(true); + } else { + for (int i = 0; i < 16; i++) { + if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) { + continue; + } + ChunkSection existing = getSections()[i]; + try { + final DataPaletteBlock blocksExisting = existing.getBlocks(); + + final DataPalette palette = (DataPalette) BukkitAdapter_1_14.fieldPalette.get(blocksExisting); + int paletteSize; + + if (palette instanceof DataPaletteLinear) { + paletteSize = ((DataPaletteLinear) palette).b(); + } else if (palette instanceof DataPaletteHash) { + paletteSize = ((DataPaletteHash) palette).b(); + } else { + super.trim(false, i); + continue; + } + if (paletteSize == 1) { + //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. + continue; + } + super.trim(false, i); + } catch (IllegalAccessException ignored) { + super.trim(false, i); + } + } + return true; } - return super.trim(aggressive); } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitGetBlocks_1_15.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitGetBlocks_1_15.java index 8f05ad098..63b04265e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitGetBlocks_1_15.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15/BukkitGetBlocks_1_15.java @@ -5,6 +5,7 @@ import static org.slf4j.LoggerFactory.getLogger; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.blocks.CharBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.queue.QueueHandler; import com.boydti.fawe.bukkit.adapter.DelegateLock; @@ -640,7 +641,37 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks { if (aggressive) { sections = null; nmsChunk = null; + return super.trim(true); + } else { + for (int i = 0; i < 16; i++) { + if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) { + continue; + } + ChunkSection existing = getSections()[i]; + try { + final DataPaletteBlock blocksExisting = existing.getBlocks(); + + final DataPalette palette = (DataPalette) BukkitAdapter_1_15.fieldPalette.get(blocksExisting); + int paletteSize; + + if (palette instanceof DataPaletteLinear) { + paletteSize = ((DataPaletteLinear) palette).b(); + } else if (palette instanceof DataPaletteHash) { + paletteSize = ((DataPaletteHash) palette).b(); + } else { + super.trim(false, i); + continue; + } + if (paletteSize == 1) { + //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. + continue; + } + super.trim(false, i); + } catch (IllegalAccessException ignored) { + super.trim(false, i); + } + } + return true; } - return super.trim(aggressive); } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java index cd4d6bc2a..8056f6e21 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java @@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit.adapter.mc1_15_2; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.blocks.CharBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.queue.QueueHandler; import com.boydti.fawe.bukkit.adapter.DelegateLock; @@ -644,7 +645,37 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { if (aggressive) { sections = null; nmsChunk = null; + return super.trim(true); + } else { + for (int i = 0; i < 16; i++) { + if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) { + continue; + } + ChunkSection existing = getSections()[i]; + try { + final DataPaletteBlock blocksExisting = existing.getBlocks(); + + final DataPalette palette = (DataPalette) BukkitAdapter_1_15_2.fieldPalette.get(blocksExisting); + int paletteSize; + + if (palette instanceof DataPaletteLinear) { + paletteSize = ((DataPaletteLinear) palette).b(); + } else if (palette instanceof DataPaletteHash) { + paletteSize = ((DataPaletteHash) palette).b(); + } else { + super.trim(false, i); + continue; + } + if (paletteSize == 1) { + //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. + continue; + } + super.trim(false, i); + } catch (IllegalAccessException ignored) { + super.trim(false, i); + } + } + return true; } - return super.trim(aggressive); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/CombinedBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/CombinedBlocks.java index 0915fed10..b5ae0014e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/CombinedBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/CombinedBlocks.java @@ -145,4 +145,9 @@ public class CombinedBlocks implements IBlocks { public boolean trim(boolean aggressive) { return false; } + + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java index 1f91546e7..c042e7a23 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IBlocks.java @@ -41,6 +41,8 @@ public interface IBlocks extends Trimable { .map(layer -> (1 << layer)).sum(); } + boolean trim(boolean aggressive, int layer); + IBlocks reset(); default byte[] toByteArray(boolean full) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/BitSetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/BitSetBlocks.java index a3712a053..4d7a6a21b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/BitSetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/BitSetBlocks.java @@ -153,4 +153,9 @@ public class BitSetBlocks implements IChunkSet { public boolean trim(boolean aggressive) { return false; } + + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java index ba49152ee..81a5c32cc 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -60,6 +60,17 @@ public abstract class CharBlocks implements IBlocks { return result; } + @Override + public boolean trim(boolean aggressive, int layer) { + boolean result = true; + if (sections[layer] == EMPTY && blocks[layer] != null) { + blocks[layer] = null; + } else { + result = false; + } + return result; + } + @Override public IChunkSet reset() { for (int i = 0; i < 16; i++) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java index 931c676be..f38d1bae4 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharGetBlocks.java @@ -25,6 +25,13 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet { return true; } + @Override + public boolean trim(boolean aggressive, int layer) { + sections[layer] = EMPTY; + blocks[layer] = null; + return true; + } + @Override public IChunkSet reset() { super.reset(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FallbackChunkGet.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FallbackChunkGet.java index 0c0ab3d44..c6b596f43 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FallbackChunkGet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/FallbackChunkGet.java @@ -85,6 +85,11 @@ public class FallbackChunkGet implements IChunkGet { return true; } + @Override + public boolean trim(boolean aggressive, int layer) { + return true; + } + @Override public > T call(IChunkSet set, Runnable finalize) { for (int layer = 0; layer < 16; layer++) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/NullChunkGet.kt b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/NullChunkGet.kt index 77e85f715..a7a5e43de 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/NullChunkGet.kt +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/NullChunkGet.kt @@ -50,6 +50,10 @@ object NullChunkGet : IChunkGet { return true } + override fun trim(aggressive: Boolean, layer: Int): Boolean { + return true + } + override fun > call(set: IChunkSet, finalize: Runnable): T? { return null } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/ChunkHolder.java index 4442faff4..a844b3079 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/ChunkHolder.java @@ -344,6 +344,11 @@ public class ChunkHolder> implements IQueueChunk { return false; } + @Override + public boolean trim(boolean aggressive, int layer) { + return this.trim(aggressive); + } + @Override public boolean isEmpty() { return chunkSet == null || chunkSet.isEmpty(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/NullChunk.kt b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/NullChunk.kt index 06a3d6e8c..6a6f33358 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/NullChunk.kt +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/NullChunk.kt @@ -117,5 +117,9 @@ object NullChunk : IQueueChunk { override fun trim(aggressive: Boolean): Boolean { return true } + + override fun trim(aggressive: Boolean, layer: Int): Boolean { + return true + } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/BatchProcessorHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/BatchProcessorHolder.java index be64c28ea..0bd4346db 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/BatchProcessorHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/BatchProcessorHolder.java @@ -4,7 +4,6 @@ import com.boydti.fawe.beta.IBatchProcessor; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; -import com.sk89q.worldedit.extent.Extent; public class BatchProcessorHolder implements IBatchProcessorHolder { private IBatchProcessor processor = EmptyBatchProcessor.INSTANCE; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java index 66f60ac69..e8717012e 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java @@ -549,6 +549,11 @@ public class MCAChunk implements IChunk { return isEmpty(); } + @Override + public boolean trim(boolean aggressive, int layer) { + return hasSection(layer); + } + @Override public CompoundTag getEntity(UUID uuid) { return this.entities.get(uuid); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypesCache.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypesCache.java index 4fb47affe..897340388 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypesCache.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypesCache.java @@ -1,6 +1,7 @@ package com.sk89q.worldedit.world.block; import com.boydti.fawe.util.MathMan; +import com.google.common.primitives.Booleans; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; @@ -166,12 +167,14 @@ public class BlockTypesCache { public static final BlockType[] values; public static final BlockState[] states; + public static final boolean[] ticking; protected static final Set $NAMESPACES = new LinkedHashSet<>(); static { try { ArrayList stateList = new ArrayList<>(); + ArrayList tickList = new ArrayList<>(); Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS); Registries registries = platform.getRegistries(); @@ -202,7 +205,7 @@ public class BlockTypesCache { if (values[internalId] != null) { throw new IllegalStateException("Invalid duplicate id for " + field.getName()); } - BlockType type = register(defaultState, internalId, stateList); + BlockType type = register(defaultState, internalId, stateList, tickList); // Note: Throws IndexOutOfBoundsError if nothing is registered and blocksMap is empty values[internalId] = type; } @@ -214,7 +217,7 @@ public class BlockTypesCache { String defaultState = entry.getValue(); // Skip already registered ids for (; values[internalId] != null; internalId++); - BlockType type = register(defaultState, internalId, stateList); + BlockType type = register(defaultState, internalId, stateList, tickList); values[internalId] = type; } } @@ -223,7 +226,7 @@ public class BlockTypesCache { } states = stateList.toArray(new BlockState[stateList.size()]); - + ticking = Booleans.toArray(tickList); } catch (Throwable e) { e.printStackTrace(); @@ -231,12 +234,14 @@ public class BlockTypesCache { } } - private static BlockType register(final String id, int internalId, List states) { + private static BlockType register(final String id, int internalId, List states, List tickList) { // Get the enum name (remove namespace if minecraft:) int propStart = id.indexOf('['); String typeName = id.substring(0, propStart == -1 ? id.length() : propStart); String enumName = (typeName.startsWith("minecraft:") ? typeName.substring(10) : typeName).toUpperCase(Locale.ROOT); + int oldsize = states.size(); BlockType existing = new BlockType(id, internalId, states); + tickList.addAll(Collections.nCopies(states.size() - oldsize, existing.getMaterial().isTicksRandomly())); // register states BlockType.REGISTRY.register(typeName, existing); String nameSpace = typeName.substring(0, typeName.indexOf(':'));