From 4ddffb197b46fcc39c2efaa280d4f1baf23cefd6 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 20 Aug 2016 13:33:56 +1000 Subject: [PATCH] Various More work on anvil API Fix IO exception with history on disk Optimize chunk index caching --- .../fawe/bukkit/v1_10/BukkitChunk_1_10.java | 2 +- .../fawe/bukkit/v1_10/BukkitQueue_1_10.java | 20 +- .../fawe/bukkit/v1_7/BukkitChunk_1_7.java | 4 +- .../fawe/bukkit/v1_7/BukkitQueue17.java | 14 +- .../fawe/bukkit/v1_8/BukkitQueue18R3.java | 14 +- .../fawe/bukkit/v1_9/BukkitChunk_1_9.java | 2 +- .../fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java | 18 +- .../main/java/com/boydti/fawe/FaweCache.java | 12 +- .../boydti/fawe/example/CharFaweChunk.java | 26 +- .../fawe/example/DefaultFaweQueueMap.java | 118 ++++++ .../boydti/fawe/example/IFaweQueueMap.java | 22 + .../boydti/fawe/example/MappedFaweQueue.java | 236 +++-------- .../fawe/example/NMSMappedFaweQueue.java | 8 +- .../java/com/boydti/fawe/jnbt/MCAChunk.java | 22 - .../java/com/boydti/fawe/jnbt/MCAFile.java | 146 ------- .../com/boydti/fawe/jnbt/anvil/MCAChunk.java | 397 ++++++++++++++++++ .../com/boydti/fawe/jnbt/anvil/MCAFile.java | 347 +++++++++++++++ .../fawe/jnbt/{ => anvil}/MCAQueue.java | 146 ++++--- .../boydti/fawe/jnbt/anvil/MCAQueueMap.java | 45 ++ .../com/boydti/fawe/object/FaweChunk.java | 2 +- .../com/boydti/fawe/object/FaweQueue.java | 6 +- .../com/boydti/fawe/object/RunnableVal4.java | 24 ++ .../fawe/object/changeset/FaweChangeSet.java | 12 +- .../boydti/fawe/object/extent/MCAExtent.java | 2 +- .../fawe/object/extent/ProcessedWEExtent.java | 3 + .../general/plot/FaweLocalBlockQueue.java | 2 +- .../boydti/fawe/util/DelegateFaweQueue.java | 4 +- .../java/com/boydti/fawe/util/SetQueue.java | 25 +- .../com/sk89q/worldedit/LocalSession.java | 2 +- .../boydti/fawe/forge/v0/ForgeChunk_All.java | 2 +- .../boydti/fawe/forge/v0/ForgeQueue_All.java | 12 +- .../boydti/fawe/forge/v0/ForgeChunk_All.java | 4 +- .../boydti/fawe/forge/v0/ForgeQueue_All.java | 14 +- .../boydti/fawe/forge/v0/ForgeQueue_All.java | 18 +- .../boydti/fawe/forge/v0/ForgeChunk_All.java | 2 +- .../boydti/fawe/forge/v0/ForgeQueue_All.java | 12 +- .../fawe/sponge/v1_8/SpongeQueue_1_8.java | 16 +- .../fawe/sponge/v1_8/SpongeQueue_ALL.java | 10 +- 38 files changed, 1224 insertions(+), 547 deletions(-) create mode 100644 core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java create mode 100644 core/src/main/java/com/boydti/fawe/example/IFaweQueueMap.java delete mode 100644 core/src/main/java/com/boydti/fawe/jnbt/MCAChunk.java delete mode 100644 core/src/main/java/com/boydti/fawe/jnbt/MCAFile.java create mode 100644 core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java create mode 100644 core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java rename core/src/main/java/com/boydti/fawe/jnbt/{ => anvil}/MCAQueue.java (56%) create mode 100644 core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueueMap.java create mode 100644 core/src/main/java/com/boydti/fawe/object/RunnableVal4.java diff --git a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10.java b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10.java index 4341d34e..999c3468 100644 --- a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10.java +++ b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10.java @@ -115,7 +115,7 @@ public class BukkitChunk_1_10 extends CharFaweChunk { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - char combinedId = blocks[FaweCache.CACHE_J[y][x][z]]; + char combinedId = blocks[FaweCache.CACHE_J[y][z][x]]; if (combinedId > 1) { palette.setBlock(x, y, z, Block.getById(combinedId >> 4).fromLegacyData(combinedId & 0xF)); } diff --git a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java index de0f460d..a601d85b 100644 --- a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java +++ b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java @@ -128,7 +128,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0 255) { continue; } - if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -607,12 +607,12 @@ public class BukkitQueue_1_10 extends BukkitQueue_0(); @@ -666,10 +666,10 @@ public class BukkitQueue_1_10 extends BukkitQueue_0 { @Override public void setBlock(int x, int y, int z, int id, int data) { - int i = FaweCache.CACHE_I[y][x][z]; - int j = FaweCache.CACHE_J[y][x][z]; + int i = FaweCache.CACHE_I[y][z][x]; + int j = FaweCache.CACHE_J[y][z][x]; byte[] vs = this.byteIds[i]; char[] vs2 = this.ids[i]; if (vs2 == null) { diff --git a/bukkit1710/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java b/bukkit1710/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java index b80e32f5..feac3653 100644 --- a/bukkit1710/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java +++ b/bukkit1710/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java @@ -116,7 +116,7 @@ public class BukkitQueue17 extends BukkitQueue_0 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -309,12 +309,12 @@ public class BukkitQueue17 extends BukkitQueue_0(); @@ -642,7 +642,7 @@ public class BukkitQueue17 extends BukkitQueue_0 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -306,12 +306,12 @@ public class BukkitQueue18R3 extends BukkitQueue_0(); @@ -634,7 +634,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0 { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - char combinedId = blocks[FaweCache.CACHE_J[y][x][z]]; + char combinedId = blocks[FaweCache.CACHE_J[y][z][x]]; if (combinedId > 1) { palette.setBlock(x, y, z, Block.getById(combinedId >> 4).fromLegacyData(combinedId & 0xF)); } diff --git a/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java b/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java index 9a99a7ec..003689e4 100644 --- a/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java +++ b/bukkit19/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java @@ -297,12 +297,12 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0 255)) { return 1; } - final int i = FaweCache.CACHE_I[y][x][z]; + final int i = FaweCache.CACHE_I[y][z][x]; final char[] section = sections[i]; if (section == null) { return 0; } - final int j = FaweCache.CACHE_J[y][x][z]; + final int j = FaweCache.CACHE_J[y][z][x]; return section[j] >> 4; } @@ -401,12 +401,12 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0 255) { continue; } - if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -553,12 +553,12 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0(); @@ -620,7 +620,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0 index + * [ y | z | x ] => index */ public final static short[][][] CACHE_I = new short[256][16][16]; /** - * [ y | x | z ] => index + * [ y | z | x ] => index */ public final static short[][][] CACHE_J = new short[256][16][16]; @@ -128,8 +128,8 @@ public class FaweCache { for (int y = 0; y < 256; y++) { final short i = (short) (y >> 4); final short j = (short) (((y & 0xF) << 8) | (z << 4) | x); - CACHE_I[y][x][z] = i; - CACHE_J[y][x][z] = j; + CACHE_I[y][z][x] = i; + CACHE_J[y][z][x] = j; CACHE_X[i][j] = (byte) x; CACHE_Y[i][j] = (short) y; CACHE_Z[i][j] = (byte) z; @@ -622,9 +622,12 @@ public class FaweCache { return asTag((Collection) value); } else if (value instanceof byte[]) { return asTag((byte[]) value); + } else if (value instanceof int[]) { + return asTag((int[]) value); } else if (value instanceof Tag) { return (Tag) value; } else if (value == null) { + System.out.println("Invalid nbt: " + value); return null; } else { Class clazz = value.getClass(); @@ -640,6 +643,7 @@ public class FaweCache { e.printStackTrace(); } } + System.out.println("Invalid nbt: " + value); return null; } } diff --git a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java index 0310082c..2adb75a0 100644 --- a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java @@ -24,6 +24,12 @@ public abstract class CharFaweChunk extends FaweChunk { public int[][] biomes; private int bitMask = -1; + public HashMap tiles; + + public HashSet entities; + + public HashSet entityRemoves; + public T chunk; /** @@ -139,16 +145,14 @@ public abstract class CharFaweChunk extends FaweChunk { } public int getCombinedId(int x, int y, int z) { - short i = FaweCache.CACHE_I[y][x][z]; + short i = FaweCache.CACHE_I[y][z][x]; char[] array = getIdArray(i); if (array == null) { return 0; } - return array[FaweCache.CACHE_J[y][x][z]]; + return array[FaweCache.CACHE_J[y][z][x]]; } - public HashMap tiles; - @Override public void setTile(int x, int y, int z, CompoundTag tile) { if (tiles == null) { @@ -181,12 +185,6 @@ public abstract class CharFaweChunk extends FaweChunk { return entities == null ? new HashSet() : entities; } - - - public HashSet entities; - - public HashSet entityRemoves; - @Override public void setEntity(CompoundTag tag) { if (entities == null) { @@ -210,8 +208,8 @@ public abstract class CharFaweChunk extends FaweChunk { @Override public void setBlock(int x, int y, int z, int id) { - final int i = FaweCache.CACHE_I[y][x][z]; - final int j = FaweCache.CACHE_J[y][x][z]; + final int i = FaweCache.CACHE_I[y][z][x]; + final int j = FaweCache.CACHE_J[y][z][x]; char[] vs = this.ids[i]; if (vs == null) { vs = this.ids[i] = new char[4096]; @@ -249,8 +247,8 @@ public abstract class CharFaweChunk extends FaweChunk { @Override public void setBlock(final int x, final int y, final int z, final int id, int data) { - final int i = FaweCache.CACHE_I[y][x][z]; - final int j = FaweCache.CACHE_J[y][x][z]; + final int i = FaweCache.CACHE_I[y][z][x]; + final int j = FaweCache.CACHE_J[y][z][x]; char[] vs = this.ids[i]; if (vs == null) { vs = this.ids[i] = new char[4096]; diff --git a/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java b/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java new file mode 100644 index 00000000..2dd08edb --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java @@ -0,0 +1,118 @@ +package com.boydti.fawe.example; + +import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.RunnableVal; +import com.boydti.fawe.util.MainUtil; +import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; + +public class DefaultFaweQueueMap implements IFaweQueueMap { + + private final MappedFaweQueue parent; + + public DefaultFaweQueueMap(MappedFaweQueue parent) { + this.parent = parent; + } + + /** + * Map of chunks in the queue + */ + public ConcurrentHashMap blocks = new ConcurrentHashMap<>(); + public ConcurrentLinkedDeque chunks = new ConcurrentLinkedDeque() { + @Override + public boolean add(FaweChunk o) { + if (parent.getProgressTask() != null) { + parent.getProgressTask().run(FaweQueue.ProgressType.QUEUE, size() + 1); + } + return super.add(o); + } + }; + + @Override + public Collection getFaweCunks() { + return new HashSet<>(chunks); + } + + @Override + public void forEachChunk(RunnableVal onEach) { + for (FaweChunk chunk : chunks) { + onEach.run(chunk); + } + } + + @Override + public FaweChunk getFaweChunk(int cx, int cz) { + if (cx == lastX && cz == lastZ) { + return lastWrappedChunk; + } + long pair = (long) (lastX = cx) << 32 | (lastX = cz) & 0xFFFFFFFFL; + FaweChunk chunk = this.blocks.get(pair); + if (chunk == null) { + chunk = this.getNewFaweChunk(cx, cz); + FaweChunk previous = this.blocks.put(pair, chunk); + if (previous != null) { + blocks.put(pair, previous); + return previous; + } + this.blocks.put(pair, previous); + chunks.add(previous); + } + return chunk; + } + + @Override + public void add(FaweChunk chunk) { + long pair = (long) (chunk.getX()) << 32 | (chunk.getZ()) & 0xFFFFFFFFL; + FaweChunk previous = this.blocks.put(pair, chunk); + if (previous == null) { + chunks.add(chunk); + } else { + blocks.put(pair, previous); + } + } + + + @Override + public void clear() { + blocks.clear(); + chunks.clear(); + } + + @Override + public int size() { + return chunks.size(); + } + + private FaweChunk getNewFaweChunk(int cx, int cz) { + return parent.getFaweChunk(cx, cz); + } + + private FaweChunk lastWrappedChunk; + private int lastX = Integer.MIN_VALUE; + private int lastZ = Integer.MIN_VALUE; + + @Override + public boolean next() { + lastX = Integer.MIN_VALUE; + lastZ = Integer.MIN_VALUE; + try { + if (this.blocks.size() == 0) { + return false; + } + synchronized (blocks) { + FaweChunk chunk = chunks.poll(); + if (chunk != null) { + blocks.remove(chunk.longHash()); + parent.execute(chunk); + return true; + } + } + } catch (Throwable e) { + MainUtil.handleError(e); + } + return false; + } +} diff --git a/core/src/main/java/com/boydti/fawe/example/IFaweQueueMap.java b/core/src/main/java/com/boydti/fawe/example/IFaweQueueMap.java new file mode 100644 index 00000000..c9506007 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/example/IFaweQueueMap.java @@ -0,0 +1,22 @@ +package com.boydti.fawe.example; + +import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.object.RunnableVal; +import java.util.Collection; + +public interface IFaweQueueMap { + + Collection getFaweCunks(); + + void forEachChunk(RunnableVal onEach); + + FaweChunk getFaweChunk(int cx, int cz); + + void add(FaweChunk chunk); + + void clear(); + + int size(); + + boolean next(); +} diff --git a/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java b/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java index 52baad5c..f2704e59 100644 --- a/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java @@ -19,48 +19,53 @@ import com.sk89q.worldedit.world.registry.BundledBlockData; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; public abstract class MappedFaweQueue extends FaweQueue { private WORLD impWorld; - /** - * Map of chunks in the queue - */ - public ConcurrentHashMap blocks = new ConcurrentHashMap<>(); - public ConcurrentLinkedDeque chunks = new ConcurrentLinkedDeque() { - @Override - public boolean add(FaweChunk o) { - if (getProgressTask() != null) { - getProgressTask().run(ProgressType.QUEUE, size() + 1); - } - return super.add(o); - } - }; + private IFaweQueueMap map; public ArrayDeque tasks = new ArrayDeque<>(); + public MappedFaweQueue(final String world) { + this(world, null); + } + + public MappedFaweQueue(final String world, IFaweQueueMap map) { + super(world); + if (map == null) { + map = new DefaultFaweQueueMap(this); + } + this.map = map; + } + + public IFaweQueueMap getFaweQueueMap() { + return map; + } + @Override public Collection getFaweChunks() { - return Collections.unmodifiableCollection(chunks); + return map.getFaweCunks(); } @Override public void optimize() { - ArrayList threads = new ArrayList(); - for (final FaweChunk chunk : chunks) { - Thread thread = new Thread(new Runnable() { - @Override - public void run() { - chunk.optimize(); - } - }); - threads.add(thread); - thread.start(); - } + final ArrayList threads = new ArrayList(); + map.forEachChunk(new RunnableVal() { + @Override + public void run(final FaweChunk chunk) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + chunk.optimize(); + } + }); + threads.add(thread); + thread.start(); + } + }); for (Thread thread : threads) { try { thread.join(); @@ -76,10 +81,6 @@ public abstract class MappedFaweQueue extends FaweQueue { size(); } - public MappedFaweQueue(final String world) { - super(world); - } - public abstract WORLD getImpWorld(); public abstract boolean isChunkLoaded(WORLD world, int x, int z); @@ -114,50 +115,16 @@ public abstract class MappedFaweQueue extends FaweQueue { @Override public void addNotifyTask(int x, int z, Runnable runnable) { - long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL; - FaweChunk result = this.blocks.get(pair); - if (result == null) { - result = this.getFaweChunk(x, z); - result.addNotifyTask(runnable); - FaweChunk previous = this.blocks.put(pair, result); - if (previous == null) { - chunks.add(result); - return; - } - this.blocks.put(pair, previous); - result = previous; - } - result.addNotifyTask(runnable); + FaweChunk chunk = map.getFaweChunk(x, z); + chunk.addNotifyTask(runnable); } - - - private FaweChunk lastWrappedChunk; - private int lastX = Integer.MIN_VALUE; - private int lastZ = Integer.MIN_VALUE; - @Override public boolean setBlock(int x, int y, int z, int id, int data) { int cx = x >> 4; int cz = z >> 4; - if (cx != lastX || cz != lastZ) { - lastX = cx; - lastZ = cz; - long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL; - lastWrappedChunk = this.blocks.get(pair); - if (lastWrappedChunk == null) { - lastWrappedChunk = this.getFaweChunk(cx, cz); - lastWrappedChunk.setBlock(x & 15, y, z & 15, id, data); - FaweChunk previous = this.blocks.put(pair, lastWrappedChunk); - if (previous == null) { - chunks.add(lastWrappedChunk); - return true; - } - this.blocks.put(pair, previous); - lastWrappedChunk = previous; - } - } - lastWrappedChunk.setBlock(x & 15, y, z & 15, id, data); + FaweChunk chunk = map.getFaweChunk(cx, cz); + chunk.setBlock(x & 15, y, z & 15, id, data); return true; } @@ -165,24 +132,8 @@ public abstract class MappedFaweQueue extends FaweQueue { public boolean setBlock(int x, int y, int z, int id) { int cx = x >> 4; int cz = z >> 4; - if (cx != lastX || cz != lastZ) { - lastX = cx; - lastZ = cz; - long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL; - lastWrappedChunk = this.blocks.get(pair); - if (lastWrappedChunk == null) { - lastWrappedChunk = this.getFaweChunk(x >> 4, z >> 4); - lastWrappedChunk.setBlock(x & 15, y, z & 15, id); - FaweChunk previous = this.blocks.put(pair, lastWrappedChunk); - if (previous == null) { - chunks.add(lastWrappedChunk); - return true; - } - this.blocks.put(pair, previous); - lastWrappedChunk = previous; - } - } - lastWrappedChunk.setBlock(x & 15, y, z & 15, id); + FaweChunk chunk = map.getFaweChunk(cx, cz); + chunk.setBlock(x & 15, y, z & 15, id); return true; } @@ -193,24 +144,8 @@ public abstract class MappedFaweQueue extends FaweQueue { } int cx = x >> 4; int cz = z >> 4; - if (cx != lastX || cz != lastZ) { - lastX = cx; - lastZ = cz; - long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL; - lastWrappedChunk = this.blocks.get(pair); - if (lastWrappedChunk == null) { - lastWrappedChunk = this.getFaweChunk(x >> 4, z >> 4); - lastWrappedChunk.setTile(x & 15, y, z & 15, tag); - FaweChunk previous = this.blocks.put(pair, lastWrappedChunk); - if (previous == null) { - chunks.add(lastWrappedChunk); - return; - } - this.blocks.put(pair, previous); - lastWrappedChunk = previous; - } - } - lastWrappedChunk.setTile(x & 15, y, z & 15, tag); + FaweChunk chunk = map.getFaweChunk(cx, cz); + chunk.setTile(x & 15, y, z & 15, tag); } @Override @@ -220,24 +155,8 @@ public abstract class MappedFaweQueue extends FaweQueue { } int cx = x >> 4; int cz = z >> 4; - if (cx != lastX || cz != lastZ) { - lastX = cx; - lastZ = cz; - long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL; - lastWrappedChunk = this.blocks.get(pair); - if (lastWrappedChunk == null) { - lastWrappedChunk = this.getFaweChunk(x >> 4, z >> 4); - lastWrappedChunk.setEntity(tag); - FaweChunk previous = this.blocks.put(pair, lastWrappedChunk); - if (previous == null) { - chunks.add(lastWrappedChunk); - return; - } - this.blocks.put(pair, previous); - lastWrappedChunk = previous; - } - } - lastWrappedChunk.setEntity(tag); + FaweChunk chunk = map.getFaweChunk(cx, cz); + chunk.setEntity(tag); } @Override @@ -247,64 +166,22 @@ public abstract class MappedFaweQueue extends FaweQueue { } int cx = x >> 4; int cz = z >> 4; - if (cx != lastX || cz != lastZ) { - lastX = cx; - lastZ = cz; - long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL; - lastWrappedChunk = this.blocks.get(pair); - if (lastWrappedChunk == null) { - lastWrappedChunk = this.getFaweChunk(x >> 4, z >> 4); - lastWrappedChunk.removeEntity(uuid); - FaweChunk previous = this.blocks.put(pair, lastWrappedChunk); - if (previous == null) { - chunks.add(lastWrappedChunk); - return; - } - this.blocks.put(pair, previous); - lastWrappedChunk = previous; - } - } - lastWrappedChunk.removeEntity(uuid); + FaweChunk chunk = map.getFaweChunk(cx, cz); + chunk.removeEntity(uuid); } @Override public boolean setBiome(int x, int z, BaseBiome biome) { - long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL; - FaweChunk result = this.blocks.get(pair); - if (result == null) { - result = this.getFaweChunk(x >> 4, z >> 4); - FaweChunk previous = this.blocks.put(pair, result); - if (previous != null) { - this.blocks.put(pair, previous); - result = previous; - } else { - chunks.add(result); - } - } - result.setBiome(x & 15, z & 15, biome); + int cx = x >> 4; + int cz = z >> 4; + FaweChunk chunk = map.getFaweChunk(cx, cz); + chunk.setBiome(x & 15, z & 15, biome); return true; } @Override - public FaweChunk next() { - lastX = Integer.MIN_VALUE; - lastZ = Integer.MIN_VALUE; - try { - if (this.blocks.size() == 0) { - return null; - } - synchronized (blocks) { - FaweChunk chunk = chunks.poll(); - if (chunk != null) { - blocks.remove(chunk.longHash()); - this.execute(chunk); - return chunk; - } - } - } catch (Throwable e) { - MainUtil.handleError(e); - } - return null; + public boolean next() { + return map.next(); } public void runTasks() { @@ -324,7 +201,7 @@ public abstract class MappedFaweQueue extends FaweQueue { @Override public int size() { - int size = chunks.size(); + int size = map.size(); if (size == 0 && SetQueue.IMP.getStage(this) != SetQueue.QueueStage.INACTIVE) { runTasks(); } @@ -341,7 +218,7 @@ public abstract class MappedFaweQueue extends FaweQueue { } // Set blocks / entities / biome if (getProgressTask() != null) { - getProgressTask().run(ProgressType.QUEUE, chunks.size()); + getProgressTask().run(ProgressType.QUEUE, map.size()); getProgressTask().run(ProgressType.DISPATCH, ++dispatched); } if (getChangeTask() != null) { @@ -362,18 +239,13 @@ public abstract class MappedFaweQueue extends FaweQueue { @Override public void clear() { - this.blocks.clear(); - this.chunks.clear(); + map.clear(); runTasks(); } @Override public void setChunk(FaweChunk chunk) { - FaweChunk previous = this.blocks.put(chunk.longHash(), (FaweChunk) chunk); - if (previous != null) { - chunks.remove(previous); - } - chunks.add((FaweChunk) chunk); + map.add(chunk); } public int lastChunkX = Integer.MIN_VALUE; diff --git a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java index fbd18648..2cc9f33a 100644 --- a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java @@ -16,6 +16,10 @@ public abstract class NMSMappedFaweQueue ex super(world); } + public NMSMappedFaweQueue(String world, IFaweQueueMap map) { + super(world, map); + } + private NMSRelighter relighter; @Override @@ -87,12 +91,12 @@ public abstract class NMSMappedFaweQueue ex if ((y < 0) || (y > 255)) { return 1; } - final int i = FaweCache.CACHE_I[y][x][z]; + final int i = FaweCache.CACHE_I[y][z][x]; final char[] section = sections[i]; if (section == null) { return 0; } - final int j = FaweCache.CACHE_J[y][x][z]; + final int j = FaweCache.CACHE_J[y][z][x]; return section[j] >> 4; } diff --git a/core/src/main/java/com/boydti/fawe/jnbt/MCAChunk.java b/core/src/main/java/com/boydti/fawe/jnbt/MCAChunk.java deleted file mode 100644 index 315bf723..00000000 --- a/core/src/main/java/com/boydti/fawe/jnbt/MCAChunk.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.boydti.fawe.jnbt; - -import com.boydti.fawe.example.CharFaweChunk; -import com.boydti.fawe.object.FaweQueue; - -public class MCAChunk extends CharFaweChunk { - /** - * A FaweSections object represents a chunk and the blocks that you wish to change in it. - * - * @param parent - * @param x - * @param z - */ - public MCAChunk(FaweQueue parent, int x, int z) { - super(parent, x, z); - } - - @Override - public Void getNewChunk() { - return null; - } -} diff --git a/core/src/main/java/com/boydti/fawe/jnbt/MCAFile.java b/core/src/main/java/com/boydti/fawe/jnbt/MCAFile.java deleted file mode 100644 index eb263880..00000000 --- a/core/src/main/java/com/boydti/fawe/jnbt/MCAFile.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.boydti.fawe.jnbt; - -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.object.RunnableVal3; -import com.boydti.fawe.object.io.BufferedRandomAccessFile; -import com.sk89q.jnbt.NBTInputStream; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.lang.reflect.Field; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - -public class MCAFile { - private final File file; - private final BufferedRandomAccessFile raf; - public final byte[] locations; - private Field fieldBuf1; - private Field fieldBuf2; - private Field fieldBuf3; - - private byte[] buffer1 = new byte[Settings.HISTORY.BUFFER_SIZE]; - private byte[] buffer2 = new byte[Settings.HISTORY.BUFFER_SIZE]; - private byte[] buffer3 = new byte[720]; - - - public MCAFile(File file) throws Exception { - this.file = file; - if (!file.exists()) { - throw new FileNotFoundException(file.toString()); - } - this.locations = new byte[4096]; - this.raf = new BufferedRandomAccessFile(file, "rw", Settings.HISTORY.BUFFER_SIZE); - raf.read(locations); - fieldBuf1 = BufferedInputStream.class.getDeclaredField("buf"); - fieldBuf1.setAccessible(true); - fieldBuf2 = InflaterInputStream.class.getDeclaredField("buf"); - fieldBuf2.setAccessible(true); - fieldBuf3 = NBTInputStream.class.getDeclaredField("buf"); - fieldBuf3.setAccessible(true); - } - - - public MCAFile(File regionFolder, int mcrX, int mcrZ) throws Exception { - this(new File(regionFolder, "r." + mcrX + "." + mcrZ + ".mca")); - } - - /** - * @param onEach cx, cz, offset - */ - public void forEachChunk(RunnableVal3 onEach) { - int i = 0; - for (int z = 0; z < 32; z++) { - for (int x = 0; x < 32; x++, i += 4) { - int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))); - int size = locations[i + 3] & 0xFF; - if (size != 0) { - onEach.run(x, z, offset << 12); - } - } - } - } - - public int getOffset(int cx, int cz) { - int i = (cx << 2) + (cz << 7); - int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))); - int size = locations[i + 3] & 0xFF; - return offset << 12; - } - - - private NBTStreamer getChunkReader(int offset) throws Exception { - raf.seek(offset); - int size = raf.readInt(); - int compression = raf.readByte(); - byte[] data = new byte[size]; - raf.read(data); - ByteArrayInputStream bais = new ByteArrayInputStream(data); - InflaterInputStream iis = new InflaterInputStream(bais, new Inflater(), 1); - fieldBuf2.set(iis, buffer2); - BufferedInputStream bis = new BufferedInputStream(iis, 1); - fieldBuf1.set(bis, buffer1); - NBTInputStream nis = new NBTInputStream(bis); - fieldBuf3.set(nis, buffer3); - return new NBTStreamer(nis); - } - - public int countId(int offset, final int id) throws Exception { - try { - NBTStreamer streamer = getChunkReader(offset); - NBTStreamer.ByteReader reader = new NBTStreamer.ByteReader() { - public int countId = id; - public int count = 0; - @Override - public void run(int index, int byteValue) { - if (byteValue == countId) { - count++; - } - } - }; - streamer.addReader(".Level.Sections.#.Blocks.#", reader); - streamer.readFully(); - return reader.getClass().getField("count").getInt(reader); - } catch (Exception e) { - e.printStackTrace(); - } - return 0; - } - - public static void main(String[] args) throws Exception { - File folder = new File("../../mc/world/region"); - long start = System.nanoTime(); - final AtomicInteger count = new AtomicInteger(); - final int id = 1; - for (File file : folder.listFiles()) { -// { -// File file = new File(folder, "r.0.0.mca"); - System.out.println(file); - final MCAFile mca = new MCAFile(file); - mca.forEachChunk(new RunnableVal3() { - @Override - public void run(Integer cx, Integer cz, Integer offset) { - try { - count.addAndGet(mca.countId(offset, id)); - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - - } - long diff = System.nanoTime() - start; - System.out.println(diff / 1000000d); - - System.out.println("Count: " + count); - - // My results - // 496,772,342 stone - // 35,164 chunks - // 17.175 seconds - - - } -} diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java new file mode 100644 index 00000000..6488923b --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java @@ -0,0 +1,397 @@ +package com.boydti.fawe.jnbt.anvil; + +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.jnbt.NBTStreamer; +import com.boydti.fawe.object.BytePair; +import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.RunnableVal2; +import com.boydti.fawe.util.MainUtil; +import com.boydti.fawe.util.MathMan; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.worldedit.world.biome.BaseBiome; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public class MCAChunk extends FaweChunk { + +// ids: byte[16][4096] +// data: byte[16][2048] +// skylight: byte[16][2048] +// blocklight: byte[16][2048] +// entities: Map +// tiles: List +// biomes: byte[256] +// compressedSize: int +// modified: boolean +// deleted: boolean + + public byte[][] ids; + public byte[][] data; + public byte[][] skyLight; + public byte[][] blockLight; + public byte[] biomes; + public Map tiles = new HashMap<>(); + public Map entities = new HashMap<>(); + private long inhabitedTime; + private long lastUpdate; + private int[] heightMap; + + public int compressedSize; + private boolean modified; + private boolean deleted; + + public CompoundTag toTag() { + if (deleted) { + return null; + } + // TODO optimize this as it's slow + // e.g. by precalculating the length + HashMap level = new HashMap(); + level.put("Entities", new ListTag(CompoundTag.class, new ArrayList(entities.values()))); + level.put("TileEntities", new ListTag(CompoundTag.class, new ArrayList(tiles.values()))); + level.put("InhabitedTime", inhabitedTime); + level.put("LastUpdate", lastUpdate); + level.put("LightPopulated", (byte) 0); + level.put("TerrainPopulated", (byte) 1); + level.put("V", (byte) 1); + level.put("xPos", getX()); + level.put("zPos", getZ()); + if (biomes != null) { + level.put("Biomes", biomes); + } + level.put("HeightMap", heightMap); + ArrayList> sections = new ArrayList<>(); + for (int layer = 0; layer < ids.length; layer++) { + byte[] idLayer = ids[layer]; + if (idLayer == null) { + continue; + } + HashMap map = new HashMap(); + map.put("Y", (byte) layer); + map.put("BlockLight", blockLight[layer]); + map.put("SkyLight", skyLight[layer]); + map.put("Blocks", idLayer); + map.put("Data", data[layer]); + sections.add(map); + } + level.put("Sections", sections); + HashMap root = new HashMap<>(); + root.put("Level", level); + return FaweCache.asTag(root); + } + + public MCAChunk(MCAChunk parent, boolean shallow) { + super(parent.getParent(), parent.getX(), parent.getZ()); + if (shallow) { + this.ids = parent.ids; + this.data = parent.data; + this.skyLight = parent.skyLight; + this.blockLight = parent.blockLight; + this.biomes = parent.biomes; + this.tiles = parent.tiles; + this.entities = parent.entities; + this.inhabitedTime = parent.inhabitedTime; + this.lastUpdate = parent.lastUpdate; + this.heightMap = parent.heightMap; + this.compressedSize = parent.compressedSize; + this.modified = parent.modified; + this.deleted = parent.deleted; + } else { + this.ids = (byte[][]) MainUtil.copyNd(parent.ids); + this.data = (byte[][]) MainUtil.copyNd(parent.data); + this.skyLight = (byte[][]) MainUtil.copyNd(parent.skyLight); + this.blockLight = (byte[][]) MainUtil.copyNd(parent.blockLight); + this.biomes = parent.biomes.clone(); + this.tiles = new HashMap<>(parent.tiles); + this.entities = new HashMap<>(parent.entities); + this.inhabitedTime = parent.inhabitedTime; + this.lastUpdate = parent.lastUpdate; + this.heightMap = parent.heightMap.clone(); + this.compressedSize = parent.compressedSize; + this.modified = parent.modified; + this.deleted = parent.deleted; + } + } + + public MCAChunk(NBTInputStream nis, FaweQueue parent, int x, int z, int compressedSize) throws IOException { + super(parent, x, z); + ids = new byte[16][]; + data = new byte[16][]; + skyLight = new byte[16][]; + blockLight = new byte[16][]; + this.compressedSize = compressedSize; +// NamedTag tag = nis.readNamedTag(); + NBTStreamer streamer = new NBTStreamer(nis); + streamer.addReader(".Level.InhabitedTime", new RunnableVal2() { + @Override + public void run(Integer index, Long value) { + inhabitedTime = value; + } + }); + streamer.addReader(".Level.LastUpdate", new RunnableVal2() { + @Override + public void run(Integer index, Long value) { + lastUpdate = value; + } + }); + streamer.addReader(".Level.Sections.#", new RunnableVal2() { + @Override + public void run(Integer index, CompoundTag tag) { + int layer = tag.getByte("Y"); + ids[layer] = tag.getByteArray("Blocks"); + data[layer] = tag.getByteArray("Data"); + skyLight[layer] = tag.getByteArray("SkyLight"); + blockLight[layer] = tag.getByteArray("BlockLight"); + } + }); + streamer.addReader(".Level.Entities.#", new RunnableVal2() { + @Override + public void run(Integer index, CompoundTag tile) { + int x = tile.getInt("x") & 15; + int y = tile.getInt("y"); + int z = tile.getInt("z") & 15; + byte i = MathMan.pair16((byte) x, (byte) z); + byte j = (byte) y; + BytePair pair = new BytePair(i, j); + tiles.put(pair, tile); + } + }); + streamer.addReader(".Level.TileEntities.#", new RunnableVal2() { + @Override + public void run(Integer index, CompoundTag entityTag) { + if (entities == null) { + entities = new HashMap(); + } + long least = entityTag.getLong("UUIDLeast"); + long most = entityTag.getLong("UUIDMost"); + entities.put(new UUID(most, least), entityTag); + } + }); + streamer.addReader(".Level.Biomes", new RunnableVal2() { + @Override + public void run(Integer index, byte[] value) { + biomes = value; + } + }); + streamer.addReader(".Level.HeightMap", new RunnableVal2() { + @Override + public void run(Integer index, int[] value) { + heightMap = value; + } + }); + streamer.readFully(); + } + + public boolean isModified() { + return modified; + } + + @Override + public int getBitMask() { + int bitMask = 0; + for (int section = 0; section < ids.length; section++) { + if (ids[section] != null) { + bitMask += 1 << section; + } + } + return bitMask; + } + + @Override + public void setTile(int x, int y, int z, CompoundTag tile) { + modified = true; + byte i = MathMan.pair16((byte) x, (byte) z); + byte j = (byte) y; + BytePair pair = new BytePair(i, j); + tiles.put(pair, tile); + } + + @Override + public void setEntity(CompoundTag entityTag) { + modified = true; + long least = entityTag.getLong("UUIDLeast"); + long most = entityTag.getLong("UUIDMost"); + entities.put(new UUID(most, least), entityTag); + } + + @Override + public void setBiome(int x, int z, BaseBiome biome) { + modified = true; + biomes[x + (z << 4)] = (byte) biome.getId();; + } + + @Override + public Set getEntities() { + return new HashSet<>(entities.values()); + } + + @Override + public Map getTiles() { + return tiles == null ? new HashMap() : tiles; + } + + @Override + public CompoundTag getTile(int x, int y, int z) { + if (tiles == null || tiles.isEmpty()) { + return null; + } + byte i = MathMan.pair16((byte) x, (byte) z); + byte j = (byte) y; + BytePair pair = new BytePair(i, j); + return tiles.get(pair); + } + + public boolean doesSectionExist(int cy) { + return ids[cy] != null; + } + + @Override + public FaweChunk copy(boolean shallow) { + return new MCAChunk(this, shallow); + } + + @Override + public int getBlockCombinedId(int x, int y, int z) { + int layer = y >> 4; + byte[] idLayer = ids[layer]; + if (idLayer == null) { + return 0; + } + int j = FaweCache.CACHE_J[y][z & 15][x & 15]; + int id = idLayer[j]; + if (FaweCache.hasData(id)) { + byte[] dataLayer = data[layer]; + if (dataLayer != null) { + return (id << 4) + dataLayer[j]; + } + } + return id << 4; + } + + @Override + public Set getEntityRemoves() { + return new HashSet<>(); + } + + public void setSkyLight(int x, int y, int z, int value) { + modified = true; + int layer = y >> 4; + byte[] skyLayer = skyLight[layer]; + if (skyLayer == null) { + return; + } + int index = FaweCache.CACHE_J[y][z & 15][x & 15]; + setNibble(index, skyLayer, value); + } + + public void setBlockLight(int x, int y, int z, int value) { + modified = true; + int layer = y >> 4; + byte[] blockLayer = blockLight[layer]; + if (blockLayer == null) { + return; + } + int index = FaweCache.CACHE_J[y][z & 15][x & 15]; + setNibble(index, blockLayer, value); + } + + public int getSkyLight(int x, int y, int z) { + modified = true; + int layer = y >> 4; + byte[] skyLayer = skyLight[layer]; + if (skyLayer == null) { + return 0; + } + int index = FaweCache.CACHE_J[y][z & 15][x & 15]; + return getNibble(index, skyLayer); + } + + public int getBlockLight(int x, int y, int z) { + modified = true; + int layer = y >> 4; + byte[] blockLayer = blockLight[layer]; + if (blockLayer == null) { + return 0; + } + int index = FaweCache.CACHE_J[y][z & 15][x & 15]; + return getNibble(index, blockLayer); + } + + public void setFullbright() { + modified = true; + for (byte[] array : skyLight) { + if (array != null) { + Arrays.fill(array, (byte) 255); + } + } + } + + public void removeLight() { + for (int i = 0; i < skyLight.length; i++) { + byte[] array1 = skyLight[i]; + if (array1 == null) { + continue; + } + byte[] array2 = blockLight[i]; + Arrays.fill(array1, (byte) 0); + Arrays.fill(array2, (byte) 0); + } + } + + private int getNibble(int index, byte[] array) { + int indexShift = index >> 1; + if((index & 1) == 0) { + return array[index] & 15; + } else { + return array[index] >> 4 & 15; + } + } + + private void setNibble(int index, byte[] array, int value) { + int indexShift = index >> 1; + if((index & 1) == 0) { + array[indexShift] = (byte)(array[indexShift] & 240 | value & 15); + } else { + array[indexShift] = (byte)(array[indexShift] & 15 | (value & 15) << 4); + } + } + + @Override + public void setBlock(int x, int y, int z, int id, int data) { + modified = true; + int layer = y >> 4; + byte[] idsLayer = ids[layer]; + if (idsLayer == null) { + return; + } + int j = FaweCache.CACHE_J[y][z & 15][x & 15]; + idsLayer[j] = (byte) id; + byte[] dataLayer = this.data[layer]; + dataLayer[j] = (byte) data; + } + + @Override + public void removeEntity(UUID uuid) { + modified = true; + entities.remove(uuid); + } + + @Override + public Void getChunk() { + throw new UnsupportedOperationException("Not applicable for this"); + } + + @Override + public char[][] getCombinedIdArrays() { + throw new UnsupportedOperationException("Not applicable for this"); + } +} diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java new file mode 100644 index 00000000..5ff8279c --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java @@ -0,0 +1,347 @@ +package com.boydti.fawe.jnbt.anvil; + +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.jnbt.NBTStreamer; +import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.RunnableVal; +import com.boydti.fawe.object.RunnableVal4; +import com.boydti.fawe.object.io.BufferedRandomAccessFile; +import com.boydti.fawe.util.MathMan; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NBTOutputStream; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; + +/** + * Chunk format: http://minecraft.gamepedia.com/Chunk_format#Entity_format + * e.g.: `.Level.Entities.#` (Starts with a . as the root tag is unnamed) + */ +public class MCAFile { + private final File file; + private final BufferedRandomAccessFile raf; + private final byte[] locations; + private final FaweQueue queue; + private Field fieldBuf1; + private Field fieldBuf2; + private Field fieldBuf3; + private Field fieldBuf4; + private Field fieldBuf5; + private Field fieldBuf6; + + private byte[] buffer1 = new byte[Settings.HISTORY.BUFFER_SIZE]; + private byte[] buffer2 = new byte[Settings.HISTORY.BUFFER_SIZE]; + private byte[] buffer3 = new byte[720]; + + private Map chunks = new HashMap<>(); + + public MCAFile(FaweQueue parent, File file) throws Exception { + this.queue = parent; + this.file = file; + if (!file.exists()) { + throw new FileNotFoundException(file.toString()); + } + this.locations = new byte[4096]; + this.raf = new BufferedRandomAccessFile(file, "rw", Settings.HISTORY.BUFFER_SIZE); + raf.read(locations); + fieldBuf1 = BufferedInputStream.class.getDeclaredField("buf"); + fieldBuf1.setAccessible(true); + fieldBuf2 = InflaterInputStream.class.getDeclaredField("buf"); + fieldBuf2.setAccessible(true); + fieldBuf3 = NBTInputStream.class.getDeclaredField("buf"); + fieldBuf3.setAccessible(true); + fieldBuf4 = ByteArrayOutputStream.class.getDeclaredField("buf"); + fieldBuf4.setAccessible(true); + fieldBuf5 = DeflaterOutputStream.class.getDeclaredField("buf"); + fieldBuf5.setAccessible(true); + fieldBuf6 = BufferedOutputStream.class.getDeclaredField("buf"); + fieldBuf6.setAccessible(true); + } + + public MCAFile(FaweQueue parent, int mcrX, int mcrZ) throws Exception { + this(parent, new File(parent.getSaveFolder(), "r." + mcrX + "." + mcrZ + ".mca")); + } + + public MCAChunk getCachedChunk(int cx, int cz) { + int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31)); + return chunks.get(pair); + } + + public MCAChunk getChunk(int cx, int cz) throws IOException { + MCAChunk cached = getCachedChunk(cx, cz); + if (cached != null) { + return cached; + } else { + return readChunk(cx, cz); + } + } + + public MCAChunk readChunk(int cx, int cz) throws IOException { + int i = (cx << 2) + (cz << 7); + int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))) << 12; + int size = (locations[i + 3] & 0xFF) << 12; + NBTInputStream nis = getChunkIS(offset); + MCAChunk chunk = new MCAChunk(nis, queue, cx, cz, size); + int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31)); + chunks.put(pair, chunk); + return chunk; + } + + /** + * @param onEach cx, cz, offset, size + */ + public void forEachChunk(RunnableVal4 onEach) { + int i = 0; + for (int z = 0; z < 32; z++) { + for (int x = 0; x < 32; x++, i += 4) { + int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))); + int size = locations[i + 3] & 0xFF; + if (size != 0) { + onEach.run(x, z, offset << 12, size << 12); + } + } + } + } + + public int getOffset(int cx, int cz) { + int i = (cx << 2) + (cz << 7); + int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))); + return offset << 12; + } + + public int getSize(int cx, int cz) { + int i = (cx << 2) + (cz << 7); + return (locations[i + 3] & 0xFF) << 12; + } + + public List getChunks() { + final List values = new ArrayList<>(chunks.size()); + for (int i = 0; i < locations.length; i+=4) { + int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i+ 2] & 0xFF))); + values.add(offset); + } + return values; + } + + private byte[] getChunkCompressedBytes(int offset) throws IOException{ + raf.seek(offset); + int size = raf.readInt(); + int compression = raf.readByte(); + byte[] data = new byte[size]; + raf.read(data); + return data; + } + + private void writeSafe(int offset, byte[] data) throws IOException { + int len = data.length + 5; + raf.seek(offset); + if (raf.length() - offset < len) { + raf.setLength(offset + len); + } + raf.writeInt(data.length); + raf.writeByte(2); + raf.write(data); + } + + private NBTInputStream getChunkIS(int offset) throws IOException { + try { + byte[] data = getChunkCompressedBytes(offset); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + InflaterInputStream iis = new InflaterInputStream(bais, new Inflater(), 1); + fieldBuf2.set(iis, buffer2); + BufferedInputStream bis = new BufferedInputStream(iis, 1); + fieldBuf1.set(bis, buffer1); + NBTInputStream nis = new NBTInputStream(bis); + fieldBuf3.set(nis, buffer3); + return nis; + } catch (IllegalAccessException unlikely) { + unlikely.printStackTrace(); + return null; + } + } + + public void streamChunk(int cx, int cz, RunnableVal addReaders) throws IOException { + streamChunk(getOffset(cx, cz), addReaders); + } + + public void streamChunk(int offset, RunnableVal addReaders) throws IOException { + NBTInputStream is = getChunkIS(offset); + NBTStreamer ns = new NBTStreamer(is); + addReaders.run(ns); + ns.readFully(); + } + + /** + * @param onEach chunk + */ + public void forEachCachedChunk(RunnableVal onEach) { + for (Map.Entry entry : chunks.entrySet()) { + onEach.run(entry.getValue()); + } + } + + public List getCachedChunks() { + return new ArrayList<>(chunks.values()); + } + + private NBTStreamer getChunkReader(int offset) throws Exception { + return new NBTStreamer(getChunkIS(offset)); + } + + public void uncache(int cx, int cz) { + int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31)); + chunks.remove(pair); + } + + private byte[] toBytes(MCAChunk chunk) throws Exception { + CompoundTag tag = chunk.toTag(); + if (tag == null) { + return null; + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(0); + fieldBuf4.set(baos, buffer3); + DeflaterOutputStream deflater = new DeflaterOutputStream(baos, new Deflater(9), 1, true); + fieldBuf5.set(deflater, buffer2); + BufferedOutputStream bos = new BufferedOutputStream(deflater, 1); + fieldBuf6.set(bos, buffer1); + NBTOutputStream nos = new NBTOutputStream(bos); + nos.writeNamedTag("", tag); + bos.flush(); + byte[] result = baos.toByteArray(); + return result; + } + + private byte[] getChunkBytes(int cx, int cz) throws Exception{ + MCAChunk mca = getCachedChunk(cx, cz); + if (mca == null) { + int offset = getOffset(cx, cz); + if (offset == 0) { + return null; + } + return getChunkCompressedBytes(offset); + } + return toBytes(mca); + } + + private void writeHeader(int cx, int cz, int offsetMedium, int sizeByte) throws IOException { + int i = (cx << 2) + (cz << 7); + raf.seek(i); + raf.write((offsetMedium >>> 16) & 0xFF); + raf.write((offsetMedium >>> 8) & 0xFF); + raf.write((offsetMedium >>> 0) & 0xFF); + raf.write(sizeByte); + } + + public void flush() { + final HashMap offsetMap = new HashMap<>(); // Offset -> + + forEachChunk(new RunnableVal4() { + @Override + public void run(Integer cx, Integer cz, Integer offset, Integer size) { + short pair1 = MathMan.pairByte((byte) (cx & 31), (byte) (cz & 31)); + short pair2 = (short) (size >> 12); + offsetMap.put(offset, MathMan.pair(pair1, pair2)); + } + }); + + HashMap relocate = new HashMap(); + int start = 8192; + int end = 8192; + int nextOffset = 8192; + try { + for (int count = 0; count < offsetMap.size(); count++) { + int loc = offsetMap.get(nextOffset); + int offset = nextOffset; + short cxz = MathMan.unpairX(loc); + int cx = MathMan.unpairShortX(cxz); + int cz = MathMan.unpairShortY(cxz); + int size = MathMan.unpairY(loc) << 12; + nextOffset += size; + end += size; + int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31)); + byte[] newBytes = relocate.get(pair); + if (newBytes == null) { + if (offset == start) { + MCAChunk cached = getCachedChunk(cx, cz); + if (cached == null || !cached.isModified()) { + start += size; + continue; + } else { + newBytes = toBytes(cached); + } + } else { + newBytes = getChunkBytes(cx, cz); + } + } + if (newBytes == null) { + System.out.println("Deleting: " + cx + "," + cz); + // Don't write + continue; + } + int len = newBytes.length + 5; + int oldSize = (size + 4095) >> 12; + int newSize = (len + 4095) >> 12; + int nextOffset2 = nextOffset; + while (start + len > end) { + int nextLoc = offsetMap.get(nextOffset2); + short nextCXZ = MathMan.unpairX(nextLoc); + int nextCX = MathMan.unpairShortX(nextCXZ); + int nextCZ = MathMan.unpairShortY(nextCXZ); + if (getCachedChunk(nextCX, nextCZ) == null) { + byte[] nextBytes = getChunkCompressedBytes(nextOffset2); + relocate.put(pair, nextBytes); + } + System.out.println("Relocating " + nextCX + "," + nextCZ); + int nextSize = MathMan.unpairY(nextLoc) << 12; + end += nextSize; + nextOffset2 += nextSize; + } + System.out.println("Writing: " + cx + "," + cz); + writeSafe(start, newBytes); + if (offset != start || end != start + size) { + System.out.println("Header: " + cx + "," + cz + " | " + offset + "," + start + " | " + end + "," + (start + size) + " | " + size + " | " + start); + writeHeader(cx, cz, offset >> 12, newSize); + } + start += newSize << 12; + } + raf.flush(); + } catch (Throwable e) { + e.printStackTrace(); + } + // TODO write header + } + + public static void main(String[] args) throws Exception { + // io benchmark + File folder = new File("../../mc/world/region"); + long start = System.nanoTime(); + final AtomicInteger count = new AtomicInteger(); + final int id = 1; +// for (File file : folder.listFiles()) { + { // Testing read/write + File file = new File(folder, "r.-2.-3.mca"); + final MCAFile mca = new MCAFile(null, file); + MCAChunk chunk = mca.getChunk(29, 30); + System.out.println("Block ID: " + chunk.getBlockCombinedId(0, 0, 0)); + chunk.setBlock(0,0,0, 5); + mca.flush(); + } + long diff = System.nanoTime() - start; + System.out.println(diff / 1000000d); // Time diff + } +} diff --git a/core/src/main/java/com/boydti/fawe/jnbt/MCAQueue.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java similarity index 56% rename from core/src/main/java/com/boydti/fawe/jnbt/MCAQueue.java rename to core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java index 26349997..4c2cfde3 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/MCAQueue.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java @@ -1,4 +1,4 @@ -package com.boydti.fawe.jnbt; +package com.boydti.fawe.jnbt.anvil; import com.boydti.fawe.example.CharFaweChunk; import com.boydti.fawe.example.NMSMappedFaweQueue; @@ -12,127 +12,139 @@ import java.util.Map; import java.util.Set; import java.util.UUID; -public class MCAQueue extends NMSMappedFaweQueue { +public class MCAQueue extends NMSMappedFaweQueue { private final FaweQueue parent; public MCAQueue(FaweQueue parent) { - super(parent.getWorldName()); + super(parent.getWorldName(), new MCAQueueMap()); this.parent = parent; } - @Override - public void setFullbright(MCAChunk sections) { - - } - - @Override - public boolean removeLighting(MCAChunk sections, RelightMode mode, boolean hasSky) { - return false; - } - @Override public void relight(int x, int y, int z) { - + throw new UnsupportedOperationException("Not supported"); } @Override public void relightBlock(int x, int y, int z) { - + throw new UnsupportedOperationException("Not supported"); } @Override public void relightSky(int x, int y, int z) { - - } - - @Override - public void setSkyLight(char[] chars, int x, int y, int z, int value) { - - } - - @Override - public void setBlockLight(char[] chars, int x, int y, int z, int value) { - - } - - @Override - public void refreshChunk(FaweChunk fs) { - - } - - @Override - public CharFaweChunk getPrevious(CharFaweChunk fs, MCAChunk sections, Map tiles, Collection[] entities, Set createdEntities, boolean all) throws Exception { - return null; - } - - @Override - public CompoundTag getTileEntity(MCAChunk mcaChunk, int x, int y, int z) { - return null; - } - - @Override - public MCAChunk getChunk(FaweQueue faweQueue, int x, int z) { - return null; - } - - @Override - public FaweQueue getImpWorld() { - return null; - } - - @Override - public boolean isChunkLoaded(FaweQueue faweQueue, int x, int z) { - return false; + throw new UnsupportedOperationException("Not supported"); } @Override public boolean regenerateChunk(FaweQueue faweQueue, int x, int z) { - return false; + throw new UnsupportedOperationException("Not supported"); } @Override public boolean setComponents(FaweChunk fc, RunnableVal changeTask) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public CharFaweChunk getPrevious(CharFaweChunk fs, MCAChunk sections, Map tiles, Collection[] entities, Set createdEntities, boolean all) throws Exception { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public MCAChunk getChunk(FaweQueue faweQueue, int x, int z) { + return (MCAChunk) getFaweChunk(x, z); + } + + @Override + public FaweQueue getImpWorld() { + return parent; + } + + @Override + public void setFullbright(MCAChunk sections) { + sections.setFullbright(); + } + + @Override + public boolean removeLighting(MCAChunk sections, RelightMode mode, boolean hasSky) { + if (mode != RelightMode.NONE) { + sections.removeLight(); + return true; + } return false; } + @Override + public void setSkyLight(MCAChunk chars, int x, int y, int z, int value) { + chars.setSkyLight(x, y, z, value); + } + + @Override + public void setBlockLight(MCAChunk chars, int x, int y, int z, int value) { + chars.setBlockLight(x, y, z, value); + } + + @Override + public void refreshChunk(FaweChunk fs) { + // Nothing + } + + @Override + public CompoundTag getTileEntity(MCAChunk mcaChunk, int x, int y, int z) { + return mcaChunk.getTile(x, y, z); + } + + @Override + public boolean isChunkLoaded(FaweQueue faweQueue, int x, int z) { + return true; + } + @Override public FaweChunk getFaweChunk(int x, int z) { - return null; + return getFaweQueueMap().getFaweChunk(x, z); } @Override public File getSaveFolder() { - return null; + return parent.getSaveFolder(); } @Override public boolean hasSky() { - return false; + return parent.hasSky(); } @Override public boolean loadChunk(FaweQueue faweQueue, int x, int z, boolean generate) { - return false; + return true; } @Override public MCAChunk getCachedSections(FaweQueue faweQueue, int cx, int cz) { + return (MCAChunk) getFaweQueueMap().getFaweChunk(cx, cz); + } + + @Override + public MCAChunk getCachedSection(MCAChunk mcaChunk, int cy) { + if (mcaChunk.doesSectionExist(cy)) { + return mcaChunk; + } return null; } @Override - public int getCombinedId4Data(char[] chars, int x, int y, int z) { - return 0; + public int getCombinedId4Data(MCAChunk chars, int x, int y, int z) { + return chars.getBlockCombinedId(x, y, z); } @Override - public int getSkyLight(char[] sections, int x, int y, int z) { - return 0; + public int getSkyLight(MCAChunk sections, int x, int y, int z) { + return sections.getSkyLight(x, y, z); } @Override - public int getEmmittedLight(char[] sections, int x, int y, int z) { - return 0; + public int getEmmittedLight(MCAChunk sections, int x, int y, int z) { + return sections.getBlockLight(x, y, z); } } diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueueMap.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueueMap.java new file mode 100644 index 00000000..33c80940 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueueMap.java @@ -0,0 +1,45 @@ +package com.boydti.fawe.jnbt.anvil; + +import com.boydti.fawe.example.IFaweQueueMap; +import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.object.RunnableVal; +import java.util.Collection; + +public class MCAQueueMap implements IFaweQueueMap { + @Override + public Collection getFaweCunks() { + return null; + } + + @Override + public void forEachChunk(RunnableVal onEach) { + + } + + @Override + public FaweChunk getFaweChunk(int cx, int cz) { + return null; + } + + @Override + public void add(FaweChunk chunk) { + + } + + + + @Override + public void clear() { + + } + + @Override + public int size() { + return 0; + } + + @Override + public boolean next() { + return false; + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/FaweChunk.java b/core/src/main/java/com/boydti/fawe/object/FaweChunk.java index 58cae2fb..ca705dad 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweChunk.java @@ -109,7 +109,7 @@ public abstract class FaweChunk { public int getBlockCombinedId(int x, int y, int z) { char[][] arrays = getCombinedIdArrays(); char[] array = arrays[y >> 4]; - return array != null ? (array[FaweCache.CACHE_J[y][x][z]]) : 0; + return array != null ? (array[FaweCache.CACHE_J[y][z][x]]) : 0; } /** diff --git a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java index 18512fc0..2bb64132 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java @@ -132,11 +132,11 @@ public abstract class FaweQueue { public abstract boolean setBiome(final int x, final int z, final BaseBiome biome); - public abstract FaweChunk getFaweChunk(int x, int z); + public abstract FaweChunk getFaweChunk(int x, int z); public abstract Collection getFaweChunks(); - public abstract void setChunk(final FaweChunk chunk); + public abstract void setChunk(final FaweChunk chunk); public abstract File getSaveFolder(); @@ -219,7 +219,7 @@ public abstract class FaweQueue { * Gets the FaweChunk and sets the requested blocks * @return */ - public abstract FaweChunk next(); + public abstract boolean next(); public void saveMemory() { MainUtil.sendAdmin(BBC.OOM.s()); diff --git a/core/src/main/java/com/boydti/fawe/object/RunnableVal4.java b/core/src/main/java/com/boydti/fawe/object/RunnableVal4.java new file mode 100644 index 00000000..d744fcf1 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/RunnableVal4.java @@ -0,0 +1,24 @@ +package com.boydti.fawe.object; + +public abstract class RunnableVal4 implements Runnable { + public T value1; + public U value2; + public V value3; + public W value4; + + public RunnableVal4() {} + + public RunnableVal4(T value1, U value2, V value3, W value4) { + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + this.value4 = value4; + } + + @Override + public void run() { + run(value1, value2, value3, value4); + } + + public abstract void run(T value1, U value2, V value3, W value4); +} diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java index 19a2960d..738c1898 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java @@ -202,12 +202,12 @@ public abstract class FaweChangeSet implements ChangeSet { for (int y = 0; y < 16; y++) { short[][] i1 = FaweCache.CACHE_J[y]; int yy = y + startY; - for (int x = 0; x < 16; x++) { - int xx = x + bx; - short[] i2 = i1[x]; - for (int z = 0; z < 16; z++) { - int zz = z + bz; - int index = i2[z]; + for (int z = 0; z < 16; z++) { + int zz = z + bz; + short[] i2 = i1[z]; + for (int x = 0; x < 16; x++) { + int xx = x + bx; + int index = i2[x]; int combinedIdCurrent = currentLayer[index]; switch (combinedIdCurrent) { case 0: diff --git a/core/src/main/java/com/boydti/fawe/object/extent/MCAExtent.java b/core/src/main/java/com/boydti/fawe/object/extent/MCAExtent.java index 32c74703..fd1b5e6a 100644 --- a/core/src/main/java/com/boydti/fawe/object/extent/MCAExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/extent/MCAExtent.java @@ -1,6 +1,6 @@ package com.boydti.fawe.object.extent; -import com.boydti.fawe.jnbt.MCAFile; +import com.boydti.fawe.jnbt.anvil.MCAFile; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.Vector; diff --git a/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java b/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java index 500df831..9cb50fcb 100644 --- a/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java @@ -103,6 +103,9 @@ public class ProcessedWEExtent extends FaweRegionExtent { return super.setBiome(position, biome); } else if (!limit.MAX_FAILS()) { WEManager.IMP.cancelEditSafe(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS); + return false; + } else { + return false; } } diff --git a/core/src/main/java/com/boydti/fawe/regions/general/plot/FaweLocalBlockQueue.java b/core/src/main/java/com/boydti/fawe/regions/general/plot/FaweLocalBlockQueue.java index 6d24251e..abfaa449 100644 --- a/core/src/main/java/com/boydti/fawe/regions/general/plot/FaweLocalBlockQueue.java +++ b/core/src/main/java/com/boydti/fawe/regions/general/plot/FaweLocalBlockQueue.java @@ -26,7 +26,7 @@ public class FaweLocalBlockQueue extends LocalBlockQueue { @Override public boolean next() { - return IMP.next() != null; + return IMP.next(); } @Override diff --git a/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java b/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java index 2646c88c..ca02d8f7 100644 --- a/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java @@ -130,7 +130,7 @@ public class DelegateFaweQueue extends FaweQueue { } @Override - public void setChunk(FaweChunk chunk) { + public void setChunk(FaweChunk chunk) { parent.setChunk(chunk); } @@ -165,7 +165,7 @@ public class DelegateFaweQueue extends FaweQueue { } @Override - public FaweChunk next() { + public boolean next() { return parent.next(); } diff --git a/core/src/main/java/com/boydti/fawe/util/SetQueue.java b/core/src/main/java/com/boydti/fawe/util/SetQueue.java index ea69b679..c7e711a5 100644 --- a/core/src/main/java/com/boydti/fawe/util/SetQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/SetQueue.java @@ -2,7 +2,6 @@ package com.boydti.fawe.util; import com.boydti.fawe.Fawe; import com.boydti.fawe.config.Settings; -import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal2; import java.util.ArrayList; @@ -42,8 +41,8 @@ public class SetQueue { @Override public void run(Long free, FaweQueue queue) { do { - final FaweChunk current = queue.next(); - if (current == null) { + final boolean current = queue.next(); + if (current == false) { lastSuccess = last; if (inactiveQueues.size() == 0 && activeQueues.size() == 0) { runEmptyTasks(); @@ -269,12 +268,12 @@ public class SetQueue { return null; } - public FaweChunk next() { + public boolean next() { while (activeQueues.size() > 0) { FaweQueue queue = activeQueues.poll(); if (queue != null) { - final FaweChunk set = queue.next(); - if (set != null) { + final boolean set = queue.next(); + if (set) { activeQueues.add(queue); return set; } @@ -290,8 +289,8 @@ public class SetQueue { long diff = now - lastSuccess; if (diff > Settings.QUEUE.MAX_WAIT_MS) { for (FaweQueue queue : tmp) { - FaweChunk result = queue.next(); - if (result != null) { + boolean result = queue.next(); + if (result) { return result; } } @@ -299,7 +298,7 @@ public class SetQueue { // These edits never finished inactiveQueues.clear(); } - return null; + return false; } } if (Settings.QUEUE.TARGET_SIZE != -1) { @@ -309,19 +308,19 @@ public class SetQueue { } if (total > Settings.QUEUE.TARGET_SIZE) { for (FaweQueue queue : tmp) { - FaweChunk result = queue.next(); - if (result != null) { + boolean result = queue.next(); + if (result) { return result; } } } } } - return null; + return false; } public boolean forceChunkSet() { - return next() != null; + return next(); } /** diff --git a/core/src/main/java/com/sk89q/worldedit/LocalSession.java b/core/src/main/java/com/sk89q/worldedit/LocalSession.java index cde437e1..1fb6171b 100644 --- a/core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -315,7 +315,7 @@ public class LocalSession { File file = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.PATHS.HISTORY + File.separator + Fawe.imp().getWorldName(world) + File.separator + uuid + File.separator + "index"); if (getHistoryNegativeIndex() != 0) { try { - if (file.exists()) { + if (!file.exists()) { file.getParentFile().mkdirs(); file.createNewFile(); } diff --git a/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeChunk_All.java b/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeChunk_All.java index 82f591af..e4a28530 100644 --- a/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeChunk_All.java +++ b/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeChunk_All.java @@ -101,7 +101,7 @@ public class ForgeChunk_All extends CharFaweChunk { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - char combinedId = blocks[FaweCache.CACHE_J[y][x][z]]; + char combinedId = blocks[FaweCache.CACHE_J[y][z][x]]; if (combinedId > 1) { palette.set(x, y, z, Block.getBlockById(combinedId >> 4).getStateFromMeta(combinedId & 0xF)); } diff --git a/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index 0e953a5c..439dfcf2 100644 --- a/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge110/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -269,12 +269,12 @@ public class ForgeQueue_All extends NMSMappedFaweQueue 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -372,12 +372,12 @@ public class ForgeQueue_All extends NMSMappedFaweQueue { @Override public void setBlock(int x, int y, int z, int id, int data) { - int i = FaweCache.CACHE_I[y][x][z]; - int j = FaweCache.CACHE_J[y][x][z]; + int i = FaweCache.CACHE_I[y][z][x]; + int j = FaweCache.CACHE_J[y][z][x]; byte[] vs = this.byteIds[i]; char[] vs2 = this.ids[i]; if (vs2 == null) { diff --git a/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index edcd96a4..5e4c0318 100644 --- a/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -122,7 +122,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -344,12 +344,12 @@ public class ForgeQueue_All extends NMSMappedFaweQueue 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -321,12 +321,12 @@ public class ForgeQueue_All extends NMSMappedFaweQueue 255) { return 1; } - int i = FaweCache.CACHE_I[y][x][z]; + int i = FaweCache.CACHE_I[y][z][x]; ExtendedBlockStorage section = sections[i]; if (section == null) { return 0; } char[] array = section.getData(); - int j = FaweCache.CACHE_J[y][x][z]; + int j = FaweCache.CACHE_J[y][z][x]; return array[j] >> 4; } @@ -627,7 +627,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - char combinedId = blocks[FaweCache.CACHE_J[y][x][z]]; + char combinedId = blocks[FaweCache.CACHE_J[y][z][x]]; if (combinedId > 1) { palette.set(x, y, z, Block.getBlockById(combinedId >> 4).getStateFromMeta(combinedId & 0xF)); } diff --git a/forge194/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge194/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index 88107763..3fe4a384 100644 --- a/forge194/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge194/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -269,12 +269,12 @@ public class ForgeQueue_All extends NMSMappedFaweQueue 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -372,12 +372,12 @@ public class ForgeQueue_All extends NMSMappedFaweQueue 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) { + if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][z][x]] != 0) { nmsWorld.removeEntity(entity); } } @@ -379,12 +379,12 @@ public class SpongeQueue_1_8 extends NMSMappedFaweQueue 255) { return 1; } - int i = FaweCache.CACHE_I[y][x][z]; + int i = FaweCache.CACHE_I[y][z][x]; ExtendedBlockStorage section = sections[i]; if (section == null) { return 0; } char[] array = section.getData(); - int j = FaweCache.CACHE_J[y][x][z]; + int j = FaweCache.CACHE_J[y][z][x]; return array[j] >> 4; } @@ -673,7 +673,7 @@ public class SpongeQueue_1_8 extends NMSMappedFaweQueue 255) { return 1; } - int i = FaweCache.CACHE_I[y][x][z]; + int i = FaweCache.CACHE_I[y][z][x]; ExtendedBlockStorage section = sections[i]; if (section == null) { return 0; } char[] array = section.getData(); - int j = FaweCache.CACHE_J[y][x][z]; + int j = FaweCache.CACHE_J[y][z][x]; return array[j] >> 4; } @@ -453,6 +453,6 @@ public class SpongeQueue_ALL extends NMSMappedFaweQueue