From ebc7ba43e6fc46ec4d04571540db137b1af18b6e Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 29 Jan 2017 09:25:53 +1100 Subject: [PATCH] Various Fix biome change not sending packet Add optimized biome get and set (AsyncWorld, EditSession etc.) Add undo for biome changes Fix tile entities for slow (non NMS) bukkit queue Translate some stuff Fix some concurrency issues with autoqueue cuboid region geChunks() now has fixed memory cost (applies to commands e.g. //listchunks) Fix some undo issues --- build.gradle | 3 +- bukkit/build.gradle | 1 + .../com/boydti/fawe/bukkit/BukkitTaskMan.java | 2 - .../fawe/bukkit/v0/BukkitChunk_All.java | 50 +- .../boydti/fawe/bukkit/v0/BukkitQueue_0.java | 14 - .../fawe/bukkit/v0/BukkitQueue_All.java | 123 ++-- .../boydti/fawe/bukkit/v0/ChunkListener.java | 31 +- .../fawe/bukkit/v1_10/BukkitChunk_1_10.java | 18 +- .../fawe/bukkit/v1_10/BukkitQueue_1_10.java | 68 +- .../fawe/bukkit/v1_11/BukkitChunk_1_11.java | 98 ++- .../bukkit/v1_11/BukkitChunk_1_11_Copy.java | 18 + .../fawe/bukkit/v1_11/BukkitQueue_1_11.java | 91 ++- .../fawe/bukkit/v1_7/BukkitChunk_1_7.java | 18 +- .../fawe/bukkit/v1_7/BukkitQueue17.java | 98 ++- .../fawe/bukkit/v1_8/BukkitChunk_1_8.java | 18 +- .../fawe/bukkit/v1_8/BukkitQueue18R3.java | 96 ++- .../fawe/bukkit/v1_9/BukkitChunk_1_9.java | 38 +- .../fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java | 68 +- .../fawe/bukkit/wrapper/AsyncWorld.java | 2 +- core/build.gradle | 1 + core/src/main/java/com/boydti/fawe/Fawe.java | 13 +- .../main/java/com/boydti/fawe/FaweCache.java | 18 + .../main/java/com/boydti/fawe/config/BBC.java | 31 +- .../java/com/boydti/fawe/config/Config.java | 7 +- .../java/com/boydti/fawe/config/Settings.java | 30 +- .../boydti/fawe/example/CharFaweChunk.java | 16 +- .../fawe/example/DefaultFaweQueueMap.java | 120 ++-- .../boydti/fawe/example/MappedFaweQueue.java | 353 +++++---- .../fawe/example/NMSMappedFaweQueue.java | 75 +- .../com/boydti/fawe/example/NMSRelighter.java | 38 +- .../boydti/fawe/example/NullFaweChunk.java | 11 + .../boydti/fawe/example/WeakFaweQueueMap.java | 152 ++-- .../com/boydti/fawe/jnbt/anvil/MCAChunk.java | 10 +- .../com/boydti/fawe/jnbt/anvil/MCAQueue.java | 41 +- .../fawe/object/ChangeSetFaweQueue.java | 10 +- .../com/boydti/fawe/object/FaweChunk.java | 8 +- .../com/boydti/fawe/object/FaweQueue.java | 4 +- .../com/boydti/fawe/object/HistoryExtent.java | 13 + .../com/boydti/fawe/object/NullChangeSet.java | 6 + .../object/brush/DoubleActionBrushTool.java | 5 +- .../boydti/fawe/object/brush/ErodeBrush.java | 3 +- .../boydti/fawe/object/brush/HeightBrush.java | 4 +- .../object/change/MutableBiomeChange.java | 36 + .../changeset/AbstractDelegateChangeSet.java | 6 + .../changeset/CPUOptimizedChangeSet.java | 6 + .../object/changeset/DiskStorageHistory.java | 49 +- .../fawe/object/changeset/FaweChangeSet.java | 120 ++-- .../object/changeset/FaweStreamChangeSet.java | 204 ++++-- .../changeset/MemoryOptimizedHistory.java | 33 +- .../object/extent/FastWorldEditExtent.java | 6 +- .../fawe/object/regions/FuzzyRegion.java | 4 +- .../fawe/regions/general/plot/PlotTrim.java | 2 +- .../boydti/fawe/util/DelegateFaweQueue.java | 142 +++- .../com/boydti/fawe/util/WESubscriber.java | 11 - .../java/com/sk89q/worldedit/EditSession.java | 24 +- .../java/com/sk89q/worldedit/Vector2D.java | 670 ++++++++++++++++++ .../worldedit/command/BiomeCommands.java | 18 +- .../worldedit/command/BrushCommands.java | 2 +- .../worldedit/command/ClipboardCommands.java | 29 +- .../worldedit/command/GeneralCommands.java | 43 +- .../worldedit/command/GenerationCommands.java | 14 +- .../worldedit/command/HistoryCommands.java | 4 +- .../worldedit/command/NavigationCommands.java | 2 +- .../worldedit/command/SelectionCommands.java | 2 +- .../worldedit/command/SnapshotCommands.java | 17 +- .../command/SnapshotUtilCommands.java | 2 +- .../command/SuperPickaxeCommands.java | 10 +- .../sk89q/worldedit/command/ToolCommands.java | 2 +- .../worldedit/command/UtilityCommands.java | 4 +- .../worldedit/command/WorldEditCommands.java | 5 +- .../worldedit/command/tool/BrushTool.java | 5 +- .../command/tool/LongRangeBuildTool.java | 3 +- .../extension/factory/DefaultBlockParser.java | 2 +- .../extension/factory/DefaultMaskParser.java | 8 +- .../extension/platform/PlatformManager.java | 2 +- .../sk89q/worldedit/regions/CuboidRegion.java | 58 +- forge110/build.gradle | 1 + forge111/build.gradle | 1 + forge1710/build.gradle | 1 + forge189/build.gradle | 1 + forge194/build.gradle | 1 + nukkit/build.gradle | 1 + .../fawe/nukkit/optimization/FaweNukkit.java | 3 - .../optimization/queue/NukkitChunk.java | 27 +- .../optimization/queue/NukkitQueue.java | 29 +- sponge/build.gradle | 1 + .../com/boydti/fawe/sponge/SpongeTaskMan.java | 4 +- 87 files changed, 2345 insertions(+), 1094 deletions(-) create mode 100644 core/src/main/java/com/boydti/fawe/object/change/MutableBiomeChange.java delete mode 100644 core/src/main/java/com/boydti/fawe/util/WESubscriber.java create mode 100644 core/src/main/java/com/sk89q/worldedit/Vector2D.java diff --git a/build.gradle b/build.gradle index 01c93e83..8a2c3726 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,6 @@ buildscript { dependencies { classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3' classpath 'org.ajoberstar:grgit:1.7.0' -// classpath 'it.unimi.dsi:fastutil:7.0.12' } } @@ -80,9 +79,9 @@ subprojects { repositories { mavenCentral() + maven {url "http://ci.emc.gs/nexus/content/groups/aikar/" } maven {url "http://ci.regularbox.com/plugin/repository/everything/"} maven {url "http://empcraft.com/maven2"} - maven {url "http://repo.mcstats.org/content/repositories/public"} maven {url "https://hub.spigotmc.org/nexus/content/groups/public/"} maven {url "http://maven.sk89q.com/repo/"} maven {url "http://nexus.hc.to/content/repositories/pub_releases"} diff --git a/bukkit/build.gradle b/bukkit/build.gradle index b53e2f7c..c2844d0c 100644 --- a/bukkit/build.gradle +++ b/bukkit/build.gradle @@ -37,6 +37,7 @@ apply plugin: 'com.github.johnrengelman.shadow' shadowJar { dependencies { include(dependency('com.github.luben:zstd-jni:1.1.1')) + include(dependency('co.aikar:fastutil-lite:1.0')) include(dependency(':core')) } archiveName = "${parent.name}-${project.name}-${parent.version}.jar" diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitTaskMan.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitTaskMan.java index 34134d66..f3248a89 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitTaskMan.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitTaskMan.java @@ -1,7 +1,6 @@ package com.boydti.fawe.bukkit; import com.boydti.fawe.util.TaskManager; -import java.util.HashMap; import org.apache.commons.lang.mutable.MutableInt; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; @@ -25,7 +24,6 @@ public class BukkitTaskMan extends TaskManager { } public MutableInt index = new MutableInt(0); - public HashMap tasks = new HashMap<>(); @Override public void async(final Runnable r) { diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java index 00f1083d..71150922 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitChunk_All.java @@ -11,10 +11,10 @@ import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitUtil; -import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.ArrayList; import org.bukkit.Bukkit; import org.bukkit.Chunk; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; @@ -75,36 +75,26 @@ public class BukkitChunk_All extends CharFaweChunk { long start = System.currentTimeMillis(); int recommended = 25 + BukkitQueue_All.ALLOCATE; boolean more = true; - BukkitQueue_All parent = (BukkitQueue_All) getParent(); + final BukkitQueue_All parent = (BukkitQueue_All) getParent(); final Chunk chunk = getChunk(); Object[] disableResult = parent.disableLighting(chunk); final World world = chunk.getWorld(); char[][] sections = getCombinedIdArrays(); + final int bx = getX() << 4; + final int bz = getZ() << 4; if (layer == -1) { // Biomes if (layer == 0) { - final int[][] biomes = getBiomeArray(); + final byte[] biomes = getBiomeArray(); if (biomes != null) { final LocalWorld lw = BukkitUtil.getLocalWorld(world); - final int X = getX() << 4; - final int Z = getZ() << 4; - final BaseBiome bb = new BaseBiome(0); - int last = 0; - for (int x = 0; x < 16; x++) { - final int[] array = biomes[x]; - if (array == null) { - continue; - } - for (int z = 0; z < 16; z++) { - final int biome = array[z]; - if (biome == 0) { - continue; - } - if (last != biome) { - last = biome; - bb.setId(biome); - } - lw.setBiome(new Vector2D(X + x, Z + z), bb); + int index = 0; + Vector2D mutable = new Vector2D(); + for (int z = 0; z < 16; z++) { + mutable.z = bx + z; + for (int x = 0; x < 16; x++) { + mutable.x = bz + x; + lw.setBiome(mutable, FaweCache.getBiome(biomes[index++] & 0xFF)); } } } @@ -142,11 +132,11 @@ public class BukkitChunk_All extends CharFaweChunk { final byte[] cacheZ = FaweCache.CACHE_Z[layer]; boolean checkTime = !((getAir(layer) == 4096 || (getCount(layer) == 4096 && getAir(layer) == 0) || (getCount(layer) == getAir(layer)))); if (!checkTime) { - ArrayList threads = new ArrayList(); + final ArrayList threads = new ArrayList(); for (int k = 0; k < 16; k++) { final int l = k << 8; final int y = cacheY[l]; - Thread thread = new Thread(new Runnable() { + final Thread thread = new Thread(new Runnable() { @Override public void run() { for (int m = l; m < l + 256; m++) { @@ -166,6 +156,13 @@ public class BukkitChunk_All extends CharFaweChunk { int x = cacheX[m]; int z = cacheZ[m]; int id = combined >> 4; + if (FaweCache.hasNBT(id) && parent.adapter != null) { + CompoundTag nbt = getTile(x, y, z); + if (nbt != null) { + parent.adapter.setBlock(new Location(world, bx + x, y, bz + z), new BaseBlock(id, combined & 0xF, nbt), false); + continue; + } + } Block block = chunk.getBlock(x, y, z); setBlock(block, id, (byte) (combined & 0xF)); } @@ -214,15 +211,14 @@ public class BukkitChunk_All extends CharFaweChunk { int x = cacheX[j]; int z = cacheZ[j]; int y = cacheY[j]; - Block block = chunk.getBlock(x, y, z); if (FaweCache.hasNBT(id) && parent.adapter != null) { CompoundTag tile = getTile(x, y, z); if (tile != null) { - BaseBlock baseBlock = new BaseBlock(id, data, tile); - parent.adapter.setBlock(block.getLocation(), baseBlock, false); + parent.adapter.setBlock(new Location(world, bx + x, y, bz + z), new BaseBlock(id, combined & 0xF, tile), false); break; } } + Block block = chunk.getBlock(x, y, z); setBlock(block, id, (byte) data); if (light) { parent.disableLighting(disableResult); diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java index 554cc656..8ea789a6 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java @@ -161,11 +161,6 @@ public abstract class BukkitQueue_0 extends NMSMa return getWorldName() != null ? Bukkit.getWorld(getWorldName()) : null; } - @Override - public boolean isChunkLoaded(World world, int x, int z) { - return world.isChunkLoaded(x, z); - } - @Override public void sendChunk(int x, int z, int bitMask) {} @@ -188,15 +183,6 @@ public abstract class BukkitQueue_0 extends NMSMa return getWorld().getEnvironment() == World.Environment.NORMAL; } - @Override - public boolean loadChunk(World impWorld, int x, int z, boolean generate) { - if (impWorld.loadChunk(x, z, generate)) { - keepLoaded.put(MathMan.pairInt(x, z), System.currentTimeMillis()); - return true; - } - return false; - } - private volatile boolean timingsEnabled; private static boolean alertTimingsChange = true; private static Field fieldTimingsEnabled; diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java index 678bde66..67a3f4f7 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java @@ -3,18 +3,18 @@ package com.boydti.fawe.bukkit.v0; import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.RunnableVal; -import com.boydti.fawe.util.TaskManager; +import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.blocks.BaseBlock; import java.lang.reflect.Field; import java.lang.reflect.Method; import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.block.Block; +import org.bukkit.block.Biome; -public class BukkitQueue_All extends BukkitQueue_0 { +public class BukkitQueue_All extends BukkitQueue_0 { public static int ALLOCATE; private static int LIGHT_MASK = 0x739C0; @@ -39,87 +39,108 @@ public class BukkitQueue_All extends BukkitQueue_0 { @Override public void setHeightMap(FaweChunk chunk, byte[] heightMap) { - // Do nothing + // Not supported } @Override - public void setSkyLight(Chunk chunk, int x, int y, int z, int value) { - + public void setSkyLight(ChunkSnapshot chunk, int x, int y, int z, int value) { + // Not supported } @Override - public void setBlockLight(Chunk chunk, int x, int y, int z, int value) { -// chunk.getBlock(x & 15, y, z & 15); + public void setBlockLight(ChunkSnapshot chunk, int x, int y, int z, int value) { + // Not supported } - public int getCombinedId4Data(Chunk section, int x, int y, int z) { - Block block = ((Chunk) section).getBlock(x & 15, y, z & 15); - int combined = block.getTypeId() << 4; - if (FaweCache.hasData(combined)) { - combined += block.getData(); + @Override + public int getCombinedId4Data(ChunkSnapshot chunk, int x, int y, int z) { + if (chunk.isSectionEmpty(y >> 4)) { + return 0; + } + int id = chunk.getBlockTypeId(x & 15, y, z & 15); + if (FaweCache.hasData(id)) { + int data = chunk.getBlockData(x & 15, y, z & 15); + return (id << 4) + data; + } else { + return id << 4; } - return combined; } @Override - public int getEmmittedLight(final Chunk chunk, int x, int y, int z) { - if (!chunk.isLoaded()) { - TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Object value) { - chunk.load(true); + public int getBiome(ChunkSnapshot chunkSnapshot, int x, int z) { + Biome biome = chunkSnapshot.getBiome(x & 15, z & 15); + return adapter.getBiomeId(biome); + } + + @Override + public ChunkSnapshot getSections(ChunkSnapshot chunkSnapshot) { + return chunkSnapshot; + } + + @Override + public ChunkSnapshot getCachedChunk(World world, int cx, int cz) { + if (world.isChunkLoaded(cx, cz)) { + long pair = MathMan.pairInt(cx, cz); + Long originalKeep = keepLoaded.get(pair); + keepLoaded.put(pair, Long.MAX_VALUE); + if (world.isChunkLoaded(cx, cz)) { + Chunk chunk = world.getChunkAt(cx, cz); + if (originalKeep != null) { + keepLoaded.put(pair, originalKeep); + } else { + keepLoaded.remove(pair); } - }); + return chunk.getChunkSnapshot(false, true, false); + + } else { + keepLoaded.remove(pair); + return null; + } + } else { + return null; } - return chunk.getBlock(x, y, z).getLightFromBlocks(); } @Override - public int getSkyLight(final Chunk chunk, int x, int y, int z) { - if (!chunk.isLoaded()) { - TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Object value) { - chunk.load(true); - } - }); - } - return chunk.getBlock(x, y, z).getLightFromSky(); + public int getEmmittedLight(final ChunkSnapshot chunk, int x, int y, int z) { + return chunk.getBlockEmittedLight(x & 15, y, z & 15); } @Override - public int getLight(final Chunk chunk, int x, int y, int z) { - if (!chunk.isLoaded()) { - TaskManager.IMP.sync(new RunnableVal() { - @Override - public void run(Object value) { - chunk.load(true); - } - }); - } - return chunk.getBlock(x, y, z).getLightLevel(); + public int getSkyLight(final ChunkSnapshot chunk, int x, int y, int z) { + return chunk.getBlockSkyLight(x & 15, y, z & 15); } @Override - public Chunk getCachedSections(World impWorld, int cx, int cz) { - return impWorld.getChunkAt(cx, cz); + public int getLight(final ChunkSnapshot chunk, int x, int y, int z) { + x = x & 15; + z = z & 15; + return Math.max(chunk.getBlockEmittedLight(x, y, z), chunk.getBlockSkyLight(x, y, z)); } @Override - public CompoundTag getTileEntity(Chunk chunk, int x, int y, int z) { + public ChunkSnapshot loadChunk(World world, int x, int z, boolean generate) { + Chunk chunk = world.getChunkAt(x, z); + chunk.load(generate); + return chunk.isLoaded() ? chunk.getChunkSnapshot(false, true, false) : null; + } + + @Override + public ChunkSnapshot getCachedSections(World impWorld, int cx, int cz) { + return getCachedChunk(impWorld, cx, cz); + } + + @Override + public CompoundTag getTileEntity(ChunkSnapshot chunk, int x, int y, int z) { if (adapter == null) { return null; } Location loc = new Location(getWorld(), x, y, z); BaseBlock block = adapter.getBlock(loc); + System.out.println("Get tile " + x + "," + y + "," + z + " | " + (block != null ? block.getNbtData() : null) + " | done"); return block != null ? block.getNbtData() : null; } - @Override - public Chunk getChunk(World world, int x, int z) { - return world.getChunkAt(x, z); - } - @Override public FaweChunk getFaweChunk(int x, int z) { return new BukkitChunk_All(this, x, z); diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/ChunkListener.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/ChunkListener.java index f78eb92e..fb2237d7 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/ChunkListener.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/ChunkListener.java @@ -6,8 +6,9 @@ import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.IntegerTrio; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.TaskManager; -import java.util.HashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.HashSet; +import java.util.Map; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; @@ -46,11 +47,37 @@ public class ChunkListener implements Listener { } } + public static void main(String[] args) { + Map map = new Long2ObjectOpenHashMap() { + @Override + public Object put(long l, Object o) { + synchronized (this) { + return super.put(l, o); + } + } + + @Override + public synchronized Object put(Long aLong, Object o) { + return super.put(aLong, o); + } + }; +// map = new ConcurrentHashMap<>(); + long start = System.currentTimeMillis(); + for (int j = 0; j < 50000; j++) { + for (long i = 0; i < 256; i++) { + map.put(i, i); + } + map.clear(); + } + System.out.println(System.currentTimeMillis() - start); + System.out.println(map.size()); + } + public static boolean physicsFreeze = false; public static boolean itemFreeze = false; private HashSet badChunks = new HashSet<>(); - private HashMap counter = new HashMap<>(); + private Map counter = new Long2ObjectOpenHashMap<>(); private int lastX = Integer.MIN_VALUE, lastZ = Integer.MIN_VALUE; private IntegerTrio lastCount; diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10.java index c8af66d0..1694279a 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitChunk_1_10.java @@ -396,19 +396,11 @@ public class BukkitChunk_1_10 extends CharFaweChunk { getParent().setCount(0, getParent().getNonEmptyBlockCount(section) + nonEmptyBlockCount, section); } // Set biomes - int[][] biomes = this.biomes; - if (biomes != null) { - for (int x = 0; x < 16; x++) { - int[] array = biomes[x]; - if (array == null) { - continue; - } - for (int z = 0; z < 16; z++) { - int biome = array[z]; - if (biome == 0) { - continue; - } - nmsChunk.getBiomeIndex()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome; + if (this.biomes != null) { + byte[] currentBiomes = nmsChunk.getBiomeIndex(); + for (int i = 0 ; i < this.biomes.length; i++) { + if (this.biomes[i] != 0) { + currentBiomes[i] = this.biomes[i]; } } } diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java index b6483b78..15724e60 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java @@ -64,7 +64,7 @@ import org.bukkit.event.world.WorldInitEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.generator.ChunkGenerator; -public class BukkitQueue_1_10 extends BukkitQueue_0 { +public class BukkitQueue_1_10 extends BukkitQueue_0 { protected static IBlockData air; protected static Field fieldBits; @@ -304,13 +304,42 @@ public class BukkitQueue_1_10 extends BukkitQueue_0 tiles = ((CraftChunk) chunk).getHandle().getTileEntities(); + public CompoundTag getTileEntity(net.minecraft.server.v1_10_R1.Chunk chunk, int x, int y, int z) { + Map tiles = chunk.getTileEntities(); pos.c(x, y, z); TileEntity tile = tiles.get(pos); return tile != null ? getTag(tile) : null; @@ -627,11 +650,6 @@ public class BukkitQueue_1_10 extends BukkitQueue_0 map = ReflectionUtils.getMap(nativeTag.getValue()); + map.put("Id", new StringTag(id)); + setEntity(nativeTag); + return true; + } else { + return false; + } + } + @Override public CharFaweChunk copy(boolean shallow) { BukkitChunk_1_11 copy; @@ -174,6 +210,7 @@ public class BukkitChunk_1_11 extends CharFaweChunk[] entities = (Collection[]) getParent().getEntitySlices.invoke(nmsChunk); Map tiles = nmsChunk.getTileEntities(); - // copy -// BukkitChunk_1_11 copy = getParent().getFaweChunk(getX(), getZ()); // TODO // Set heightmap getParent().setHeightMap(this, heightMap); // Remove entities @@ -198,6 +233,9 @@ public class BukkitChunk_1_11 extends CharFaweChunk ents = new ArrayList<>(entities[i]); for (Entity entity : ents) { if (entsToRemove.contains(entity.getUniqueID())) { + if (copy != null) { + copy.storeEntity(entity); + } nmsWorld.removeEntity(entity); } } @@ -211,7 +249,11 @@ public class BukkitChunk_1_11 extends CharFaweChunk= 4096) { Collection ents = entities[i]; if (!ents.isEmpty()) { -// copy.storeEntities(this, i); + if (copy != null) { + for (Entity entity : ents) { + copy.storeEntity(entity); + } + } synchronized (BukkitQueue_0.adapter) { ents.clear(); } @@ -220,8 +262,7 @@ public class BukkitChunk_1_11 extends CharFaweChunk ents = entities[i]; if (!ents.isEmpty()) { char[] array = this.getIdArray(i); - if (array == null || entities[i] == null || entities[i].isEmpty()) continue; - ents = new ArrayList<>(entities[i]); + if (array == null || ents == null || ents.isEmpty()) continue; synchronized (BukkitQueue_0.adapter) { for (Entity entity : ents) { if (entity instanceof EntityPlayer) { @@ -232,7 +273,9 @@ public class BukkitChunk_1_11 extends CharFaweChunk 255) continue; if (array[FaweCache.CACHE_J[y][z][x]] != 0) { -// copy.storeEntity(this, entity); + if (copy != null) { + copy.storeEntity(entity); + } nmsWorld.removeEntity(entity); } } @@ -291,11 +334,6 @@ public class BukkitChunk_1_11 extends CharFaweChunk> iterator = tiles.entrySet().iterator(); HashMap toRemove = null; @@ -315,11 +353,13 @@ public class BukkitChunk_1_11 extends CharFaweChunk(); } + if (copy != null) { + storeTile(tile.getValue(), tile.getKey()); + } toRemove.put(tile.getKey(), tile.getValue()); } } if (toRemove != null) { -// copy.storeTiles(this, toRemove); for (Map.Entry entry : toRemove.entrySet()) { BlockPosition bp = entry.getKey(); TileEntity tile = entry.getValue(); @@ -342,7 +382,9 @@ public class BukkitChunk_1_11 extends CharFaweChunk { +public class BukkitQueue_1_11 extends BukkitQueue_0 { protected static IBlockData air; protected static Field fieldBits; @@ -150,6 +150,41 @@ public class BukkitQueue_1_11 extends BukkitQueue_0 tiles = ((CraftChunk) chunk).getHandle().getTileEntities(); + public CompoundTag getTileEntity(net.minecraft.server.v1_11_R1.Chunk chunk, int x, int y, int z) { + Map tiles = chunk.getTileEntities(); pos.c(x, y, z); TileEntity tile = tiles.get(pos); return tile != null ? getTag(tile) : null; @@ -618,11 +648,6 @@ public class BukkitQueue_1_11 extends BukkitQueue_0 { } // Set biomes - int[][] biomes = this.biomes; - if (biomes != null) { - for (int x = 0; x < 16; x++) { - int[] array = biomes[x]; - if (array == null) { - continue; - } - for (int z = 0; z < 16; z++) { - int biome = array[z]; - if (biome == 0) { - continue; - } - nmsChunk.m()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome; // Biome array + if (this.biomes != null) { + byte[] currentBiomes = nmsChunk.m(); + for (int i = 0 ; i < this.biomes.length; i++) { + if (this.biomes[i] != 0) { + currentBiomes[i] = this.biomes[i]; } } } diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java index 9412193b..8892e457 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_7/BukkitQueue17.java @@ -48,7 +48,6 @@ import net.minecraft.server.v1_7_R4.WorldServer; import net.minecraft.server.v1_7_R4.WorldSettings; import net.minecraft.server.v1_7_R4.WorldType; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.WorldCreator; import org.bukkit.block.Biome; @@ -59,7 +58,7 @@ import org.bukkit.event.world.WorldInitEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.generator.ChunkGenerator; -public class BukkitQueue17 extends BukkitQueue_0 { +public class BukkitQueue17 extends BukkitQueue_0 { protected static Field fieldData; protected static Field fieldIds; @@ -175,18 +174,48 @@ public class BukkitQueue17 extends BukkitQueue_0 tilesGeneric, Collection[] entitiesGeneric, Set createdEntities, boolean all) throws Exception { Map tiles = (Map) tilesGeneric; @@ -307,19 +314,14 @@ public class BukkitQueue17 extends BukkitQueue_0 tiles = ((CraftChunk) chunk).getHandle().tileEntities; + public CompoundTag getTileEntity(net.minecraft.server.v1_7_R4.Chunk chunk, int x, int y, int z) { + Map tiles = chunk.tileEntities; ChunkPosition pos = new ChunkPosition(x, y, z); TileEntity tile = tiles.get(pos); return tile != null ? getTag(tile) : null; } - @Override - public Chunk getChunk(World world, int x, int z) { - return world.getChunkAt(x, z); - } - public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException { fieldTickingBlockCount.set(section, tickingBlockCount); fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount); @@ -331,28 +333,22 @@ public class BukkitQueue17 extends BukkitQueue_0 { } // Set biomes - int[][] biomes = this.biomes; - if (biomes != null) { - for (int x = 0; x < 16; x++) { - int[] array = biomes[x]; - if (array == null) { - continue; - } - for (int z = 0; z < 16; z++) { - int biome = array[z]; - if (biome == 0) { - continue; - } - nmsChunk.getBiomeIndex()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome; + if (this.biomes != null) { + byte[] currentBiomes = nmsChunk.getBiomeIndex(); + for (int i = 0 ; i < this.biomes.length; i++) { + if (this.biomes[i] != 0) { + currentBiomes[i] = this.biomes[i]; } } } diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue18R3.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue18R3.java index e881a679..fcb8e4e6 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue18R3.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue18R3.java @@ -47,7 +47,6 @@ import net.minecraft.server.v1_8_R3.WorldServer; import net.minecraft.server.v1_8_R3.WorldSettings; import net.minecraft.server.v1_8_R3.WorldType; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.WorldCreator; import org.bukkit.block.Biome; @@ -58,7 +57,7 @@ import org.bukkit.event.world.WorldInitEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.generator.ChunkGenerator; -public class BukkitQueue18R3 extends BukkitQueue_0 { +public class BukkitQueue18R3 extends BukkitQueue_0 { public static Field isDirty; @@ -180,17 +179,43 @@ public class BukkitQueue18R3 extends BukkitQueue_0 tilesGeneric, Collection[] entitiesGeneric, Set createdEntities, boolean all) throws Exception { Map tiles = (Map) tilesGeneric; @@ -309,19 +312,14 @@ public class BukkitQueue18R3 extends BukkitQueue_0 tiles = ((CraftChunk) chunk).getHandle().getTileEntities(); + public CompoundTag getTileEntity(net.minecraft.server.v1_8_R3.Chunk chunk, int x, int y, int z) { + Map tiles = chunk.getTileEntities(); pos.c(x, y, z); TileEntity tile = tiles.get(pos); return tile != null ? getTag(tile) : null; } - @Override - public Chunk getChunk(World world, int x, int z) { - return world.getChunkAt(x, z); - } - public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException { fieldTickingBlockCount.set(section, tickingBlockCount); fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount); @@ -333,28 +331,22 @@ public class BukkitQueue18R3 extends BukkitQueue_0 { getParent().setCount(0, getParent().getNonEmptyBlockCount(section) + nonEmptyBlockCount, section); } // Set biomes - int[][] biomes = this.biomes; + byte[] biomes = this.biomes; if (biomes != null) { - for (int x = 0; x < 16; x++) { - int[] array = biomes[x]; - if (array == null) { - continue; - } - for (int z = 0; z < 16; z++) { - int biome = array[z]; - if (biome == 0) { - continue; - } - nmsChunk.getBiomeIndex()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome; + byte[] currentBiomes = nmsChunk.getBiomeIndex(); + for (int i = 0; i < currentBiomes.length; i++) { + byte newBiome = biomes[i]; + if (newBiome != 0) { + currentBiomes[i] = newBiome; } } } @@ -437,23 +430,6 @@ public class BukkitChunk_1_9 extends CharFaweChunk { } catch (Throwable e) { MainUtil.handleError(e); } - final int[][] biomes = this.getBiomeArray(); - final Biome[] values = Biome.values(); - if (biomes != null) { - for (int x = 0; x < 16; x++) { - final int[] array = biomes[x]; - if (array == null) { - continue; - } - for (int z = 0; z < 16; z++) { - final int biome = array[z]; - if (biome == 0) { - continue; - } - chunk.getBlock(x, 0, z).setBiome(values[biome]); - } - } - } return this; } -} +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java index 3a585895..bdc7f1b4 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java @@ -62,7 +62,7 @@ import org.bukkit.event.world.WorldInitEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.generator.ChunkGenerator; -public class BukkitQueue_1_9_R1 extends BukkitQueue_0 { +public class BukkitQueue_1_9_R1 extends BukkitQueue_0 { protected static IBlockData air; protected static Field fieldBits; @@ -191,13 +191,42 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0 tiles = ((CraftChunk) chunk).getHandle().getTileEntities(); + public CompoundTag getTileEntity(net.minecraft.server.v1_9_R2.Chunk chunk, int x, int y, int z) { + Map tiles = chunk.getTileEntities(); pos.c(x, y, z); TileEntity tile = tiles.get(pos); return tile != null ? getTag(tile) : null; @@ -578,11 +601,6 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0 block @@ -129,7 +135,19 @@ public class FaweCache { return CACHE_COLOR[0]; } + public static final BaseBiome getBiome(int id) { + return CACHE_BIOME[id]; + } + static { + for (int i = 0; i < 256; i++) { + CACHE_BIOME[i] = new BaseBiome(i) { + @Override + public void setId(int id) { + throw new IllegalStateException("Cannot set id"); + } + }; + } for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 256; y++) { diff --git a/core/src/main/java/com/boydti/fawe/config/BBC.java b/core/src/main/java/com/boydti/fawe/config/BBC.java index 94e8f5f5..b0577213 100644 --- a/core/src/main/java/com/boydti/fawe/config/BBC.java +++ b/core/src/main/java/com/boydti/fawe/config/BBC.java @@ -76,9 +76,11 @@ public enum BBC { COMMAND_REGEN_1("Region regenerated.\nTip: Use a seed with /regen [biome] [seed]", "WorldEdit.Regen"), COMMAND_REGEN_2("Region regenerated.", "WorldEdit.Regen"), COMMAND_TREE("%s0 trees created.", "WorldEdit.Tree"), + COMMAND_PUMPKIN("%s0 pumpkin patches created.", "WorldEdit.Tree"), COMMAND_FLORA("%s0 flora created.", "WorldEdit.Flora"), COMMAND_HISTORY_CLEAR("History cleared", "WorldEdit.History"), COMMAND_REDO_ERROR("Nothing left to redo. (See also `/inspect` and `/frb`)", "WorldEdit.History"), + COMMAND_HISTORY_OTHER_ERROR("Unable to find session for %s0.", "WorldEdit.History"), COMMAND_REDO_SUCCESS("Redo successful.", "WorldEdit.History"), COMMAND_UNDO_ERROR("Nothing left to undo. (See also `/inspect` and `/frb`)", "WorldEdit.History"), COMMAND_UNDO_SUCCESS("Undo successful.", "WorldEdit.History"), @@ -133,6 +135,7 @@ public enum BBC { BRUSH_TRANSFORM("Brush transform set", "WorldEdit.Brush"), BRUSH_MATERIAL("Brush material set", "WorldEdit.Brush"), + ROLLBACK_ELEMENT("Undoing %s0", "WorldEdit.Rollback"), TOOL_INSPECT("Inspect tool bound to %s0.", "WorldEdit.Tool"), @@ -145,13 +148,32 @@ public enum BBC { TOOL_REPL("Block replacer tool bound to %s0.", "WorldEdit.Tool"), TOOL_CYCLER("Block data cycler tool bound to %s0.", "WorldEdit.Tool"), TOOL_FLOOD_FILL("Block flood fill tool bound to %s0.", "WorldEdit.Tool"), - TOOL_FLOOD_FILL_RANGE_ERROR("Maximum range: %s0.", "WorldEdit.Tool"), + TOOL_RANGE_ERROR("Maximum range: %s0.", "WorldEdit.Tool"), + TOOL_RADIUS_ERROR("Maximum allowed brush radius: %s0.", "WorldEdit.Tool"), TOOL_DELTREE("Floating tree remover tool bound to %s0.", "WorldEdit.Tool"), TOOL_FARWAND("Far wand tool bound to %s0.", "WorldEdit.Tool"), TOOL_LRBUILD_BOUND("Long-range building tool bound to %s0.", "WorldEdit.Tool"), TOOL_LRBUILD_INFO("Left-click set to %s0; right-click set to %s1.", "WorldEdit.Tool"), SUPERPICKAXE_ENABLED("Super Pickaxe enabled.", "WorldEdit.Tool"), SUPERPICKAXE_DISABLED("Super Pickaxe disabled.", "WorldEdit.Tool"), + SUPERPICKAXE_AREA_ENABLED("Mode changed. Left click with a pickaxe. // to disable.", "WorldEdit.Tool"), + + SNAPSHOT_LOADED("Snapshot '%s0' loaded; now restoring...", "WorldEdit.Snapshot"), + SNAPSHOT_SET("Snapshot set to: %s0", "WorldEdit.Snapshot"), + SNAPSHOT_NEWEST("Now using newest snapshot.", "WorldEdit.Snapshot"), + SNAPSHOT_LIST_HEADER("Snapshots for world (%s0):", "WorldEdit.Snapshot"), + SNAPSHOT_LIST_FOOTER("Use /snap use [snapshot] or /snap use latest.", "WorldEdit.Snapshot"), + + BIOME_LIST_HEADER("Biomes (page %s0/%s1):", "WorldEdit.Biome"), + BIOME_CHANGED("Biomes were changed in %s0 columns.", "WorldEdit.Biome"), + + FAST_ENABLED("Fast mode enabled. History and edit restrictions will be bypassed.", "WorldEdit.General"), + FAST_DISABLED("Fast mode disabled", "WorldEdit.General"), + + PLACE_ENABLED("Now placing at pos #1.", "WorldEdit.General"), + PLACE_DISABLED("Now placing at the block you stand in.", "WorldEdit.General"), + + KILL_SUCCESS("Killed %s0 entities in a radius of %s1.", "WorldEdit.Utility"), SCHEMATIC_DELETE("%s0 has been deleted.", "Worldedit.Schematic"), @@ -163,6 +185,7 @@ public enum BBC { SCHEMATIC_LIST("Available schematics (Filename: Format) [%s0/%s1]:", "Worldedit.Schematic"), CLIPBOARD_CLEARED("Clipboard cleared", "WorldEdit.Clipboard"), + CLIPBOARD_INVALID_FORMAT("Unknown clipboard format: %s0", "WorldEdit.Clipboard"), VISITOR_BLOCK("%s0 blocks affected", "WorldEdit.Visitor"), VISITOR_ENTITY("%s0 entities affected", "WorldEdit.Visitor"), @@ -174,6 +197,10 @@ public enum BBC { SELECTOR_CUBOID_POS2("pos2 set to %s0 %s1.", "WorldEdit.Selector"), SELECTOR_INVALID_COORDINATES("Invalid coordinates %s0", "WorldEdit.Selector"), SELECTOR_ALREADY_SET("Position already set.", "WorldEdit.Selector"), + SELECTOR_SET_DEFAULT("Your default region selector is now %s0.", "WorldEdit.Selector"), + + TIMEZONE_SET("Timezone set for this session to: %s0", "WorldEdit.Timezone"), + TIMEZONE_DISPLAY("The current time in that timezone is: %s0", "WorldEdit.Timezone"), COMMAND_INVALID_SYNTAX("The command was not used properly (no more help available).", "WorldEdit.Command"), @@ -222,7 +249,7 @@ public enum BBC { WHOOSH("Whoosh!", "Navigation"), POOF("Poof!", "Navigation"), THRU_FAIL("No free spot ahead of you found.", "Navigation"), - JUMPTO_FAIL("No block in sight!", "Navigation"), + NO_BLOCK("No block in sight! (or too far)", "Navigation"), UP_FAIL("You would hit something above you.", "Navigation"), SEL_CUBOID("Cuboid: left click for point 1, right click for point 2", "Selection"), diff --git a/core/src/main/java/com/boydti/fawe/config/Config.java b/core/src/main/java/com/boydti/fawe/config/Config.java index d3191ae6..1354cf39 100644 --- a/core/src/main/java/com/boydti/fawe/config/Config.java +++ b/core/src/main/java/com/boydti/fawe/config/Config.java @@ -4,6 +4,7 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.configuration.MemorySection; import com.boydti.fawe.configuration.file.YamlConfiguration; import com.boydti.fawe.util.StringMan; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintWriter; import java.lang.annotation.ElementType; @@ -22,6 +23,10 @@ import java.util.Map; public class Config { + public Config() { + save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0); + } + /** * Get the value for a node
* Probably throws some error if you try to get a non existent key @@ -220,7 +225,7 @@ public class Config { return value != null ? value.toString() : "null"; } - private void save(PrintWriter writer, Class clazz, Object instance, int indent) { + private void save(PrintWriter writer, Class clazz, final Object instance, int indent) { try { String CTRF = System.lineSeparator(); String spacing = StringMan.repeat(" ", indent); diff --git a/core/src/main/java/com/boydti/fawe/config/Settings.java b/core/src/main/java/com/boydti/fawe/config/Settings.java index 69ed72f4..d10d30ea 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -18,13 +18,13 @@ public class Settings extends Config { @Final public final String WIKI = "https://github.com/boy0001/FastAsyncWorldedit/wiki/"; @Final - public String DATE = null; // These values are set from FAWE before loading + public String DATE; // These values are set from FAWE before loading @Final - public String BUILD = null; // These values are set from FAWE before loading + public String BUILD; // These values are set from FAWE before loading @Final - public String COMMIT = null; // These values are set from FAWE before loading + public String COMMIT; // These values are set from FAWE before loading @Final - public String PLATFORM = null; // These values are set from FAWE before loading + public String PLATFORM; // These values are set from FAWE before loading @Comment("Allow the plugin to update") public boolean UPDATE = true; @@ -46,23 +46,23 @@ public class Settings extends Config { public int MAX_MEMORY_PERCENT = 95; @Create - public CLIPBOARD CLIPBOARD = null; + public CLIPBOARD CLIPBOARD; @Create - public LIGHTING LIGHTING = null; + public LIGHTING LIGHTING; @Create - public TICK_LIMITER TICK_LIMITER = null; + public TICK_LIMITER TICK_LIMITER; @Create - public WEB WEB = null; + public WEB WEB; @Create - public EXTENT EXTENT = null; + public EXTENT EXTENT; @Create - public EXPERIMENTAL EXPERIMENTAL = null; + public EXPERIMENTAL EXPERIMENTAL; @Create - public QUEUE QUEUE = null; + public QUEUE QUEUE; @Create - public HISTORY HISTORY = null; + public HISTORY HISTORY; @Create - public PATHS PATHS = null; + public PATHS PATHS; @Comment("Paths for various directories") public static final class PATHS { @@ -72,7 +72,7 @@ public class Settings extends Config { @Create // This value will be generated automatically - public ConfigBlock LIMITS = null; + public ConfigBlock LIMITS; @Comment({ "The \"default\" limit group affects those without a specific limit permission.", @@ -208,7 +208,7 @@ public class Settings extends Config { public static class QUEUE { @Create - public static PROGRESS PROGRESS = null; + public static PROGRESS PROGRESS; @Comment({ "If no blocks from completed edits are queued, and if the global queue has more available ", "chunks to place from still-processing edits than the target size setting, it will begin", 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 7437c2a9..27cad6f1 100644 --- a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java @@ -5,7 +5,6 @@ import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.MathMan; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -19,7 +18,7 @@ public abstract class CharFaweChunk extends FaweChunk public final short[] air; public final byte[] heightMap; - public int[][] biomes; + public byte[] biomes; public HashMap tiles; public HashSet entities; public HashSet entityRemoves; @@ -121,7 +120,8 @@ public abstract class CharFaweChunk extends FaweChunk return this.ids; } - public int[][] getBiomeArray() { + @Override + public byte[] getBiomeArray() { return this.biomes; } @@ -342,15 +342,11 @@ public abstract class CharFaweChunk extends FaweChunk } @Override - public void setBiome(final int x, final int z, final BaseBiome biome) { + public void setBiome(final int x, final int z, final byte biome) { if (this.biomes == null) { - this.biomes = new int[16][]; + this.biomes = new byte[256]; } - int[] index = this.biomes[x]; - if (index == null) { - index = this.biomes[x] = new int[16]; - } - index[z] = biome.getId(); + biomes[((z & 15) << 4) + (x & 15)] = biome; } @Override diff --git a/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java b/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java index c3086e81..d27024f3 100644 --- a/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java +++ b/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java @@ -5,11 +5,11 @@ import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.SetQueue; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorCompletionService; public class DefaultFaweQueueMap implements IFaweQueueMap { @@ -20,12 +20,14 @@ public class DefaultFaweQueueMap implements IFaweQueueMap { this.parent = parent; } - /** - * Map of chunks in the queue - */ - public final ConcurrentHashMap blocks = new ConcurrentHashMap(8, 0.9f, 1) { + public final Long2ObjectOpenHashMap blocks = new Long2ObjectOpenHashMap() { @Override public FaweChunk put(Long key, FaweChunk value) { + return put((long) key, value); + } + + @Override + public FaweChunk put(long key, FaweChunk value) { if (parent.getProgressTask() != null) { try { parent.getProgressTask().run(FaweQueue.ProgressType.QUEUE, size() + 1); @@ -33,7 +35,9 @@ public class DefaultFaweQueueMap implements IFaweQueueMap { e.printStackTrace(); } } - return super.put(key, value); + synchronized (this) { + return super.put(key, value); + } } }; @@ -109,67 +113,69 @@ public class DefaultFaweQueueMap implements IFaweQueueMap { @Override public boolean next(int amount, ExecutorCompletionService pool, long time) { - try { - boolean skip = parent.getStage() == SetQueue.QueueStage.INACTIVE; - int added = 0; - Iterator> iter = blocks.entrySet().iterator(); - if (amount == 1) { - long start = System.currentTimeMillis(); - do { - if (iter.hasNext()) { - FaweChunk chunk = iter.next().getValue(); - if (skip && chunk == lastWrappedChunk) { - continue; - } - iter.remove(); - parent.start(chunk); - chunk.call(); - parent.end(chunk); - } else { - break; - } - } while (System.currentTimeMillis() - start < time); - } else { - boolean result = true; - // amount = 8; - for (int i = 0; i < amount && (result = iter.hasNext()); i++, added++) { - Map.Entry item = iter.next(); - FaweChunk chunk = item.getValue(); - if (skip && chunk == lastWrappedChunk) { - i--; - added--; - continue; - } - iter.remove(); - parent.start(chunk); - pool.submit(chunk); - } - // if result, then submitted = amount - if (result) { + synchronized (blocks) { + try { + boolean skip = parent.getStage() == SetQueue.QueueStage.INACTIVE; + int added = 0; + Iterator> iter = blocks.entrySet().iterator(); + if (amount == 1) { long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < time && result) { - if (result = iter.hasNext()) { - Map.Entry item = iter.next(); - FaweChunk chunk = item.getValue(); + do { + if (iter.hasNext()) { + FaweChunk chunk = iter.next().getValue(); if (skip && chunk == lastWrappedChunk) { continue; } iter.remove(); parent.start(chunk); - pool.submit(chunk); - FaweChunk fc = ((FaweChunk) pool.take().get()); - parent.end(fc); + chunk.call(); + parent.end(chunk); + } else { + break; + } + } while (System.currentTimeMillis() - start < time); + } else { + boolean result = true; + // amount = 8; + for (int i = 0; i < amount && (result = iter.hasNext()); i++, added++) { + Map.Entry item = iter.next(); + FaweChunk chunk = item.getValue(); + if (skip && chunk == lastWrappedChunk) { + i--; + added--; + continue; + } + iter.remove(); + parent.start(chunk); + pool.submit(chunk); + } + // if result, then submitted = amount + if (result) { + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < time && result) { + if (result = iter.hasNext()) { + Map.Entry item = iter.next(); + FaweChunk chunk = item.getValue(); + if (skip && chunk == lastWrappedChunk) { + continue; + } + iter.remove(); + parent.start(chunk); + pool.submit(chunk); + FaweChunk fc = ((FaweChunk) pool.take().get()); + parent.end(fc); + } } } + for (int i = 0; i < added; i++) { + FaweChunk fc = ((FaweChunk) pool.take().get()); + parent.end(fc); + } } - for (int i = 0; i < added; i++) { - FaweChunk fc = ((FaweChunk) pool.take().get()); - parent.end(fc); - } + } catch (Throwable e) { + e.printStackTrace(); } - } catch (Throwable e) { - e.printStackTrace(); + return !blocks.isEmpty(); } - return !blocks.isEmpty(); } } 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 81d88ee3..d2064683 100644 --- a/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java @@ -21,17 +21,36 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.UUID; -import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; -public abstract class MappedFaweQueue extends FaweQueue { +public abstract class MappedFaweQueue extends FaweQueue { private WORLD impWorld; private IFaweQueueMap map; + public int lastSectionX = Integer.MIN_VALUE; + public int lastSectionZ = Integer.MIN_VALUE; + public int lastSectionY = Integer.MIN_VALUE; + public CHUNK lastChunk; + public CHUNKSECTIONS lastChunkSections; + public SECTION lastSection; + + private CHUNK cachedLoadChunk; + public final RunnableVal loadChunk = new RunnableVal() { + + { + this.value = new IntegerPair(0, 0); + } + + @Override + public void run(IntegerPair coord) { + cachedLoadChunk = loadChunk(getWorld(), coord.x, coord.z, true); + } + }; + public MappedFaweQueue(final World world) { this(world, null); } @@ -102,21 +121,18 @@ public abstract class MappedFaweQueue extends FaweQueue { public abstract WORLD getImpWorld(); - public abstract boolean isChunkLoaded(WORLD world, int x, int z); - public abstract boolean regenerateChunk(WORLD world, int x, int z, BaseBiome biome, Long seed); @Override public abstract FaweChunk getFaweChunk(int x, int z); - public abstract boolean loadChunk(WORLD world, int x, int z, boolean generate); + public abstract CHUNK loadChunk(WORLD world, int x, int z, boolean generate); - public abstract CHUNK getCachedSections(WORLD world, int cx, int cz); + public abstract CHUNKSECTIONS getSections(CHUNK chunk); - @Override - public boolean isChunkLoaded(int x, int z) { - return isChunkLoaded(getWorld(), x, z); - }; + public abstract CHUNKSECTIONS getCachedSections(WORLD world, int cx, int cz); + + public abstract CHUNK getCachedChunk(WORLD world, int cx, int cz); public WORLD getWorld() { if (impWorld != null) { @@ -233,16 +249,12 @@ public abstract class MappedFaweQueue extends FaweQueue { @Override public int size() { int size = map.size(); - if (size == 0 && getStage() != SetQueue.QueueStage.INACTIVE) { + if (size == 0 && getStage() == SetQueue.QueueStage.NONE) { runTasks(); } return size; } - private ConcurrentLinkedDeque toUpdate = new ConcurrentLinkedDeque<>(); - - private int dispatched = 0; - @Override public void clear() { map.clear(); @@ -254,44 +266,53 @@ public abstract class MappedFaweQueue extends FaweQueue { map.add(chunk); } - public int lastChunkX = Integer.MIN_VALUE; - public int lastChunkZ = Integer.MIN_VALUE; - public int lastChunkY = Integer.MIN_VALUE; - - public CHUNK lastChunkSections; - public SECTION lastSection; - - public SECTION getCachedSection(CHUNK chunk, int cy) { + public SECTION getCachedSection(CHUNKSECTIONS chunk, int cy) { return (SECTION) lastChunkSections; } public abstract int getCombinedId4Data(SECTION section, int x, int y, int z); - public final RunnableVal loadChunk = new RunnableVal() { - @Override - public void run(IntegerPair coord) { - loadChunk(getWorld(), coord.x, coord.z, true); - } - }; + public abstract int getBiome(CHUNK chunk, int x, int z); - long average = 0; + public abstract CompoundTag getTileEntity(CHUNK chunk, int x, int y, int z); - public boolean ensureChunkLoaded(int cx, int cz) throws FaweException.FaweChunkLoadException { - if (!isChunkLoaded(cx, cz)) { - boolean sync = Thread.currentThread() == Fawe.get().getMainThread(); - if (sync) { - loadChunk(getWorld(), cx, cz, true); - } else if (Settings.IMP.HISTORY.CHUNK_WAIT_MS > 0) { - loadChunk.value = new IntegerPair(cx, cz); - TaskManager.IMP.syncWhenFree(loadChunk, Settings.IMP.HISTORY.CHUNK_WAIT_MS); - if (!isChunkLoaded(cx, cz)) { - throw new FaweException.FaweChunkLoadException(); - } - } else { - return false; - } +// public CHUNKSECTIONS ensureSectionsLoaded(int cx, int cz) throws FaweException.FaweChunkLoadException { +// CHUNKSECTIONS sections = getCachedSections(getWorld(), cx, cz); +// if (sections != null) { +// return sections; +// } +// boolean sync = Thread.currentThread() == Fawe.get().getMainThread(); +// if (sync) { +// CHUNK chunk = loadChunk(getWorld(), cx, cz, true); +// return chunk != null ? getSections(chunk) : null; +// } else if (Settings.IMP.HISTORY.CHUNK_WAIT_MS > 0) { +// cachedLoadChunk = null; +// loadChunk.value.x = cx; +// loadChunk.value.z = cz; +// TaskManager.IMP.syncWhenFree(loadChunk, Settings.IMP.HISTORY.CHUNK_WAIT_MS); +// return cachedLoadChunk != null ? getSections(cachedLoadChunk) : null; +// } else { +// return null; +// } +// } + + public CHUNK ensureChunkLoaded(int cx, int cz) throws FaweException.FaweChunkLoadException { + CHUNK chunk = getCachedChunk(getWorld(), cx, cz); + if (chunk != null) { + return chunk; + } + boolean sync = Thread.currentThread() == Fawe.get().getMainThread(); + if (sync) { + return loadChunk(getWorld(), cx, cz, true); + } else if (Settings.IMP.HISTORY.CHUNK_WAIT_MS > 0) { + cachedLoadChunk = null; + loadChunk.value.x = cx; + loadChunk.value.z = cz; + TaskManager.IMP.syncWhenFree(loadChunk, Settings.IMP.HISTORY.CHUNK_WAIT_MS); + return cachedLoadChunk; + } else { + return null; } - return true; } @Override @@ -299,21 +320,24 @@ public abstract class MappedFaweQueue extends FaweQueue { int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return false; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return false; } - lastSection = getCachedSection(lastChunkSections, cy); } - if (lastSection == null) { return false; } @@ -368,21 +392,24 @@ public abstract class MappedFaweQueue extends FaweQueue { int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return 0; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return 0; } - lastSection = getCachedSection(lastChunkSections, cy); } - if (lastSection == null) { return 0; } @@ -394,24 +421,38 @@ public abstract class MappedFaweQueue extends FaweQueue { int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (y >= FaweChunk.HEIGHT) { - return 15; - } - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return 0; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { - return getSkyLight(x, y + 16, z); + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { + return 0; } - lastSection = getCachedSection(lastChunkSections, cy); } if (lastSection == null) { + if (lastChunkSections == null) { + return 0; + } + int max = FaweChunk.HEIGHT >> 4; + do { + if (++cy >= max) { + return 15; + } + lastSection = getCachedSection(lastChunkSections, cy); + } while (lastSection == null); + } + if (lastSection == null) { + return getSkyLight(x, y + 16, z); } return getSkyLight(lastSection, x, y, z); @@ -422,19 +463,23 @@ public abstract class MappedFaweQueue extends FaweQueue { int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return 0; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return 0; } - lastSection = getCachedSection(lastChunkSections, cy); } if (lastSection == null) { return 0; @@ -447,21 +492,24 @@ public abstract class MappedFaweQueue extends FaweQueue { int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return 0; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return 0; } - lastSection = getCachedSection(lastChunkSections, cy); } - if (lastSection == null) { return 0; } @@ -473,21 +521,24 @@ public abstract class MappedFaweQueue extends FaweQueue { int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return 0; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return 0; } - lastSection = getCachedSection(lastChunkSections, cy); } - if (lastSection == null) { return 0; } @@ -499,21 +550,24 @@ public abstract class MappedFaweQueue extends FaweQueue { int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return 0; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return 0; } - lastSection = getCachedSection(lastChunkSections, cy); } - if (lastSection == null) { return 0; } @@ -537,24 +591,69 @@ public abstract class MappedFaweQueue extends FaweQueue { int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return 0; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return 0; } - lastSection = getCachedSection(lastChunkSections, cy); } - if (lastSection == null) { return 0; } return getCombinedId4Data(lastSection, x, y, z); } + + @Override + public int getBiomeId(int x, int z) throws FaweException.FaweChunkLoadException { + int cx = x >> 4; + int cz = z >> 4; + lastSectionY = -1; + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + } else { + lastChunkSections = null; + return 0; + } + } else if (lastChunk == null) { + return 0; + } + return getBiome(lastChunk, x, z); + } + + @Override + public CompoundTag getTileEntity(int x, int y, int z) throws FaweException.FaweChunkLoadException { + int cx = x >> 4; + int cz = z >> 4; + lastSectionY = -1; + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + } else { + lastChunkSections = null; + return null; + } + } else if (lastChunk == null) { + return null; + } + return getTileEntity(lastChunk, x, y, z); + } } 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 90837a73..5365067c 100644 --- a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java @@ -3,17 +3,15 @@ package com.boydti.fawe.example; import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweChunk; -import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.TaskManager; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.world.World; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.UUID; -public abstract class NMSMappedFaweQueue extends MappedFaweQueue { +public abstract class NMSMappedFaweQueue extends MappedFaweQueue { private final int maxY; @@ -60,10 +58,13 @@ public abstract class NMSMappedFaweQueue ex @Override public void end(FaweChunk chunk) { super.end(chunk); - if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) { + if (Settings.IMP.LIGHTING.MODE == 0) { sendChunk(chunk); return; } + if (!Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) { + sendChunk(chunk); + } if (Settings.IMP.LIGHTING.MODE == 2) { relighter.addChunk(chunk.getX(), chunk.getZ(), null, chunk.getBitMask()); return; @@ -90,7 +91,7 @@ public abstract class NMSMappedFaweQueue ex } if (relight) { relighter.addChunk(chunk.getX(), chunk.getZ(), fix, chunk.getBitMask()); - } else { + } else if (Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) { sendChunk(chunk); } } @@ -148,19 +149,23 @@ public abstract class NMSMappedFaweQueue ex int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return; } - lastSection = getCachedSection(lastChunkSections, cy); } if (lastSection == null) { return; @@ -172,19 +177,23 @@ public abstract class NMSMappedFaweQueue ex int cx = x >> 4; int cz = z >> 4; int cy = y >> 4; - if (cx != lastChunkX || cz != lastChunkZ) { - lastChunkX = cx; - lastChunkZ = cz; - if (!ensureChunkLoaded(cx, cz)) { + if (cx != lastSectionX || cz != lastSectionZ) { + lastSectionX = cx; + lastSectionZ = cz; + lastChunk = ensureChunkLoaded(cx, cz); + if (lastChunk != null) { + lastChunkSections = getSections(lastChunk); + lastSection = getCachedSection(lastChunkSections, cy); + } else { + lastChunkSections = null; return; } - lastChunkSections = getCachedSections(getWorld(), cx, cz); - lastSection = getCachedSection(lastChunkSections, cy); - } else if (cy != lastChunkY) { - if (lastChunkSections == null) { + } else if (cy != lastSectionY) { + if (lastChunkSections != null) { + lastSection = getCachedSection(lastChunkSections, cy); + } else { return; } - lastSection = getCachedSection(lastChunkSections, cy); } if (lastSection == null) { return; @@ -199,24 +208,4 @@ public abstract class NMSMappedFaweQueue ex public abstract void refreshChunk(FaweChunk fs); public abstract CharFaweChunk getPrevious(CharFaweChunk fs, CHUNKSECTION sections, Map tiles, Collection[] entities, Set createdEntities, boolean all) throws Exception; - - public abstract CompoundTag getTileEntity(CHUNK chunk, int x, int y, int z); - - public abstract CHUNK getChunk(WORLD world, int x, int z); - - private CHUNK lastChunk; - - @Override - public CompoundTag getTileEntity(int x, int y, int z) throws FaweException.FaweChunkLoadException { - if (y < 0 || y > maxY) { - return null; - } - int cx = x >> 4; - int cz = z >> 4; - lastChunk = getChunk(getWorld(), cx, cz); - if (lastChunk == null) { - return null; - } - return getTileEntity(lastChunk, x, y, z); - } } diff --git a/core/src/main/java/com/boydti/fawe/example/NMSRelighter.java b/core/src/main/java/com/boydti/fawe/example/NMSRelighter.java index d8772722..94ed4590 100644 --- a/core/src/main/java/com/boydti/fawe/example/NMSRelighter.java +++ b/core/src/main/java/com/boydti/fawe/example/NMSRelighter.java @@ -5,6 +5,8 @@ import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.IntegerTrio; import com.boydti.fawe.util.MathMan; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; @@ -14,15 +16,14 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; public class NMSRelighter implements Relighter{ private final NMSMappedFaweQueue queue; private final Map skyToRelight; - private final Map> lightQueue; + private final Map> lightQueue; private final Object present = new Object(); - private final HashMap chunksToSend; + private final Map chunksToSend; private final int maxY; private volatile boolean relighting = false; @@ -33,9 +34,9 @@ public class NMSRelighter implements Relighter{ public NMSRelighter(NMSMappedFaweQueue queue) { this.queue = queue; - this.skyToRelight = new ConcurrentHashMap<>(); - this.lightQueue = new ConcurrentHashMap<>(); - chunksToSend = new HashMap<>(); + this.skyToRelight = new Long2ObjectOpenHashMap<>(); + this.lightQueue = new Long2ObjectOpenHashMap<>(); + this.chunksToSend = new Long2ObjectOpenHashMap<>(); this.maxY = queue.getMaxY(); } @@ -63,7 +64,6 @@ public class NMSRelighter implements Relighter{ Iterator> iter = skyToRelight.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); - iter.remove(); RelightSkyEntry chunk = entry.getValue(); long pair = entry.getKey(); Integer existing = chunksToSend.get(pair); @@ -71,10 +71,11 @@ public class NMSRelighter implements Relighter{ queue.ensureChunkLoaded(chunk.x, chunk.z); Object sections = queue.getCachedSections(queue.getWorld(), chunk.x, chunk.z); queue.removeLighting(sections, FaweQueue.RelightMode.ALL, queue.hasSky()); + iter.remove(); } } - public void updateBlockLight(Map> map) { + public void updateBlockLight(Map> map) { int size = map.size(); if (size == 0) { return; @@ -84,17 +85,16 @@ public class NMSRelighter implements Relighter{ Map visited = new HashMap<>(); Map removalVisited = new HashMap<>(); - Iterator>> iter = map.entrySet().iterator(); + Iterator>> iter = map.entrySet().iterator(); while (iter.hasNext() && size-- > 0) { - Map.Entry> entry = iter.next(); - iter.remove(); + Map.Entry> entry = iter.next(); long index = entry.getKey(); - Map blocks = entry.getValue(); + Map blocks = entry.getValue(); int chunkX = MathMan.unpairIntX(index); int chunkZ = MathMan.unpairIntY(index); int bx = chunkX << 4; int bz = chunkZ << 4; - for (short blockHash : blocks.keySet()) { + for (int blockHash : blocks.keySet()) { int x = (blockHash >> 12 & 0xF) + bx; int y = (blockHash & 0xFF); int z = (blockHash >> 8 & 0xF) + bz; @@ -114,6 +114,7 @@ public class NMSRelighter implements Relighter{ } } } + iter.remove(); } while (!lightRemovalQueue.isEmpty()) { @@ -192,12 +193,12 @@ public class NMSRelighter implements Relighter{ public void addLightUpdate(int x, int y, int z) { long index = MathMan.pairInt((int) x >> 4, (int) z >> 4); - Map currentMap = lightQueue.get(index); + Map currentMap = lightQueue.get(index); if (currentMap == null) { - currentMap = new ConcurrentHashMap<>(8, 0.9f, 1); + currentMap = new Int2ObjectOpenHashMap<>(); this.lightQueue.put(index, currentMap); } - currentMap.put(MathMan.tripleBlockCoord(x, y, z), present); + currentMap.put((int) MathMan.tripleBlockCoord(x, y, z), present); } public synchronized void fixLightingSafe(boolean sky) { @@ -222,10 +223,10 @@ public class NMSRelighter implements Relighter{ Map.Entry entry = iter.next(); long pair = entry.getKey(); int bitMask = entry.getValue(); - iter.remove(); int x = MathMan.unpairIntX(pair); int z = MathMan.unpairIntY(pair); queue.sendChunk(x, z, bitMask); + iter.remove(); } } @@ -239,9 +240,9 @@ public class NMSRelighter implements Relighter{ Iterator> iter = skyToRelight.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); - iter.remove(); chunksToSend.put(entry.getKey(), entry.getValue().bitmask); chunksList.add(entry.getValue()); + iter.remove(); } Collections.sort(chunksList); int size = chunksList.size(); @@ -312,7 +313,6 @@ public class NMSRelighter implements Relighter{ int brightness = MathMan.unpair16y(pair); if (brightness > 1 && (brightness != 15 || opacity != 15)) { addLightUpdate(bx + x, y, bz + z); -// lightBlock(bx + x, y, bz + z, brightness); } switch (value) { case 0: diff --git a/core/src/main/java/com/boydti/fawe/example/NullFaweChunk.java b/core/src/main/java/com/boydti/fawe/example/NullFaweChunk.java index b4423736..0fef349a 100644 --- a/core/src/main/java/com/boydti/fawe/example/NullFaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/example/NullFaweChunk.java @@ -11,6 +11,7 @@ import java.util.Set; import java.util.UUID; public class NullFaweChunk extends FaweChunk { + public static final NullFaweChunk INSTANCE = new NullFaweChunk(null, 0 ,0); /** * A FaweSections object represents a chunk and the blocks that you wish to change in it. * @@ -32,6 +33,11 @@ public class NullFaweChunk extends FaweChunk { return null; } + @Override + public byte[] getBiomeArray() { + return new byte[256]; + } + @Override public int getBitMask() { return 0; @@ -92,6 +98,11 @@ public class NullFaweChunk extends FaweChunk { } + @Override + public void setBiome(int x, int z, byte biome) { + + } + @Override public FaweChunk copy(boolean shallow) { return this; diff --git a/core/src/main/java/com/boydti/fawe/example/WeakFaweQueueMap.java b/core/src/main/java/com/boydti/fawe/example/WeakFaweQueueMap.java index e5eed3e3..3a71d5e9 100644 --- a/core/src/main/java/com/boydti/fawe/example/WeakFaweQueueMap.java +++ b/core/src/main/java/com/boydti/fawe/example/WeakFaweQueueMap.java @@ -6,13 +6,13 @@ import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.SetQueue; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorCompletionService; public class WeakFaweQueueMap implements IFaweQueueMap { @@ -23,12 +23,14 @@ public class WeakFaweQueueMap implements IFaweQueueMap { this.parent = parent; } - /** - * Map of chunks in the queue - */ - public ConcurrentHashMap> blocks = new ConcurrentHashMap>(8, 0.9f, 1) { + public final Long2ObjectOpenHashMap> blocks = new Long2ObjectOpenHashMap>() { @Override public Reference put(Long key, Reference value) { + return put((long) key, value); + } + + @Override + public Reference put(long key, Reference value) { if (parent.getProgressTask() != null) { try { parent.getProgressTask().run(FaweQueue.ProgressType.QUEUE, size() + 1); @@ -36,7 +38,9 @@ public class WeakFaweQueueMap implements IFaweQueueMap { e.printStackTrace(); } } - return super.put(key, value); + synchronized (this) { + return super.put(key, value); + } } }; @@ -142,83 +146,83 @@ public class WeakFaweQueueMap implements IFaweQueueMap { @Override public boolean next(int amount, ExecutorCompletionService pool, long time) { - try { - boolean skip = parent.getStage() == SetQueue.QueueStage.INACTIVE; - int added = 0; - Iterator>> iter = blocks.entrySet().iterator(); - if (amount == 1) { - long start = System.currentTimeMillis(); - do { - if (iter.hasNext()) { - Map.Entry> entry = iter.next(); - Reference chunkReference = entry.getValue(); - FaweChunk chunk = chunkReference.get(); - if (skip && chunk == lastWrappedChunk) { - continue; - } - iter.remove(); - if (chunk != null) { - parent.start(chunk); - chunk.call(); - parent.end(chunk); + synchronized (blocks) { + try { + boolean skip = parent.getStage() == SetQueue.QueueStage.INACTIVE; + int added = 0; + Iterator>> iter = blocks.entrySet().iterator(); + if (amount == 1) { + long start = System.currentTimeMillis(); + do { + if (iter.hasNext()) { + Map.Entry> entry = iter.next(); + Reference chunkReference = entry.getValue(); + FaweChunk chunk = chunkReference.get(); + if (skip && chunk == lastWrappedChunk) { + continue; + } + iter.remove(); + if (chunk != null) { + parent.start(chunk); + chunk.call(); + parent.end(chunk); + } else { + Fawe.debug("Skipped modifying chunk due to low memory (3)"); + } } else { - Fawe.debug("Skipped modifying chunk due to low memory (3)"); + break; } + } while (System.currentTimeMillis() - start < time); + return !blocks.isEmpty(); + } + boolean result = true; + // amount = 8; + for (int i = 0; i < amount && (result = iter.hasNext());) { + Map.Entry> item = iter.next(); + Reference chunkReference = item.getValue(); + FaweChunk chunk = chunkReference.get(); + if (skip && chunk == lastWrappedChunk) { + continue; + } + iter.remove(); + if (chunk != null) { + parent.start(chunk); + pool.submit(chunk); + added++; + i++; } else { - break; + Fawe.debug("Skipped modifying chunk due to low memory (4)"); } - } while (System.currentTimeMillis() - start < time); - return !blocks.isEmpty(); - } - boolean result = true; - // amount = 8; - for (int i = 0; i < amount && (result = iter.hasNext()); i++, added++) { - Map.Entry> item = iter.next(); - Reference chunkReference = item.getValue(); - FaweChunk chunk = chunkReference.get(); - if (skip && chunk == lastWrappedChunk) { - i--; - added--; - continue; } - iter.remove(); - if (chunk != null) { - parent.start(chunk); - pool.submit(chunk); - } else { - Fawe.debug("Skipped modifying chunk due to low memory (4)"); - i--; - added--; - } - } - // if result, then submitted = amount - if (result) { - long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < time && result) { - if (result = iter.hasNext()) { - Map.Entry> item = iter.next(); - Reference chunkReference = item.getValue(); - FaweChunk chunk = chunkReference.get(); - if (skip && chunk == lastWrappedChunk) { - continue; - } - iter.remove(); - if (chunk != null) { - parent.start(chunk); - pool.submit(chunk); - FaweChunk fc = ((FaweChunk) pool.take().get()); - parent.end(fc); + // if result, then submitted = amount + if (result) { + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < time && result) { + if (result = iter.hasNext()) { + Map.Entry> item = iter.next(); + Reference chunkReference = item.getValue(); + FaweChunk chunk = chunkReference.get(); + if (skip && chunk == lastWrappedChunk) { + continue; + } + iter.remove(); + if (chunk != null) { + parent.start(chunk); + pool.submit(chunk); + FaweChunk fc = ((FaweChunk) pool.take().get()); + parent.end(fc); + } } } } + for (int i = 0; i < added; i++) { + FaweChunk fc = ((FaweChunk) pool.take().get()); + parent.end(fc); + } + } catch (Throwable e) { + e.printStackTrace(); } - for (int i = 0; i < added; i++) { - FaweChunk fc = ((FaweChunk) pool.take().get()); - parent.end(fc); - } - } catch (Throwable e) { - e.printStackTrace(); + return !blocks.isEmpty(); } - return !blocks.isEmpty(); } } 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 index e4dd0c3c..51773078 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java @@ -10,7 +10,6 @@ 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; @@ -241,9 +240,9 @@ public class MCAChunk extends FaweChunk { } @Override - public void setBiome(int x, int z, BaseBiome biome) { + public void setBiome(int x, int z, byte biome) { modified = true; - biomes[x + (z << 4)] = (byte) biome.getId();; + biomes[x + (z << 4)] = biome; } @Override @@ -292,6 +291,11 @@ public class MCAChunk extends FaweChunk { return id << 4; } + @Override + public byte[] getBiomeArray() { + return this.biomes; + } + @Override public Set getEntityRemoves() { return new HashSet<>(); diff --git a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java index 557dc0a4..8be99df1 100644 --- a/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java +++ b/core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAQueue.java @@ -41,6 +41,32 @@ public class MCAQueue extends NMSMappedFaweQueue implements Callable { return ids; } + public abstract byte[] getBiomeArray(); + public char[][] getCombinedIdArrays() { char[][] ids = new char[HEIGHT >> 4][]; for (int y = 0; y < HEIGHT >> 4; y++) { @@ -272,7 +274,11 @@ public abstract class FaweChunk implements Callable { */ public abstract CompoundTag getTile(int x, int y, int z); - public abstract void setBiome(final int x, final int z, final BaseBiome biome); + public void setBiome(final int x, final int z, final BaseBiome biome) { + setBiome(x, z, (byte) biome.getId()); + } + + public abstract void setBiome(final int x, final int z, final byte biome); /** * Spend time now so that the chunk can be more efficiently dispatched later
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 363de060..4983024f 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java @@ -281,8 +281,6 @@ public abstract class FaweQueue { } } - public abstract boolean isChunkLoaded(final int x, final int z); - @Deprecated public boolean regenerateChunk(int x, int z) { return regenerateChunk(x, z, null, null); @@ -349,6 +347,8 @@ public abstract class FaweQueue { return getCombinedId4Data(x, y, z) != 0; } + public abstract int getBiomeId(int x, int z) throws FaweException.FaweChunkLoadException; + public abstract int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException; public abstract int getCachedCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException; diff --git a/core/src/main/java/com/boydti/fawe/object/HistoryExtent.java b/core/src/main/java/com/boydti/fawe/object/HistoryExtent.java index 32e607d0..8cd547ad 100644 --- a/core/src/main/java/com/boydti/fawe/object/HistoryExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/HistoryExtent.java @@ -6,6 +6,7 @@ import com.boydti.fawe.object.exception.FaweException; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; @@ -15,6 +16,7 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; @@ -133,6 +135,17 @@ public class HistoryExtent extends AbstractDelegateExtent { return newList; } + @Override + public boolean setBiome(Vector2D position, BaseBiome newBiome) { + BaseBiome oldBiome = this.getBiome(position); + if (oldBiome.getId() != newBiome.getId()) { + this.changeSet.addBiomeChange(position.getBlockX(), position.getBlockZ(), oldBiome, newBiome); + return extent.setBiome(position, newBiome); + } else { + return false; + } + } + private class TrackedEntity implements Entity { private final Entity entity; diff --git a/core/src/main/java/com/boydti/fawe/object/NullChangeSet.java b/core/src/main/java/com/boydti/fawe/object/NullChangeSet.java index df0dcf6d..44afb47d 100644 --- a/core/src/main/java/com/boydti/fawe/object/NullChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/NullChangeSet.java @@ -5,6 +5,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.history.change.Change; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.ArrayList; import java.util.Iterator; @@ -47,6 +48,11 @@ public class NullChangeSet extends FaweChangeSet { } + @Override + public void addBiomeChange(int x, int z, BaseBiome from, BaseBiome to) { + + } + @Override public void addChangeTask(FaweQueue queue) { diff --git a/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrushTool.java b/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrushTool.java index 41ca5941..688c53ad 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrushTool.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/DoubleActionBrushTool.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.brush; +import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.extent.ResettableExtent; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; @@ -176,7 +177,7 @@ public class DoubleActionBrushTool implements DoubleActionTraceTool { target = player.getBlockTrace(getRange(), true); if (target == null) { - player.printError("No block in sight!"); + BBC.NO_BLOCK.send(player); return true; } @@ -216,7 +217,7 @@ public class DoubleActionBrushTool implements DoubleActionTraceTool { try { brush.build(action, editSession, target, material, size); } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); + player.printError("Max blocks change limit reached."); // Never happens } finally { if (bag != null) { bag.flushChanges(); diff --git a/core/src/main/java/com/boydti/fawe/object/brush/ErodeBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/ErodeBrush.java index cd450ca4..4e10bfdf 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/ErodeBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/ErodeBrush.java @@ -12,6 +12,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.function.pattern.Pattern; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.util.Map; public class ErodeBrush implements DoubleActionBrush { @@ -130,7 +131,7 @@ public class ErodeBrush implements DoubleActionBrush { } private void erosionIteration(int brushSize, int brushSizeSquared, int erodeFaces, FaweClipboard current, FaweClipboard target) { - Map frequency = Maps.newHashMap(); + Int2ObjectOpenHashMap frequency = new Int2ObjectOpenHashMap<>(); for (int x = -brushSize; x <= brushSize; x++) { for (int y = -brushSize; y <= brushSize; y++) { diff --git a/core/src/main/java/com/boydti/fawe/object/brush/HeightBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/HeightBrush.java index 50ea684a..031c27b8 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/HeightBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/HeightBrush.java @@ -42,12 +42,12 @@ public class HeightBrush implements DoubleActionBrush { @Override public void build(DoubleActionBrushTool.BrushAction action, EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException { - int size = (int) (action == DoubleActionBrushTool.BrushAction.PRIMARY ? sizeDouble : -sizeDouble); + int size = (int) sizeDouble; Mask mask = tool.getMask(); if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) { mask = null; } heightMap.setSize(size); - heightMap.apply(editSession, mask, position, size, rotation, yscale, true); + heightMap.apply(editSession, mask, position, size, rotation, action == DoubleActionBrushTool.BrushAction.PRIMARY ? yscale : -yscale, true); } } diff --git a/core/src/main/java/com/boydti/fawe/object/change/MutableBiomeChange.java b/core/src/main/java/com/boydti/fawe/object/change/MutableBiomeChange.java new file mode 100644 index 00000000..47d3a96b --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/change/MutableBiomeChange.java @@ -0,0 +1,36 @@ +package com.boydti.fawe.object.change; + +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.history.UndoContext; +import com.sk89q.worldedit.history.change.Change; +import com.sk89q.worldedit.world.biome.BaseBiome; + +public class MutableBiomeChange implements Change { + + private Vector2D pos; + private BaseBiome from; + private BaseBiome to; + public MutableBiomeChange() { + this.from = new BaseBiome(0); + this.to = new BaseBiome(0); + this.pos = new Vector2D(); + } + + public void setBiome(int x, int z, int from, int to) { + this.pos.x = x; + this.pos.z = z; + this.from.setId(from); + this.to.setId(to); + } + + @Override + public void undo(UndoContext context) throws WorldEditException { + context.getExtent().setBiome(pos, from); + } + + @Override + public void redo(UndoContext context) throws WorldEditException { + context.getExtent().setBiome(pos, to); + } +} diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/AbstractDelegateChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/AbstractDelegateChangeSet.java index 813797bd..43794735 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/AbstractDelegateChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/AbstractDelegateChangeSet.java @@ -12,6 +12,7 @@ import com.sk89q.worldedit.history.change.Change; import com.sk89q.worldedit.history.change.EntityCreate; import com.sk89q.worldedit.history.change.EntityRemove; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.Iterator; public class AbstractDelegateChangeSet extends FaweChangeSet { @@ -71,6 +72,11 @@ public class AbstractDelegateChangeSet extends FaweChangeSet { return parent.size(); } + @Override + public void addBiomeChange(int x, int z, BaseBiome from, BaseBiome to) { + parent.addBiomeChange(x, z, from, to); + } + @Override public void addTileCreate(CompoundTag tag) { parent.addTileCreate(tag); diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/CPUOptimizedChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/CPUOptimizedChangeSet.java index c4b9e870..599bfc75 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/CPUOptimizedChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/CPUOptimizedChangeSet.java @@ -8,6 +8,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.history.change.Change; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.ArrayList; import java.util.Iterator; @@ -56,6 +57,11 @@ public class CPUOptimizedChangeSet extends FaweChangeSet { throw new UnsupportedOperationException("Invalid mode"); } + @Override + public void addBiomeChange(int x, int z, BaseBiome from, BaseBiome to) { + throw new UnsupportedOperationException("Invalid mode"); + } + @Override public void addTileCreate(CompoundTag tag) { throw new UnsupportedOperationException("Invalid mode"); diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java index 8d0eb534..ca23dfcf 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/DiskStorageHistory.java @@ -13,13 +13,13 @@ import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.world.World; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -34,6 +34,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet { private UUID uuid; private File bdFile; + private File bioFile; private File nbtfFile; private File nbttFile; private File entfFile; @@ -49,6 +50,8 @@ public class DiskStorageHistory extends FaweStreamChangeSet { * { short rel x, short rel z, unsigned byte y, short combinedFrom, short combinedTo } */ private OutputStream osBD; + // biome + private OutputStream osBIO; // NBT From private NBTOutputStream osNBTF; // NBT To @@ -117,6 +120,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet { entfFile = new File(folder, index + ".entf"); enttFile = new File(folder, index + ".entt"); bdFile = new File(folder, index + ".bd"); + bioFile = new File(folder, index + ".bio"); } private void init(UUID uuid, int i) { @@ -165,12 +169,16 @@ public class DiskStorageHistory extends FaweStreamChangeSet { public boolean flush() { super.flush(); synchronized (this) { - boolean flushed = osBD != null || osNBTF != null || osNBTT != null && osENTCF != null || osENTCT != null; + boolean flushed = osBD != null || osBIO != null || osNBTF != null || osNBTT != null && osENTCF != null || osENTCT != null; try { if (osBD != null) { osBD.close(); osBD = null; } + if (osBIO != null) { + osBIO.close(); + osBIO = null; + } if (osNBTF != null) { osNBTF.close(); osNBTF = null; @@ -210,6 +218,9 @@ public class DiskStorageHistory extends FaweStreamChangeSet { if (bdFile.exists()) { total += bdFile.length(); } + if (bioFile.exists()) { + total += bioFile.length(); + } if (nbtfFile.exists()) { total += entfFile.length(); } @@ -239,6 +250,19 @@ public class DiskStorageHistory extends FaweStreamChangeSet { } } + @Override + public OutputStream getBiomeOS() throws IOException { + if (osBIO != null) { + return osBIO; + } + synchronized (this) { + bioFile.getParentFile().mkdirs(); + bioFile.createNewFile(); + osBIO = getCompressedOS(new FileOutputStream(bioFile)); + return osBIO; + } + } + @Override public NBTOutputStream getEntityCreateOS() throws IOException { if (osENTCT != null) { @@ -293,6 +317,15 @@ public class DiskStorageHistory extends FaweStreamChangeSet { return is; } + @Override + public InputStream getBiomeIS() throws IOException { + if (!bioFile.exists()) { + return null; + } + InputStream is = MainUtil.getCompressedIS(new FileInputStream(bioFile)); + return is; + } + @Override public NBTInputStream getEntityCreateIS() throws IOException { if (!enttFile.exists()) { @@ -426,25 +459,25 @@ public class DiskStorageHistory extends FaweStreamChangeSet { } } - public HashMap getBlocks() { - HashMap map = new HashMap<>(); + public Map getBlocks() { + Int2ObjectOpenHashMap map = new Int2ObjectOpenHashMap<>(); for (int i = 0; i < blocks.length; i++) { if (blocks[i] != 0) { - map.put(i, blocks[i]); + map.put(i, (Integer) blocks[i]); } } return map; } public Map getPercents() { - HashMap map = getBlocks(); + Map map = getBlocks(); int count = getSize(); - HashMap newMap = new HashMap(); + Int2ObjectOpenHashMap newMap = new Int2ObjectOpenHashMap(); for (Map.Entry entry : map.entrySet()) { int id = entry.getKey(); int changes = entry.getValue(); double percent = ((changes * 1000l) / count) / 10d; - newMap.put(id, percent); + newMap.put(id, (Double) percent); } return newMap; } 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 23627f4c..386ee57c 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 @@ -23,6 +23,7 @@ import com.sk89q.worldedit.history.change.EntityCreate; import com.sk89q.worldedit.history.change.EntityRemove; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -119,6 +120,7 @@ public abstract class FaweChangeSet implements ChangeSet { public abstract void addTileRemove(CompoundTag tag); public abstract void addEntityRemove(CompoundTag tag); public abstract void addEntityCreate(CompoundTag tag); + public abstract void addBiomeChange(int x, int z, BaseBiome from, BaseBiome to); public Iterator getIterator(BlockBag blockBag, int mode, boolean redo) { return getIterator(redo); } @@ -227,79 +229,81 @@ public abstract class FaweChangeSet implements ChangeSet { int cz = previous.getZ(); int bx = cx << 4; int bz = cz << 4; - // Biome changes - { - // TODO - } - // Block changes - // Current blocks -// char[][] currentIds = next.getCombinedIdArrays(); - // Previous blocks in modified sections (i.e. we skip sections that weren't modified) -// char[][] previousIds = previous.getCombinedIdArrays(); - for (int layer = 0; layer < layers; layer++) { - char[] currentLayer = next.getIdArray(layer); - char[] previousLayer = previous.getIdArray(layer); - if (currentLayer == null) { - continue; - } - int startY = layer << 4; - for (int y = 0; y < 16; y++) { - short[][] i1 = FaweCache.CACHE_J[y]; - int yy = y + startY; + synchronized (FaweChangeSet.this) { + // Biome changes + if (previous.getBiomeArray() != null) { + byte[] previousBiomes = previous.getBiomeArray(); + byte[] nextBiomes = next.getBiomeArray(); + int index = 0; for (int z = 0; z < 16; z++) { - int zz = z + bz; - short[] i2 = i1[z]; + int zz = bz + z; for (int x = 0; x < 16; x++) { - int xx = x + bx; - int index = i2[x]; - int combinedIdCurrent = currentLayer[index]; - switch (combinedIdCurrent) { - case 0: - continue; - case 1: - combinedIdCurrent = 0; - default: - char combinedIdPrevious = previousLayer != null ? previousLayer[index] : 0; - if (combinedIdCurrent != combinedIdPrevious) { - synchronized (FaweChangeSet.this) { + byte idFrom = previousBiomes[index]; + byte idTo = nextBiomes[index]; + if (idFrom != idTo && idTo != 0) { + addBiomeChange(bx + x, zz, FaweCache.getBiome(idFrom & 0xFF), FaweCache.getBiome(idTo & 0xFF)); + } + index++; + } + } + // TODO + } + // Block changes + for (int layer = 0; layer < layers; layer++) { + char[] currentLayer = next.getIdArray(layer); + char[] previousLayer = previous.getIdArray(layer); + if (currentLayer == null) { + continue; + } + int startY = layer << 4; + for (int y = 0; y < 16; y++) { + short[][] i1 = FaweCache.CACHE_J[y]; + int yy = y + startY; + 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: + continue; + case 1: + combinedIdCurrent = 0; + default: + char combinedIdPrevious = previousLayer != null ? previousLayer[index] : 0; + if (combinedIdCurrent != combinedIdPrevious) { add(xx, yy, zz, combinedIdPrevious, combinedIdCurrent); } - } + } } } } } - } - // Tile changes - { - // Tiles created - Map tiles = next.getTiles(); - for (Map.Entry entry : tiles.entrySet()) { - synchronized (FaweChangeSet.this) { + // Tile changes + { + // Tiles created + Map tiles = next.getTiles(); + for (Map.Entry entry : tiles.entrySet()) { addTileCreate(entry.getValue()); } - } - // Tiles removed - tiles = previous.getTiles(); - for (Map.Entry entry : tiles.entrySet()) { - synchronized (FaweChangeSet.this) { + // Tiles removed + tiles = previous.getTiles(); + for (Map.Entry entry : tiles.entrySet()) { addTileRemove(entry.getValue()); } } - } - // Entity changes - { - // Entities created - Set entities = next.getEntities(); - for (CompoundTag entityTag : entities) { - synchronized (FaweChangeSet.this) { + // Entity changes + { + // Entities created + Set entities = next.getEntities(); + for (CompoundTag entityTag : entities) { addEntityCreate(entityTag); } - } - // Entities removed - entities = previous.getEntities(); - for (CompoundTag entityTag : entities) { - synchronized (FaweChangeSet.this) { + // Entities removed + entities = previous.getEntities(); + for (CompoundTag entityTag : entities) { addEntityRemove(entityTag); } } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java index 005d3ea5..6582b3d3 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java @@ -3,6 +3,7 @@ package com.boydti.fawe.object.changeset; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweInputStream; import com.boydti.fawe.object.FaweOutputStream; +import com.boydti.fawe.object.change.MutableBiomeChange; import com.boydti.fawe.object.change.MutableBlockChange; import com.boydti.fawe.object.change.MutableEntityChange; import com.boydti.fawe.object.change.MutableFullBlockChange; @@ -15,12 +16,14 @@ import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.history.change.Change; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BaseBiome; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; +import java.util.NoSuchElementException; public abstract class FaweStreamChangeSet extends FaweChangeSet { @@ -266,12 +269,14 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { } public abstract OutputStream getBlockOS(int x, int y, int z) throws IOException; + public abstract OutputStream getBiomeOS() throws IOException; public abstract NBTOutputStream getEntityCreateOS() throws IOException; public abstract NBTOutputStream getEntityRemoveOS() throws IOException; public abstract NBTOutputStream getTileCreateOS() throws IOException; public abstract NBTOutputStream getTileRemoveOS() throws IOException; public abstract InputStream getBlockIS() throws IOException; + public abstract InputStream getBiomeIS() throws IOException; public abstract NBTInputStream getEntityCreateIS() throws IOException; public abstract NBTInputStream getEntityRemoveIS() throws IOException; public abstract NBTInputStream getTileCreateIS() throws IOException; @@ -312,10 +317,32 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { } } + @Override + public void addBiomeChange(int x, int z, BaseBiome from, BaseBiome to) { + blockSize++; + try { + OutputStream os = getBiomeOS(); + os.write((byte) (x >> 24)); + os.write((byte) (x >> 16)); + os.write((byte) (x >> 8)); + os.write((byte) (x)); + os.write((byte) (z >> 24)); + os.write((byte) (z >> 16)); + os.write((byte) (z >> 8)); + os.write((byte) (z)); + os.write(from.getId()); + os.write(to.getId()); + } + catch (Throwable e) { + MainUtil.handleError(e); + } + } + public void addTileCreate(CompoundTag tag) { if (tag == null) { return; } + blockSize++; try { NBTOutputStream nbtos = getTileCreateOS(); nbtos.writeTag(tag); @@ -328,6 +355,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { if (tag == null) { return; } + blockSize++; try { NBTOutputStream nbtos = getTileRemoveOS(); nbtos.writeTag(tag); @@ -340,6 +368,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { if (tag == null) { return; } + blockSize++; try { NBTOutputStream nbtos = getEntityRemoveOS(); nbtos.writeTag(tag); @@ -352,6 +381,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { if (tag == null) { return; } + blockSize++; try { NBTOutputStream nbtos = getEntityCreateOS(); nbtos.writeTag(tag); @@ -376,32 +406,83 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { idDel.readCombined(is, change, dir); return change; } catch (EOFException ignoreOEF) { - return null; } catch (Exception e) { e.printStackTrace(); MainUtil.handleError(e); } + try { + is.close(); + } catch (IOException e) { + MainUtil.handleError(e); + } return null; } @Override public boolean hasNext() { - if (last != null) { - return true; - } else if ((last = read()) != null) { - return true; + return last != null || ((last = read()) != null); + } + + @Override + public MutableBlockChange next() { + MutableBlockChange tmp = last; + if (tmp == null) { + tmp = read(); + } + last = null; + return tmp; + } + + @Override + public void remove() { + throw new IllegalArgumentException("CANNOT REMOVE"); + } + }; + } + + public Iterator getBiomeIterator(final boolean dir) throws IOException { + final InputStream is = getBiomeIS(); + if (is == null) { + return new ArrayList().iterator(); + } + final MutableBiomeChange change = new MutableBiomeChange(); + return new Iterator() { + private MutableBiomeChange last = new MutableBiomeChange(); + public MutableBiomeChange read() { + try { + int int1 = is.read(); + if (int1 != -1) { + int x = ((int1 << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0)); + int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0)); + int from = is.read(); + int to = is.read(); + change.setBiome(x, z, from, to); + return change; + } + } catch (EOFException ignoreOEF) { + } catch (Exception e) { + e.printStackTrace(); + MainUtil.handleError(e); } try { is.close(); } catch (IOException e) { MainUtil.handleError(e); } - return false; + return null; } @Override - public MutableBlockChange next() { - MutableBlockChange tmp = last; + public boolean hasNext() { + return last != null || ((last = read()) != null); + } + + @Override + public MutableBiomeChange next() { + MutableBiomeChange tmp = last; + if (tmp == null) { + tmp = read(); + } last = null; return tmp; } @@ -441,8 +522,13 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { idDel.readCombined(is, change, dir); return change; } catch (EOFException ignoreOEF) { - return null; } catch (Exception e) { + e.printStackTrace(); + MainUtil.handleError(e); + } + try { + is.close(); + } catch (IOException e) { MainUtil.handleError(e); } return null; @@ -450,23 +536,15 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { @Override public boolean hasNext() { - if (last == null) { - last = read(); - } - if (last != null) { - return true; - } - try { - is.close(); - } catch (IOException e) { - MainUtil.handleError(e); - } - return false; + return last != null || ((last = read()) != null); } @Override public MutableFullBlockChange next() { MutableFullBlockChange tmp = last; + if (tmp == null) { + tmp = read(); + } last = null; return tmp; } @@ -485,36 +563,35 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { final MutableEntityChange change = new MutableEntityChange(null, create); try { return new Iterator() { - private CompoundTag last = read(); + private MutableEntityChange last = read(); - public CompoundTag read() { + public MutableEntityChange read() { try { - return (CompoundTag) is.readTag(); - } catch (Exception ignoreEOS) {} - return null; - } - - @Override - public boolean hasNext() { - if (last == null) { - last = read(); - } - if (last != null) { - return true; - } + CompoundTag tag = (CompoundTag) is.readTag(); + change.tag = tag; + return change; + } catch (Exception ignoreOEF) {} try { is.close(); } catch (IOException e) { MainUtil.handleError(e); } - return false; + return null; + } + + @Override + public boolean hasNext() { + return last != null || ((last = read()) != null); } @Override public MutableEntityChange next() { - change.tag = last; + MutableEntityChange tmp = last; + if (tmp == null) { + tmp = read(); + } last = null; - return change; + return tmp; } @Override @@ -535,36 +612,35 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { final MutableTileChange change = new MutableTileChange(null, create); try { return new Iterator() { - private CompoundTag last = read(); + private MutableTileChange last = read(); - public CompoundTag read() { + public MutableTileChange read() { try { - return (CompoundTag) is.readTag(); - } catch (Exception ignoreEOS) {} - return null; - } - - @Override - public boolean hasNext() { - if (last == null) { - last = read(); - } - if (last != null) { - return true; - } + CompoundTag tag = (CompoundTag) is.readTag(); + change.tag = tag; + return change; + } catch (Exception ignoreOEF) {} try { is.close(); } catch (IOException e) { MainUtil.handleError(e); } - return false; + return null; + } + + @Override + public boolean hasNext() { + return last != null || ((last = read()) != null); } @Override public MutableTileChange next() { - change.tag = last; + MutableTileChange tmp = last; + if (tmp == null) { + tmp = read(); + } last = null; - return change; + return tmp; } @Override @@ -589,8 +665,10 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { final Iterator blockChange = getBlockIterator(dir); + final Iterator biomeChange = getBiomeIterator(dir); + return new Iterator() { - Iterator[] iterators = new Iterator[]{tileCreate, tileRemove, entityCreate, entityRemove, blockChange}; + Iterator[] iterators = new Iterator[]{tileCreate, tileRemove, entityCreate, entityRemove, blockChange, biomeChange}; int i = 0; Iterator current = iterators[0]; @@ -613,7 +691,15 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { @Override public Change next() { - return current.next(); + try { + return current.next(); + } catch (Throwable ignore) { + if (i >= iterators.length - 1) { + throw new NoSuchElementException("End of iterator"); + } + current = iterators[++i]; + return next(); + } } }; } catch (Exception e) { diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java b/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java index 5ad7557c..5f3ae1c4 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/MemoryOptimizedHistory.java @@ -21,11 +21,14 @@ import java.io.OutputStream; */ public class MemoryOptimizedHistory extends FaweStreamChangeSet { - private int size = 0; private byte[][] ids; private FastByteArrayOutputStream idsStream; private FaweOutputStream idsStreamZip; + private byte[][] biomes; + private FastByteArrayOutputStream biomeStream; + private FaweOutputStream biomeStreamZip; + private byte[][] entC; private FastByteArrayOutputStream entCStream; private NBTOutputStream entCStreamZip; @@ -57,11 +60,16 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { try { if (idsStream != null) { idsStreamZip.close(); - size = idsStream.getSize(); ids = idsStream.toByteArrays(); idsStream = null; idsStreamZip = null; } + if (biomeStream != null) { + biomeStreamZip.close(); + biomes = biomeStream.toByteArrays(); + biomeStream = null; + biomeStreamZip = null; + } if (entCStream != null) { entCStreamZip.close(); entC = entCStream.toByteArrays(); @@ -125,6 +133,27 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet { } } + @Override + public InputStream getBiomeIS() throws IOException { + if (biomes == null) { + return null; + } + FaweInputStream result = MainUtil.getCompressedIS(new FastByteArraysInputStream(biomes)); + return result; + } + + @Override + public OutputStream getBiomeOS() throws IOException { + if (biomeStreamZip != null) { + return biomeStreamZip; + } + synchronized (this) { + biomeStream = new FastByteArrayOutputStream(Settings.IMP.HISTORY.BUFFER_SIZE); + biomeStreamZip = getCompressedOS(biomeStream); + return biomeStreamZip; + } + } + @Override public InputStream getBlockIS() throws IOException { if (ids == null) { diff --git a/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java b/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java index ff440533..55ef380f 100644 --- a/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java @@ -10,7 +10,6 @@ import com.sk89q.jnbt.DoubleTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.WorldEditException; @@ -85,10 +84,7 @@ public class FastWorldEditExtent extends AbstractDelegateExtent implements HasFa @Override public BaseBiome getBiome(final Vector2D position) { - if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) { - return EditSession.nullBiome; - } - return super.getBiome(position); + return FaweCache.CACHE_BIOME[queue.getBiomeId(position.getBlockX(), position.getBlockZ())]; } @Override diff --git a/core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java b/core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java index cf4fdaf6..0681444d 100644 --- a/core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java +++ b/core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java @@ -53,12 +53,11 @@ public class FuzzyRegion extends AbstractRegion { public Iterator iterator() { return new Iterator() { - private int index = -1; + private int index = set.nextSetBit(0); private BlockVector pos = new BlockVector(0, 0, 0); @Override public boolean hasNext() { - index = set.nextSetBit(index + 1); return index != -1; } @@ -71,6 +70,7 @@ public class FuzzyRegion extends AbstractRegion { pos.mutX(offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21)); pos.mutY(offsetY + b1); pos.mutZ(offsetZ + (((b4 + ((MathMan.unpair8y(b2)) << 8)) << 21) >> 21)); + index = set.nextSetBit(index + 1); return pos; } diff --git a/core/src/main/java/com/boydti/fawe/regions/general/plot/PlotTrim.java b/core/src/main/java/com/boydti/fawe/regions/general/plot/PlotTrim.java index 1d3b4e92..8a51cb9d 100644 --- a/core/src/main/java/com/boydti/fawe/regions/general/plot/PlotTrim.java +++ b/core/src/main/java/com/boydti/fawe/regions/general/plot/PlotTrim.java @@ -56,7 +56,7 @@ public class PlotTrim implements Listener { } public void setChunk(int x, int z) { - this.ids = originalQueue.getChunk(originalQueue, x, z).ids; + this.ids = ((MCAChunk) originalQueue.getFaweChunk(x, z)).ids; } @EventHandler 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 f70ae0ce..ca2509ab 100644 --- a/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java @@ -1,5 +1,7 @@ package com.boydti.fawe.util; +import com.boydti.fawe.config.Settings; +import com.boydti.fawe.example.Relighter; import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; @@ -7,6 +9,10 @@ import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.exception.FaweException; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BaseBiome; import java.io.File; import java.util.Collection; @@ -49,6 +55,11 @@ public class DelegateFaweQueue extends FaweQueue { parent.addEditSession(session); } + @Override + public World getWEWorld() { + return parent.getWEWorld(); + } + @Override public void setProgressTracker(RunnableVal2 progressTask) { parent.setProgressTracker(progressTask); @@ -89,6 +100,11 @@ public class DelegateFaweQueue extends FaweQueue { parent.setProgressTask(progressTask); } + @Override + public int getBiomeId(int x, int z) throws FaweException.FaweChunkLoadException { + return parent.getBiomeId(x, z); + } + @Override public void setChangeTask(RunnableVal2 changeTask) { parent.setChangeTask(changeTask); @@ -104,11 +120,26 @@ public class DelegateFaweQueue extends FaweQueue { parent.optimize(); } + @Override + public int setBlocks(CuboidRegion cuboid, int id, int data) { + return parent.setBlocks(cuboid, id, data); + } + @Override public boolean setBlock(int x, int y, int z, int id, int data) { return parent.setBlock(x, y, z, id, data); } + @Override + public boolean setBlock(int x, int y, int z, int id) { + return parent.setBlock(x, y, z, id); + } + + @Override + public boolean setBlock(int x, int y, int z, int id, int data, CompoundTag nbt) { + return parent.setBlock(x, y, z, id, data, nbt); + } + @Override public void setTile(int x, int y, int z, CompoundTag tag) { parent.setTile(x, y, z, tag); @@ -150,8 +181,24 @@ public class DelegateFaweQueue extends FaweQueue { } @Override - public boolean isChunkLoaded(int x, int z) { - return parent.isChunkLoaded(x, z); + public int getMaxY() { + return parent.getMaxY(); + } + + @Override + public void forEachBlockInChunk(int cx, int cz, RunnableVal2 onEach) { + parent.forEachBlockInChunk(cx, cz, onEach); + } + + @Override + public void forEachTileInChunk(int cx, int cz, RunnableVal2 onEach) { + parent.forEachTileInChunk(cx, cz, onEach); + } + + @Override + @Deprecated + public boolean regenerateChunk(int x, int z) { + return parent.regenerateChunk(x, z); } @Override @@ -179,6 +226,7 @@ public class DelegateFaweQueue extends FaweQueue { parent.sendBlockUpdate(blockMap, players); } + @Deprecated @Override public boolean next() { return parent.next(); @@ -209,6 +257,11 @@ public class DelegateFaweQueue extends FaweQueue { parent.addNotifyTask(x, z, runnable); } + @Override + public boolean hasBlock(int x, int y, int z) throws FaweException.FaweChunkLoadException { + return parent.hasBlock(x, y, z); + } + @Override public void addNotifyTask(Runnable runnable) { parent.addNotifyTask(runnable); @@ -224,6 +277,11 @@ public class DelegateFaweQueue extends FaweQueue { return parent.getCachedCombinedId4Data(x, y, z); } + @Override + public int getAdjacentLight(int x, int y, int z) { + return parent.getAdjacentLight(x, y, z); + } + @Override public boolean hasSky() { return parent.hasSky(); @@ -234,6 +292,11 @@ public class DelegateFaweQueue extends FaweQueue { return parent.getSkyLight(x, y, z); } + @Override + public int getLight(int x, int y, int z) { + return parent.getLight(x, y, z); + } + @Override public int getEmmittedLight(int x, int y, int z) { return parent.getEmmittedLight(x, y, z); @@ -249,23 +312,98 @@ public class DelegateFaweQueue extends FaweQueue { return parent.getCombinedId4Data(x, y, z, def); } + @Override + public int getCachedCombinedId4Data(int x, int y, int z, int def) { + return parent.getCachedCombinedId4Data(x, y, z, def); + } + @Override public int getCombinedId4DataDebug(int x, int y, int z, int def, EditSession session) { return parent.getCombinedId4DataDebug(x, y, z, def, session); } + @Override + public int getBrightness(int x, int y, int z) { + return parent.getBrightness(x, y, z); + } + + @Override + public int getOpacityBrightnessPair(int x, int y, int z) { + return parent.getOpacityBrightnessPair(x, y, z); + } + + @Override + public int getOpacity(int x, int y, int z) { + return parent.getOpacity(x, y, z); + } + @Override public int size() { return parent.size(); } + @Override + public boolean isEmpty() { + return parent.isEmpty(); + } + + @Override + public void flush() { + parent.flush(); + } + + @Override + public SetQueue.QueueStage getStage() { + return parent.getStage(); + } + + @Override + public void setStage(SetQueue.QueueStage stage) { + parent.setStage(stage); + } + + @Override + public void flush(int time) { + parent.flush(time); + } + @Override public void runTasks() { parent.runTasks(); } + @Override + public void addTask(Runnable whenFree) { + parent.addTask(whenFree); + } + @Override public boolean enqueue() { return parent.enqueue(); } + + @Override + public void dequeue() { + parent.dequeue(); + } + + @Override + public Relighter getRelighter() { + return parent.getRelighter(); + } + + @Override + public Settings getSettings() { + return parent.getSettings(); + } + + @Override + public void setSettings(Settings settings) { + parent.setSettings(settings); + } + + @Override + public void setWorld(String world) { + parent.setWorld(world); + } } diff --git a/core/src/main/java/com/boydti/fawe/util/WESubscriber.java b/core/src/main/java/com/boydti/fawe/util/WESubscriber.java deleted file mode 100644 index d03cafa4..00000000 --- a/core/src/main/java/com/boydti/fawe/util/WESubscriber.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.boydti.fawe.util; - -import com.sk89q.worldedit.event.extent.EditSessionEvent; -import com.sk89q.worldedit.util.eventbus.EventHandler.Priority; -import com.sk89q.worldedit.util.eventbus.Subscribe; - -public class WESubscriber { - - @Subscribe(priority = Priority.VERY_EARLY) - public void onEditSession(final EditSessionEvent event) {} -} diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index a5531a1c..480c5922 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -72,7 +72,6 @@ import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.ChangeSetExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.MaskingExtent; -import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.world.SurvivalModeExtent; import com.sk89q.worldedit.function.GroundFunction; @@ -92,7 +91,6 @@ import com.sk89q.worldedit.function.mask.RegionMask; import com.sk89q.worldedit.function.operation.ChangeSetExecutor; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.function.operation.OperationQueue; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Patterns; @@ -1543,6 +1541,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting public boolean canBypassAll(Region region, boolean get, boolean set) { if (wrapped) return false; FaweRegionExtent regionExtent = getRegionExtent(); + if (!(region instanceof CuboidRegion)) return false; if (regionExtent != null) { if (!(region instanceof CuboidRegion)) return false; Vector pos1 = region.getMinimumPoint(); @@ -1950,7 +1949,11 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting checkNotNull(dir); checkArgument(distance >= 1, "distance >= 1 required"); final Vector displace = dir.multiply(distance); - // Remove the original blocks + + final Vector size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); + final Vector to = region.getMinimumPoint(); + final ForwardExtentCopy copy = new ForwardExtentCopy(EditSession.this, region, EditSession.this, to); + final com.sk89q.worldedit.function.pattern.Pattern pattern = replacement != null ? new BlockPattern(replacement) : new BlockPattern(new BaseBlock(BlockID.AIR)); final BlockReplace remove = new BlockReplace(EditSession.this, pattern) { @Override @@ -1966,12 +1969,9 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting } }; - // Copy to a buffer so we don't destroy our original before we can copy all the blocks from it - final ForgetfulExtentBuffer buffer = new ForgetfulExtentBuffer(EditSession.this, new RegionMask(region)); - final ForwardExtentCopy copy = new ForwardExtentCopy(EditSession.this, region, buffer, region.getMinimumPoint()); + copy.setSourceFunction(remove); + copy.setRepetitions(1); copy.setTransform(new AffineTransform().translate(dir.multiply(distance))); - copy.setSourceFunction(remove); // Remove - copy.setRemovingEntities(true); Mask sourceMask = getSourceMask(); if (sourceMask != null) { new MaskTraverser(sourceMask).reset(EditSession.this); @@ -1981,13 +1981,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting if (!copyAir) { copy.setSourceMask(new ExistingBlockMask(EditSession.this)); } - - // Then we need to copy the buffer to the world - final BlockReplace replace = new BlockReplace(EditSession.this, buffer); - final RegionVisitor visitor = new RegionVisitor(buffer.asRegion(), replace); - - final OperationQueue operation = new OperationQueue(copy, visitor); - Operations.completeSmart(operation, new Runnable() { + Operations.completeSmart(copy, new Runnable() { @Override public void run() { EditSession.this.flushQueue(); diff --git a/core/src/main/java/com/sk89q/worldedit/Vector2D.java b/core/src/main/java/com/sk89q/worldedit/Vector2D.java new file mode 100644 index 00000000..fdc51a38 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/Vector2D.java @@ -0,0 +1,670 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit; + +import com.sk89q.worldedit.math.transform.AffineTransform; + +/** + * An immutable 2-dimensional vector. + */ +public class Vector2D { + public static final Vector2D ZERO = new Vector2D(0, 0); + public static final Vector2D UNIT_X = new Vector2D(1, 0); + public static final Vector2D UNIT_Z = new Vector2D(0, 1); + public static final Vector2D ONE = new Vector2D(1, 1); + + public double x, z; + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param z the Z coordinate + */ + public Vector2D(double x, double z) { + this.x = x; + this.z = z; + } + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param z the Z coordinate + */ + public Vector2D(int x, int z) { + this.x = (double) x; + this.z = (double) z; + } + + /** + * Construct an instance. + * + * @param x the X coordinate + * @param z the Z coordinate + */ + public Vector2D(float x, float z) { + this.x = (double) x; + this.z = (double) z; + } + + /** + * Copy another vector. + * + * @param other the other vector + */ + public Vector2D(Vector2D other) { + this.x = other.x; + this.z = other.z; + } + + /** + * Construct a new instance with X and Z coordinates set to 0. + * + *

One can also refer to a static {@link #ZERO}.

+ */ + public Vector2D() { + this.x = 0; + this.z = 0; + } + + /** + * Get the X coordinate. + * + * @return the x coordinate + */ + public double getX() { + return x; + } + + /** + * Get the X coordinate rounded. + * + * @return the x coordinate + */ + public int getBlockX() { + return (int) Math.round(x); + } + + /** + * Set the X coordinate. + * + * @param x the new X + * @return a new vector + */ + public Vector2D setX(double x) { + return new Vector2D(x, z); + } + + /** + * Set the X coordinate. + * + * @param x the new X + * @return a new vector + */ + public Vector2D setX(int x) { + return new Vector2D(x, z); + } + + /** + * Get the Z coordinate. + * + * @return the z coordinate + */ + public double getZ() { + return z; + } + + /** + * Get the Z coordinate rounded. + * + * @return the z coordinate + */ + public int getBlockZ() { + return (int) Math.round(z); + } + + /** + * Set the Z coordinate. + * + * @param z the new Z + * @return a new vector + */ + public Vector2D setZ(double z) { + return new Vector2D(x, z); + } + + /** + * Set the Z coordinate. + * + * @param z the new Z + * @return a new vector + */ + public Vector2D setZ(int z) { + return new Vector2D(x, z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public Vector2D add(Vector2D other) { + return new Vector2D(x + other.x, z + other.z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param x the value to add + * @param z the value to add + * @return a new vector + */ + public Vector2D add(double x, double z) { + return new Vector2D(this.x + x, this.z + z); + } + + /** + * Add another vector to this vector and return the result as a new vector. + * + * @param x the value to add + * @param z the value to add + * @return a new vector + */ + public Vector2D add(int x, int z) { + return new Vector2D(this.x + x, this.z + z); + } + + /** + * Add a list of vectors to this vector and return the + * result as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector2D add(Vector2D... others) { + double newX = x, newZ = z; + + for (Vector2D other : others) { + newX += other.x; + newZ += other.z; + } + + return new Vector2D(newX, newZ); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param other the other vector + * @return a new vector + */ + public Vector2D subtract(Vector2D other) { + return new Vector2D(x - other.x, z - other.z); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param x the value to subtract + * @param z the value to subtract + * @return a new vector + */ + public Vector2D subtract(double x, double z) { + return new Vector2D(this.x - x, this.z - z); + } + + /** + * Subtract another vector from this vector and return the result + * as a new vector. + * + * @param x the value to subtract + * @param z the value to subtract + * @return a new vector + */ + public Vector2D subtract(int x, int z) { + return new Vector2D(this.x - x, this.z - z); + } + + /** + * Subtract a list of vectors from this vector and return the result + * as a new vector. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector2D subtract(Vector2D... others) { + double newX = x, newZ = z; + + for (Vector2D other : others) { + newX -= other.x; + newZ -= other.z; + } + + return new Vector2D(newX, newZ); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public Vector2D multiply(Vector2D other) { + return new Vector2D(x * other.x, z * other.z); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param x the value to multiply + * @param z the value to multiply + * @return a new vector + */ + public Vector2D multiply(double x, double z) { + return new Vector2D(this.x * x, this.z * z); + } + + /** + * Multiply this vector by another vector on each component. + * + * @param x the value to multiply + * @param z the value to multiply + * @return a new vector + */ + public Vector2D multiply(int x, int z) { + return new Vector2D(this.x * x, this.z * z); + } + + /** + * Multiply this vector by zero or more vectors on each component. + * + * @param others an array of vectors + * @return a new vector + */ + public Vector2D multiply(Vector2D... others) { + double newX = x, newZ = z; + + for (Vector2D other : others) { + newX *= other.x; + newZ *= other.z; + } + + return new Vector2D(newX, newZ); + } + + /** + * Perform scalar multiplication and return a new vector. + * + * @param n the value to multiply + * @return a new vector + */ + public Vector2D multiply(double n) { + return new Vector2D(this.x * n, this.z * n); + } + + /** + * Perform scalar multiplication and return a new vector. + * + * @param n the value to multiply + * @return a new vector + */ + public Vector2D multiply(float n) { + return new Vector2D(this.x * n, this.z * n); + } + + /** + * Perform scalar multiplication and return a new vector. + * + * @param n the value to multiply + * @return a new vector + */ + public Vector2D multiply(int n) { + return new Vector2D(this.x * n, this.z * n); + } + + /** + * Divide this vector by another vector on each component. + * + * @param other the other vector + * @return a new vector + */ + public Vector2D divide(Vector2D other) { + return new Vector2D(x / other.x, z / other.z); + } + + /** + * Divide this vector by another vector on each component. + * + * @param x the value to divide by + * @param z the value to divide by + * @return a new vector + */ + public Vector2D divide(double x, double z) { + return new Vector2D(this.x / x, this.z / z); + } + + /** + * Divide this vector by another vector on each component. + * + * @param x the value to divide by + * @param z the value to divide by + * @return a new vector + */ + public Vector2D divide(int x, int z) { + return new Vector2D(this.x / x, this.z / z); + } + + /** + * Perform scalar division and return a new vector. + * + * @param n the value to divide by + * @return a new vector + */ + public Vector2D divide(int n) { + return new Vector2D(x / n, z / n); + } + + /** + * Perform scalar division and return a new vector. + * + * @param n the value to divide by + * @return a new vector + */ + public Vector2D divide(double n) { + return new Vector2D(x / n, z / n); + } + + /** + * Perform scalar division and return a new vector. + * + * @param n the value to divide by + * @return a new vector + */ + public Vector2D divide(float n) { + return new Vector2D(x / n, z / n); + } + + /** + * Get the length of the vector. + * + * @return length + */ + public double length() { + return Math.sqrt(x * x + z * z); + } + + /** + * Get the length, squared, of the vector. + * + * @return length, squared + */ + public double lengthSq() { + return x * x + z * z; + } + + /** + * Get the distance between this vector and another vector. + * + * @param other the other vector + * @return distance + */ + public double distance(Vector2D other) { + return Math.sqrt(Math.pow(other.x - x, 2) + Math.pow(other.z - z, 2)); + } + + /** + * Get the distance between this vector and another vector, squared. + * + * @param other the other vector + * @return distance + */ + public double distanceSq(Vector2D other) { + return Math.pow(other.x - x, 2) + + Math.pow(other.z - z, 2); + } + + /** + * Get the normalized vector, which is the vector divided by its + * length, as a new vector. + * + * @return a new vector + */ + public Vector2D normalize() { + return divide(length()); + } + + /** + * Gets the dot product of this and another vector. + * + * @param other the other vector + * @return the dot product of this and the other vector + */ + public double dot(Vector2D other) { + return x * other.x + z * other.z; + } + + /** + * Checks to see if a vector is contained with another. + * + * @param min the minimum point (X, Y, and Z are the lowest) + * @param max the maximum point (X, Y, and Z are the lowest) + * @return true if the vector is contained + */ + public boolean containedWithin(Vector2D min, Vector2D max) { + return x >= min.x && x <= max.x + && z >= min.z && z <= max.z; + } + + /** + * Checks to see if a vector is contained with another. + * + * @param min the minimum point (X, Y, and Z are the lowest) + * @param max the maximum point (X, Y, and Z are the lowest) + * @return true if the vector is contained + */ + public boolean containedWithinBlock(Vector2D min, Vector2D max) { + return getBlockX() >= min.getBlockX() && getBlockX() <= max.getBlockX() + && getBlockZ() >= min.getBlockZ() && getBlockZ() <= max.getBlockZ(); + } + + /** + * Floors the values of all components. + * + * @return a new vector + */ + public Vector2D floor() { + return new Vector2D(Math.floor(x), Math.floor(z)); + } + + /** + * Rounds all components up. + * + * @return a new vector + */ + public Vector2D ceil() { + return new Vector2D(Math.ceil(x), Math.ceil(z)); + } + + /** + * Rounds all components to the closest integer. + * + *

Components < 0.5 are rounded down, otherwise up.

+ * + * @return a new vector + */ + public Vector2D round() { + return new Vector2D(Math.floor(x + 0.5), Math.floor(z + 0.5)); + } + + /** + * Returns a vector with the absolute values of the components of + * this vector. + * + * @return a new vector + */ + public Vector2D positive() { + return new Vector2D(Math.abs(x), Math.abs(z)); + } + + /** + * Perform a 2D transformation on this vector and return a new one. + * + * @param angle in degrees + * @param aboutX about which x coordinate to rotate + * @param aboutZ about which z coordinate to rotate + * @param translateX what to add after rotation + * @param translateZ what to add after rotation + * @return a new vector + * @see AffineTransform another method to transform vectors + */ + public Vector2D transform2D(double angle, double aboutX, double aboutZ, double translateX, double translateZ) { + angle = Math.toRadians(angle); + double x = this.x - aboutX; + double z = this.z - aboutZ; + double x2 = x * Math.cos(angle) - z * Math.sin(angle); + double z2 = x * Math.sin(angle) + z * Math.cos(angle); + return new Vector2D( + x2 + aboutX + translateX, + z2 + aboutZ + translateZ + ); + } + + /** + * Returns whether this vector is collinear with another vector. + * + * @param other the other vector + * @return true if collinear + */ + public boolean isCollinearWith(Vector2D other) { + if (x == 0 && z == 0) { + // this is a zero vector + return true; + } + + final double otherX = other.x; + final double otherZ = other.z; + + if (otherX == 0 && otherZ == 0) { + // other is a zero vector + return true; + } + + if ((x == 0) != (otherX == 0)) return false; + if ((z == 0) != (otherZ == 0)) return false; + + final double quotientX = otherX / x; + if (!Double.isNaN(quotientX)) { + return other.equals(multiply(quotientX)); + } + + final double quotientZ = otherZ / z; + if (!Double.isNaN(quotientZ)) { + return other.equals(multiply(quotientZ)); + } + + throw new RuntimeException("This should not happen"); + } + + /** + * Create a new {@code BlockVector2D} from this vector. + * + * @return a new {@code BlockVector2D} + */ + public BlockVector2D toBlockVector2D() { + return new BlockVector2D(this); + } + + /** + * Creates a 3D vector by adding a zero Y component to this vector. + * + * @return a new vector + */ + public Vector toVector() { + return new Vector(x, 0, z); + } + + /** + * Creates a 3D vector by adding the specified Y component to this vector. + * + * @param y the Y component + * @return a new vector + */ + public Vector toVector(double y) { + return new Vector(x, y, z); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Vector2D)) { + return false; + } + + Vector2D other = (Vector2D) obj; + return other.x == this.x && other.z == this.z; + + } + + @Override + public int hashCode() { + return ((new Double(x)).hashCode() >> 13) ^ + (new Double(z)).hashCode(); + } + + @Override + public String toString() { + return "(" + x + ", " + z + ")"; + } + + /** + * Gets the minimum components of two vectors. + * + * @param v1 the first vector + * @param v2 the second vector + * @return minimum + */ + public static Vector2D getMinimum(Vector2D v1, Vector2D v2) { + return new Vector2D( + Math.min(v1.x, v2.x), + Math.min(v1.z, v2.z) + ); + } + + /** + * Gets the maximum components of two vectors. + * + * @param v1 the first vector + * @param v2 the second vector + * @return maximum + */ + public static Vector2D getMaximum(Vector2D v1, Vector2D v2) { + return new Vector2D( + Math.max(v1.x, v2.x), + Math.max(v1.z, v2.z) + ); + } + + public static Class inject() { + return Vector2D.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index 58fa5b0a..1462da3a 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -94,7 +94,7 @@ public class BiomeCommands { BiomeRegistry biomeRegistry = player.getWorld().getWorldData().getBiomeRegistry(); List biomes = biomeRegistry.getBiomes(); int totalPages = biomes.size() / 19 + 1; - player.print(BBC.getPrefix() + "Available Biomes (page " + page + "/" + totalPages + ") :"); + BBC.BIOME_LIST_HEADER.send(player, page, totalPages); for (BaseBiome biome : biomes) { if (offset > 0) { offset--; @@ -106,7 +106,7 @@ public class BiomeCommands { break; } } else { - player.print(BBC.getPrefix() + " "); + player.print(BBC.getPrefix() + " "); } } } @@ -132,19 +132,15 @@ public class BiomeCommands { if (args.hasFlag('t')) { Vector blockPosition = player.getBlockTrace(300); if (blockPosition == null) { - player.printError("No block in sight!"); + BBC.NO_BLOCK.send(player); return; } BaseBiome biome = player.getWorld().getBiome(blockPosition.toVector2D()); biomes.add(biome); - - qualifier = "at line of sight point"; } else if (args.hasFlag('p')) { BaseBiome biome = player.getWorld().getBiome(player.getPosition().toVector2D()); biomes.add(biome); - - qualifier = "at your position"; } else { World world = player.getWorld(); Region region = session.getSelection(world); @@ -158,17 +154,15 @@ public class BiomeCommands { biomes.add(world.getBiome(pt.toVector2D())); } } - - qualifier = "in your selection"; } - player.print(biomes.size() != 1 ? "Biomes " + qualifier + ":" : "Biome " + qualifier + ":"); + BBC.BIOME_LIST_HEADER.send(player, 1, 1); for (BaseBiome biome : biomes) { BiomeData data = biomeRegistry.getData(biome); if (data != null) { player.print(BBC.getPrefix() + " " + data.getName()); } else { - player.print(BBC.getPrefix() + " "); + player.print(BBC.getPrefix() + " "); } } } @@ -204,7 +198,7 @@ public class BiomeCommands { FlatRegionVisitor visitor = new FlatRegionVisitor(Regions.asFlatRegion(region), replace); Operations.completeLegacy(visitor); - player.print(BBC.getPrefix() + "Biomes were changed in " + visitor.getAffected() + " columns. You may have to rejoin your game (or close and reopen your world) to see a change."); + BBC.BIOME_CHANGED.send(player, visitor.getAffected()); } public static Class inject() { diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 55d5ecdd..1753fe01 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -438,7 +438,7 @@ public class BrushCommands { maxRadius = Math.max(config.maxBrushRadius, config.butcherMaxRadius); } if (radius > maxRadius) { - player.printError("Maximum allowed brush radius: " + maxRadius); + BBC.TOOL_RADIUS_ERROR.send(player, maxRadius); return; } diff --git a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index a3c740ce..2042b4e4 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -42,7 +42,6 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; @@ -233,7 +232,7 @@ public class ClipboardCommands { public void download(final Player player, final LocalSession session, @Optional("schematic") final String formatName) throws CommandException, WorldEditException { final ClipboardFormat format = ClipboardFormat.findByAlias(formatName); if (format == null) { - player.printError("Unknown schematic format: " + formatName); + BBC.CLIPBOARD_INVALID_FORMAT.send(player, formatName); return; } ClipboardHolder holder = session.getClipboard(); @@ -467,32 +466,6 @@ public class ClipboardCommands { BBC.COMMAND_FLIPPED.send(player); } - @Command( - aliases = { "/load" }, - usage = "", - desc = "Load a schematic into your clipboard", - min = 0, - max = 1 - ) - @Deprecated - @CommandPermissions("worldedit.clipboard.load") - public void load(Actor actor) { - actor.printError("This command is no longer used. See //schematic load."); - } - - @Command( - aliases = { "/save" }, - usage = "", - desc = "Save a schematic into your clipboard", - min = 0, - max = 1 - ) - @Deprecated - @CommandPermissions("worldedit.clipboard.save") - public void save(Actor actor) { - actor.printError("This command is no longer used. See //schematic save."); - } - @Command( aliases = { "clearclipboard" }, usage = "", diff --git a/core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 1eb93986..18f8084f 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -8,7 +8,6 @@ import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -55,36 +54,6 @@ public class GeneralCommands { } } - @Command( - aliases = { "/limit" }, - usage = "", - desc = "Modify block change limit", - min = 1, - max = 1 - ) - @CommandPermissions("worldedit.limit") - public void limit(Player player, LocalSession session, CommandContext args) throws WorldEditException { - - LocalConfiguration config = worldEdit.getConfiguration(); - boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted"); - - int limit = Math.max(-1, args.getInteger(0)); - if (!mayDisable && config.maxChangeLimit > -1) { - if (limit > config.maxChangeLimit) { - player.printError("Your maximum allowable limit is " + config.maxChangeLimit + "."); - return; - } - } - - session.setBlockChangeLimit(limit); - - if (limit != -1) { - player.print(BBC.getPrefix() + "Block change limit set to " + limit + ". (Use //limit -1 to go back to the default.)"); - } else { - player.print(BBC.getPrefix() + "Block change limit set to " + limit + "."); - } - } - @Command( aliases = { "/fast" }, usage = "[on|off]", @@ -98,20 +67,20 @@ public class GeneralCommands { String newState = args.getString(0, null); if (session.hasFastMode()) { if ("on".equals(newState)) { - player.printError("Fast mode already enabled."); + BBC.FAST_ENABLED.send(player); return; } session.setFastMode(false); - player.print(BBC.getPrefix() + "Fast mode disabled."); + BBC.FAST_DISABLED.send(player); } else { if ("off".equals(newState)) { - player.printError("Fast mode already disabled."); + BBC.FAST_DISABLED.send(player); return; } session.setFastMode(true); - player.print(BBC.getPrefix() + "Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes."); + BBC.FAST_ENABLED.send(player); } } @@ -197,9 +166,9 @@ public class GeneralCommands { public void togglePlace(Player player, LocalSession session, CommandContext args) throws WorldEditException { if (session.togglePlacementPosition()) { - player.print(BBC.getPrefix() + "Now placing at pos #1."); + BBC.PLACE_ENABLED.send(player); } else { - player.print(BBC.getPrefix() + "Now placing at the block you stand in."); + BBC.PLACE_DISABLED.send(player); } } diff --git a/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index f93839b5..c0bb89a5 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -119,7 +119,7 @@ public class GenerationCommands { Vector pos = session.getPlacementPosition(player); int affected = editSession.makeCylinder(pos, Patterns.wrap(pattern), radiusX, radiusZ, height, !hollow); - player.print(BBC.getPrefix() + affected + " block(s) have been created."); + BBC.VISITOR_BLOCK.send(player, affected); } @Command( @@ -185,7 +185,7 @@ public class GenerationCommands { int affected = editSession.makeSphere(pos, Patterns.wrap(pattern), radiusX, radiusY, radiusZ, !hollow); player.findFreePosition(); - player.print(BBC.getPrefix() + affected + " block(s) have been created."); + BBC.VISITOR_BLOCK.send(player, affected); } @Command( @@ -201,7 +201,7 @@ public class GenerationCommands { public void forestGen(Player player, LocalSession session, EditSession editSession, @Optional("10") int size, @Optional("tree") TreeType type, @Optional("5") double density) throws WorldEditException { density = density / 100; int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, new TreeGenerator(type)); - player.print(BBC.getPrefix() + affected + " trees created."); + BBC.COMMAND_TREE.send(player, affected); } @Command( @@ -215,7 +215,7 @@ public class GenerationCommands { @Logging(POSITION) public void pumpkins(Player player, LocalSession session, EditSession editSession, @Optional("10") int apothem) throws WorldEditException { int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem); - player.print(BBC.getPrefix() + affected + " pumpkin patches created."); + BBC.COMMAND_PUMPKIN.send(player, affected); } @Command( @@ -246,7 +246,7 @@ public class GenerationCommands { worldEdit.checkMaxRadius(size); int affected = editSession.makePyramid(pos, Patterns.wrap(pattern), size, !hollow); player.findFreePosition(); - player.print(BBC.getPrefix() + affected + " block(s) have been created."); + BBC.VISITOR_BLOCK.send(player, affected); } @Command( @@ -309,7 +309,7 @@ public class GenerationCommands { try { final int affected = editSession.makeShape(region, zero, unit, Patterns.wrap(pattern), expression, hollow); player.findFreePosition(); - player.print(BBC.getPrefix() + affected + " block(s) have been created."); + BBC.VISITOR_BLOCK.send(player, affected); } catch (ExpressionException e) { player.printError(e.getMessage()); } @@ -374,7 +374,7 @@ public class GenerationCommands { try { final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow); player.findFreePosition(); - player.print(BBC.getPrefix() + "" + affected + " columns affected."); + BBC.VISITOR_FLAT.send(player, affected); } catch (ExpressionException e) { player.printError(e.getMessage()); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index c55471cb..fc4a390d 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -222,7 +222,7 @@ public class HistoryCommands { player.checkPermission("worldedit.history.undo.other"); LocalSession sess = worldEdit.getSession(args.getString(1)); if (sess == null) { - player.printError("Unable to find session for " + args.getString(1)); + BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, args.getString(1)); break; } undone = sess.undo(session.getBlockBag(player), player); @@ -257,7 +257,7 @@ public class HistoryCommands { player.checkPermission("worldedit.history.redo.other"); LocalSession sess = worldEdit.getSession(args.getString(1)); if (sess == null) { - player.printError("Unable to find session for " + args.getString(1)); + BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, args.getString(1)); break; } redone = sess.redo(session.getBlockBag(player), player); diff --git a/core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java b/core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java index 98b1b45c..b9357d21 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java @@ -185,7 +185,7 @@ public class NavigationCommands { player.findFreePosition(pos); BBC.POOF.send(player); } else { - BBC.JUMPTO_FAIL.send(player); + BBC.NO_BLOCK.send(player); } } diff --git a/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index df091026..a230f533 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -789,7 +789,7 @@ public class SelectionCommands { if (found != null) { session.setDefaultRegionSelector(found); - player.print(BBC.getPrefix() + "Your default region selector is now " + found.name() + "."); + BBC.SELECTOR_SET_DEFAULT.send(player, found.name()); } else { throw new RuntimeException("Something unexpected happened. Please report this."); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java index 0375209d..ff3824d0 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java @@ -77,12 +77,12 @@ public class SnapshotCommands { int num = args.argsLength() > 0 ? Math.min(40, Math.max(5, args.getInteger(0))) : 5; - player.print(BBC.getPrefix() + "Snapshots for world: '" + player.getWorld().getName() + "'"); + BBC.SNAPSHOT_LIST_HEADER.send(player, player.getWorld().getName()); for (byte i = 0; i < Math.min(num, snapshots.size()); i++) { player.print(BBC.getPrefix() + (i + 1) + ". " + snapshots.get(i).getName()); } - player.print(BBC.getPrefix() + "Use /snap use [snapshot] or /snap use latest."); + BBC.SNAPSHOT_LIST_FOOTER.send(player); } else { player.printError("No snapshots are available. See console for details."); @@ -129,7 +129,7 @@ public class SnapshotCommands { if (snapshot != null) { session.setSnapshot(null); - player.print(BBC.getPrefix() + "Now using newest snapshot."); + BBC.SNAPSHOT_NEWEST.send(player); } else { player.printError("No snapshots were found."); } @@ -139,7 +139,7 @@ public class SnapshotCommands { } else { try { session.setSnapshot(config.snapshotRepo.getSnapshot(name)); - player.print(BBC.getPrefix() + "Snapshot set to: " + name); + BBC.SNAPSHOT_SET.send(player, name); } catch (InvalidSnapshotException e) { player.printError("That snapshot does not exist or is not available."); } @@ -187,7 +187,7 @@ public class SnapshotCommands { return; } session.setSnapshot(snapshot); - player.print(BBC.getPrefix() + "Snapshot set to: " + snapshot.getName()); + BBC.SNAPSHOT_SET.send(player, snapshot.getName()); } catch (MissingWorldException e) { player.printError("No snapshots were found for this world."); } @@ -224,7 +224,7 @@ public class SnapshotCommands { + dateFormat.format(date.getTime()) + "."); } else { session.setSnapshot(snapshot); - player.print(BBC.getPrefix() + "Snapshot set to: " + snapshot.getName()); + BBC.SNAPSHOT_SET.send(player, snapshot.getName()); } } catch (MissingWorldException ex) { player.printError("No snapshots were found for this world."); @@ -258,11 +258,10 @@ public class SnapshotCommands { Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName()); if (snapshot == null) { dateFormat.setTimeZone(session.getTimeZone()); - player.printError("Couldn't find a snapshot after " - + dateFormat.format(date.getTime()) + "."); + player.printError("Couldn't find a snapshot after " + dateFormat.format(date.getTime()) + "."); } else { session.setSnapshot(snapshot); - player.print(BBC.getPrefix() + "Snapshot set to: " + snapshot.getName()); + BBC.SNAPSHOT_SET.send(player, snapshot.getName()); } } catch (MissingWorldException ex) { player.printError("No snapshots were found for this world."); diff --git a/core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java index 8c50f246..d81f2e2b 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java @@ -115,7 +115,7 @@ public class SnapshotUtilCommands { // Load chunk store try { chunkStore = snapshot.getChunkStore(); - player.print(BBC.getPrefix() + "Snapshot '" + snapshot.getName() + "' loaded; now restoring..."); + BBC.SNAPSHOT_LOADED.send(player, snapshot.getName()); } catch (DataException e) { player.printError("Failed to load snapshot: " + e.getMessage()); return; diff --git a/core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java index 1a95eeef..c4f6b37f 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java @@ -48,7 +48,7 @@ public class SuperPickaxeCommands { session.setSuperPickaxe(new SinglePickaxe()); session.enableSuperPickAxe(); - player.print(BBC.getPrefix() + "Mode changed. Left click with a pickaxe. // to disable."); + BBC.SUPERPICKAXE_AREA_ENABLED.send(player); } @Command( @@ -65,13 +65,13 @@ public class SuperPickaxeCommands { int range = args.getInteger(0); if (range > config.maxSuperPickaxeSize) { - player.printError("Maximum range: " + config.maxSuperPickaxeSize); + BBC.TOOL_RANGE_ERROR.send(player, config.maxSuperPickaxeSize); return; } session.setSuperPickaxe(new AreaPickaxe(range)); session.enableSuperPickAxe(); - player.print(BBC.getPrefix() + "Mode changed. Left click with a pickaxe. // to disable."); + BBC.SUPERPICKAXE_AREA_ENABLED.send(player); } @Command( @@ -88,13 +88,13 @@ public class SuperPickaxeCommands { double range = args.getDouble(0); if (range > config.maxSuperPickaxeSize) { - player.printError("Maximum range: " + config.maxSuperPickaxeSize); + BBC.TOOL_RANGE_ERROR.send(player, config.maxSuperPickaxeSize); return; } session.setSuperPickaxe(new RecursivePickaxe(range)); session.enableSuperPickAxe(); - player.print(BBC.getPrefix() + "Mode changed. Left click with a pickaxe. // to disable."); + BBC.SUPERPICKAXE_AREA_ENABLED.send(player); } public static Class inject() { diff --git a/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 1d435d09..7a791ae1 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -155,7 +155,7 @@ public class ToolCommands { int range = args.getInteger(1); if (range > config.maxSuperPickaxeSize) { - BBC.TOOL_FLOOD_FILL_RANGE_ERROR.send(player, config.maxSuperPickaxeSize); + BBC.TOOL_RANGE_ERROR.send(player, config.maxSuperPickaxeSize); return; } diff --git a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 2983d3c1..33aeea49 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -442,7 +442,7 @@ public class UtilityCommands { killed += visitor.getAffected(); } - actor.print(BBC.getPrefix() + "Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + "."); + BBC.KILL_SUCCESS.send(actor, killed, radius); if (editSession != null) { session.remember(editSession); @@ -502,7 +502,7 @@ public class UtilityCommands { removed += visitor.getAffected(); } - actor.print(BBC.getPrefix() + "Marked " + removed + (removed != 1 ? " entities" : " entity") + " for removal."); + BBC.KILL_SUCCESS.send(removed, radius); if (editSession != null) { session.remember(editSession); diff --git a/core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java index 258adace..21eb3453 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -107,9 +107,8 @@ public class WorldEditCommands { public void tz(Player player, LocalSession session, CommandContext args) throws WorldEditException { TimeZone tz = TimeZone.getTimeZone(args.getString(0)); session.setTimezone(tz); - player.print(BBC.getPrefix() + "Timezone set for this session to: " + tz.getDisplayName()); - player.print(BBC.getPrefix() + "The current time in that timezone is: " - + dateFormat.format(Calendar.getInstance(tz).getTime())); + BBC.TIMEZONE_SET.send(player, tz.getDisplayName()); + BBC.TIMEZONE_DISPLAY.send(player, dateFormat.format(Calendar.getInstance(tz).getTime())); } @Command( diff --git a/core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index e60e1d4c..03b26eae 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java +++ b/core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -1,5 +1,6 @@ package com.sk89q.worldedit.command.tool; +import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.extent.ResettableExtent; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; @@ -176,7 +177,7 @@ public class BrushTool implements TraceTool { target = player.getBlockTrace(getRange(), true); if (target == null) { - player.printError("No block in sight!"); + BBC.NO_BLOCK.send(player); return true; } @@ -216,7 +217,7 @@ public class BrushTool implements TraceTool { try { brush.build(editSession, target, material, size); } catch (MaxChangedBlocksException e) { - player.printError("Max blocks change limit reached."); + player.printError("Max blocks change limit reached."); // Never happens } finally { if (bag != null) { bag.flushChanges(); diff --git a/core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java b/core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java index aeb0e2ab..ef8b38a5 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java +++ b/core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command.tool; +import com.boydti.fawe.config.BBC; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; @@ -82,7 +83,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo target = player.getBlockTraceFace(getRange(), true); if (target == null) { - player.printError("No block in sight!"); + BBC.NO_BLOCK.send(player); return null; } diff --git a/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java b/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java index 5b9a5df4..9f496f6e 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultBlockParser.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.extension.factory; import com.boydti.fawe.jnbt.JSON2NBT; import com.boydti.fawe.jnbt.NBTException; import com.boydti.fawe.util.MathMan; -import com.intellectualcrafters.plot.util.StringMan; +import com.boydti.fawe.util.StringMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.BlockVector; diff --git a/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java b/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java index 4e936544..8c960462 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/factory/DefaultMaskParser.java @@ -282,19 +282,19 @@ public class DefaultMaskParser extends FaweParser { int requiredMin = 1; int requiredMax = 8; if (split.length == 2) { - String[] split2 = split[1].split(":"); + String[] split2 = split[1].split("[:|,]"); requiredMin = (int) Math.abs(Expression.compile(split2[0]).evaluate()); - if (split2.length == 2) { + if (split2.length >= 2) { requiredMax = (int) Math.abs(Expression.compile(split2[1]).evaluate()); } } if (firstChar == '~') { - return new AdjacentMask(extent, worldEdit.getBlockFactory().parseFromListInput(input.substring(1), tempContext), requiredMin, requiredMax); + return new AdjacentMask(extent, worldEdit.getBlockFactory().parseFromListInput(split[0], tempContext), requiredMin, requiredMax); } else { return new WallMask(extent, worldEdit.getBlockFactory().parseFromListInput(input.substring(1), tempContext), requiredMin, requiredMax); } } catch (NumberFormatException | ExpressionException e) { - throw new SuggestInputParseException(input, "~="); + throw new SuggestInputParseException(input, "~=:"); } } case '>': diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index c448452b..dc492825 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -482,7 +482,7 @@ public class PlatformManager { if (pos != null) { player.findFreePosition(pos); } else { - player.printError("No block in sight (or too far)!"); + BBC.NO_BLOCK.send(player); } event.setCancelled(true); diff --git a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index a58c6033..d8cc0d83 100644 --- a/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -28,8 +28,8 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.storage.ChunkStore; +import java.util.AbstractSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.Set; @@ -315,18 +315,60 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { @Override public Set getChunks() { - Set chunks = new LinkedHashSet(); - Vector min = getMinimumPoint(); Vector max = getMaximumPoint(); + final int maxX = max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; + final int minX = min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; + final int maxZ = max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; + final int minZ = min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; + final int size = (maxX - minX + 1) * (maxZ - minZ + 1); - for (int x = max.getBlockX() >> ChunkStore.CHUNK_SHIFTS; x >= min.getBlockX() >> ChunkStore.CHUNK_SHIFTS; --x) { - for (int z = max.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; z >= min.getBlockZ() >> ChunkStore.CHUNK_SHIFTS; --z) { - chunks.add(new Vector2D(x, z)); + return new AbstractSet() { + @Override + public Iterator iterator() { + return new Iterator() { + private Vector2D pos = new Vector2D(minX, minZ); + @Override + public boolean hasNext() { + return pos != null; + } + + @Override + public Vector2D next() { + Vector2D result = pos; + // calc next + if (pos.getX() < maxX) { + pos = new Vector2D(pos.getX() + 1, pos.getZ()); + } else if (pos.getZ() < maxZ) { + pos = new Vector2D(minX, pos.getZ() + 1); + } else { + pos = null; + } + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("This set is immutable."); + } + }; } - } - return chunks; + @Override + public int size() { + return size; + } + + @Override + public boolean contains(Object o) { + if (o instanceof Vector2D) { + Vector2D cv = (Vector2D) o; + return cv.getX() >= minX && cv.getX() <= maxX && cv.getZ() >= minZ && cv.getZ() <= maxZ; + } else { + return false; + } + } + }; } @Override diff --git a/forge110/build.gradle b/forge110/build.gradle index 263c1075..40b105c2 100644 --- a/forge110/build.gradle +++ b/forge110/build.gradle @@ -58,6 +58,7 @@ shadowJar { relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml' dependencies { include(dependency('com.github.luben:zstd-jni:1.1.1')) + include(dependency('co.aikar:fastutil-lite:1.0')) include(dependency(':core')) include(dependency('org.yaml:snakeyaml:1.16')) } diff --git a/forge111/build.gradle b/forge111/build.gradle index c7380bb0..950b05e6 100644 --- a/forge111/build.gradle +++ b/forge111/build.gradle @@ -58,6 +58,7 @@ shadowJar { relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml' dependencies { include(dependency('com.github.luben:zstd-jni:1.1.1')) + include(dependency('co.aikar:fastutil-lite:1.0')) include(dependency(':core')) include(dependency('org.yaml:snakeyaml:1.16')) } diff --git a/forge1710/build.gradle b/forge1710/build.gradle index d8bec635..dfbd68c5 100644 --- a/forge1710/build.gradle +++ b/forge1710/build.gradle @@ -49,6 +49,7 @@ shadowJar { relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml' dependencies { include(dependency('com.github.luben:zstd-jni:1.1.1')) + include(dependency('co.aikar:fastutil-lite:1.0')) include(dependency(':core')) include(dependency('org.yaml:snakeyaml:1.16')) } diff --git a/forge189/build.gradle b/forge189/build.gradle index cc0b9fd6..a0ad89ac 100644 --- a/forge189/build.gradle +++ b/forge189/build.gradle @@ -58,6 +58,7 @@ shadowJar { relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml' dependencies { include(dependency('com.github.luben:zstd-jni:1.1.1')) + include(dependency('co.aikar:fastutil-lite:1.0')) include(dependency(':core')) include(dependency('org.yaml:snakeyaml:1.16')) } diff --git a/forge194/build.gradle b/forge194/build.gradle index a30c49d2..b328804a 100644 --- a/forge194/build.gradle +++ b/forge194/build.gradle @@ -57,6 +57,7 @@ shadowJar { relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml' dependencies { include(dependency('com.github.luben:zstd-jni:1.1.1')) + include(dependency('co.aikar:fastutil-lite:1.0')) include(dependency(':core')) include(dependency('org.yaml:snakeyaml:1.16')) } diff --git a/nukkit/build.gradle b/nukkit/build.gradle index 21eaede6..99c97d27 100644 --- a/nukkit/build.gradle +++ b/nukkit/build.gradle @@ -23,6 +23,7 @@ jar.enabled = false shadowJar { dependencies { include(dependency('com.github.luben:zstd-jni:1.1.1')) + include(dependency('co.aikar:fastutil-lite:1.0')) include(dependency(name: 'worldedit-core-6.1.4-SNAPSHOT-dist')) include(dependency('com.google.code.gson:gson:2.2.4')) include(dependency('org.yaml:snakeyaml:1.16')) diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkit.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkit.java index 95afdabc..7697705d 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkit.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/FaweNukkit.java @@ -28,9 +28,6 @@ public class FaweNukkit implements IFawe, Listener { private final NukkitWorldEdit plugin; public FaweNukkit(NukkitWorldEdit mod) { - Settings.IMP.HISTORY.USE_DISK = true; - Settings.IMP.CLIPBOARD.USE_DISK = true; - Settings.IMP.HISTORY.COMPRESSION_LEVEL = 9; this.plugin = mod; FaweChunk.HEIGHT = 128; plugin.getServer().getPluginManager().registerEvents(this, plugin); diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/queue/NukkitChunk.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/queue/NukkitChunk.java index a5aeac6a..d2ae5235 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/queue/NukkitChunk.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/queue/NukkitChunk.java @@ -14,7 +14,6 @@ import com.boydti.fawe.util.MainUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector2D; -import com.sk89q.worldedit.world.biome.BaseBiome; import java.io.IOException; import java.util.Map; @@ -80,28 +79,18 @@ public class NukkitChunk extends CharFaweChunk { final BaseFullChunk chunk = getChunk(); getParent().setHeightMap(this, heightMap); char[][] sections = getCombinedIdArrays(); - final int[][] biomes = getBiomeArray(); final int X = getX() << 4; final int Z = getZ() << 4; if (biomes != null) { final LocalWorld lw = NukkitUtil.getLocalWorld(world); - final BaseBiome bb = new BaseBiome(0); - int last = 0; - for (int x = 0; x < 16; x++) { - final int[] array = biomes[x]; - if (array == null) { - continue; - } - for (int z = 0; z < 16; z++) { - final int biome = array[z]; - if (biome == 0) { - continue; - } - if (last != biome) { - last = biome; - bb.setId(biome); - } - lw.setBiome(new Vector2D(X + x, Z + z), bb); + final byte[] biomes = getBiomeArray(); + int index = 0; + Vector2D mutable = new Vector2D(); + for (int z = 0; z < 16; z++) { + mutable.z = Z + z; + for (int x = 0; x < 16; x++) { + mutable.x = X + x; + lw.setBiome(mutable, FaweCache.getBiome(biomes[index++] & 0xFF)); } } } diff --git a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/queue/NukkitQueue.java b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/queue/NukkitQueue.java index fbd4dc4f..3cc4872d 100644 --- a/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/queue/NukkitQueue.java +++ b/nukkit/src/main/java/com/boydti/fawe/nukkit/optimization/queue/NukkitQueue.java @@ -236,21 +236,11 @@ public class NukkitQueue extends NMSMappedFaweQueue tasks = new HashMap<>(); + private final ConcurrentHashMap tasks = new ConcurrentHashMap<>(); @Override public int repeat(Runnable runnable, int interval) {