diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 12d38de6a..4d9ca1649 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/renovate.json b/renovate.json new file mode 100644 index 000000000..7620d71b8 --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "extends": [ + "config:base" + ], + "ignoreDeps": ["guava", "rhino-runtime", "mockito-core", "antlr4", "antlr4-runtime", "paranamer"] +} diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index eb767c152..69a08e31f 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -23,6 +23,7 @@ repositories { name = "ProtocolLib Repo" url = uri("https://repo.dmulloy2.net/nexus/repository/public/") } + maven { url = uri("https://repo.inventivetalent.org/content/groups/public/") } flatDir {dir(File("src/main/resources"))} } @@ -56,7 +57,7 @@ dependencies { "compileOnly"("org.jetbrains:annotations:20.1.0") "testCompileOnly"("org.jetbrains:annotations:20.1.0") "compileOnly"("org.spigotmc:spigot:1.16.4-R0.1-SNAPSHOT") - "implementation"("io.papermc:paperlib:1.0.4") + "implementation"("io.papermc:paperlib:1.0.6") "compileOnly"("com.sk89q:dummypermscompat:1.10") { exclude("com.github.MilkBowl", "VaultAPI") } @@ -68,15 +69,16 @@ dependencies { exclude("com.sk89q.worldedit.worldedit-libs", "bukkit") exclude("com.sk89q.worldedit.worldedit-libs", "core") } - "compile"("org.bstats:bstats-bukkit:1.7") + "compile"("org.bstats:bstats-bukkit:1.8") + "compile"("com.intellectualsites.paster:Paster:1.0.1-SNAPSHOT") // Third party - "implementation"("com.github.InventivetalentDev:MapManager:1.7.+") { isTransitive = false } + compileOnlyApi("org.inventivetalent:mapmanager:1.7.+") { isTransitive = false } "implementation"("com.github.TechFortress:GriefPrevention:16.+") { isTransitive = false } "implementation"("com.massivecraft:mcore:7.0.1") { isTransitive = false } "implementation"("com.bekvon.bukkit.residence:Residence:4.5._13.1") { isTransitive = false } "implementation"("com.palmergames.bukkit:towny:0.84.0.9") { isTransitive = false } "implementation"("com.thevoxelbox.voxelsniper:voxelsniper:5.171.0") { isTransitive = false } - "implementation"("com.comphenix.protocol:ProtocolLib:4.5.0") { isTransitive = false } + "implementation"("com.comphenix.protocol:ProtocolLib:4.5.1") { isTransitive = false } } tasks.named("processResources") { @@ -107,17 +109,17 @@ tasks.named("shadowJar") { include(dependency("org.slf4j:slf4j-api")) include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) include(dependency("org.antlr:antlr4-runtime")) - relocate("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { - include(dependency("org.bstats:bstats-bukkit:1.7")) - } relocate("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") { - include(dependency("io.papermc:paperlib:1.0.4")) + include(dependency("io.papermc:paperlib:1.0.6")) } relocate("it.unimi.dsi.fastutil", "com.sk89q.worldedit.bukkit.fastutil") { include(dependency("it.unimi.dsi:fastutil")) } relocate("org.bstats", "com.boydti.metrics") { - include(dependency("org.bstats:bstats-bukkit:1.7")) + include(dependency("org.bstats:bstats-bukkit:1.8")) + } + relocate("com.intellectualsites.paster", "com.boydti.fawe.paster") { + include(dependency("com.intellectualsites.paster:Paster:1.0.1-SNAPSHOT")) } } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitAdapter_1_15_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitAdapter_1_15_2.java index 8098145a1..ea5fea77b 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitAdapter_1_15_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitAdapter_1_15_2.java @@ -190,37 +190,32 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter { return; } if (playerChunk.hasBeenLoaded()) { - TaskManager.IMP.sync(() -> { - try { - int dirtyBits = fieldDirtyBits.getInt(playerChunk); - if (dirtyBits == 0) { - nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk); - } - if (mask == 0) { - dirtyBits = 65535; - } else { - dirtyBits |= mask; - } - - fieldDirtyBits.set(playerChunk, dirtyBits); - fieldDirtyCount.set(playerChunk, 64); - - if (lighting) { - ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); - PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine()); - playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { - p.playerConnection.sendPacket(packet); - }); - } - - } catch (IllegalAccessException e) { - e.printStackTrace(); + try { + int dirtyBits = fieldDirtyBits.getInt(playerChunk); + if (dirtyBits == 0) { + nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk); } - return null; - }); - return; + if (mask == 0) { + dirtyBits = 65535; + } else { + dirtyBits |= mask; + } + + fieldDirtyBits.set(playerChunk, dirtyBits); + fieldDirtyCount.set(playerChunk, 64); + + if (lighting) { + ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); + PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine()); + playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { + p.playerConnection.sendPacket(packet); + }); + } + + } catch (IllegalAccessException e) { + e.printStackTrace(); + } } - return; } /* diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java index 0cb058215..c4a9dfc9c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java @@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; -import com.boydti.fawe.beta.implementation.blocks.CharBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.lighting.HeightMapType; import com.boydti.fawe.beta.implementation.queue.QueueHandler; @@ -90,6 +89,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { public NibbleArray[] skyLight = new NibbleArray[16]; private boolean createCopy = false; private BukkitGetBlocks_1_15_2_Copy copy = null; + private boolean forceLoadSections = true; public BukkitGetBlocks_1_15_2(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -316,7 +316,8 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { @Override public > T call(IChunkSet set, Runnable finalizer) { - copy = createCopy ? new BukkitGetBlocks_1_15_2_Copy(world, getChunkX(), getChunkZ()) : null; + forceLoadSections = false; + copy = createCopy ? new BukkitGetBlocks_1_15_2_Copy(world) : null; try { WorldServer nmsWorld = world; Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -357,13 +358,14 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { if (!set.hasSection(layer)) { continue; } - if (createCopy) { - copy.storeSection(layer); - } bitMask |= 1 << layer; - char[] setArr = set.load(layer); + char[] setArr = set.load(layer).clone(); + if (createCopy) { + copy.storeSection(layer, load(layer).clone()); + } + ChunkSection newSection; ChunkSection existingSection = sections[layer]; if (existingSection == null) { @@ -392,7 +394,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { this.nmsChunk = nmsChunk; this.sections = null; this.reset(); - } else if (existingSection != getSections()[layer]) { + } else if (existingSection != getSections(false)[layer]) { this.sections[layer] = existingSection; this.reset(); } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { @@ -403,7 +405,6 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr, fastmode); if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) { log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer); - continue; } else { updateGet(this, nmsChunk, sections, newSection, setArr, layer); } @@ -470,9 +471,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { Set entityRemoves = set.getEntityRemoves(); if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } + syncTasks = new Runnable[3]; syncTasks[2] = () -> { final List[] entities = nmsChunk.getEntitySlices(); @@ -632,12 +631,14 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { } catch (Throwable e) { e.printStackTrace(); return null; + } finally { + forceLoadSections = true; } } @Override public synchronized char[] update(int layer, char[] data) { - ChunkSection section = getSections()[layer]; + ChunkSection section = getSections(true)[layer]; // Section is null, return empty array if (section == null) { data = new char[4096]; @@ -752,7 +753,10 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { } } - public ChunkSection[] getSections() { + public ChunkSection[] getSections(boolean force) { + if (force && forceLoadSections) { + return sections = getChunk().getSections().clone(); + } ChunkSection[] tmp = sections; if (tmp == null) { synchronized (this) { @@ -804,7 +808,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { @Override public boolean hasSection(int layer) { - return getSections()[layer] != null; + return getSections(false)[layer] != null; } @Override @@ -817,10 +821,10 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { return super.trim(true); } else { for (int i = 0; i < 16; i++) { - if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) { + if (!hasSection(i) || !super.sections[i].isFull()) { continue; } - ChunkSection existing = getSections()[i]; + ChunkSection existing = getSections(true)[i]; try { final DataPaletteBlock blocksExisting = existing.getBlocks(); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2_Copy.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2_Copy.java index a9aef70f4..8fddf5db1 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2_Copy.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2_Copy.java @@ -2,6 +2,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_15_2; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.IBlocks; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.lighting.HeightMapType; import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2; import com.google.common.base.Suppliers; import com.sk89q.jnbt.CompoundTag; @@ -21,22 +25,25 @@ import net.minecraft.server.v1_15_R1.TileEntity; import net.minecraft.server.v1_15_R1.WorldServer; import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.Future; -public class BukkitGetBlocks_1_15_2_Copy extends BukkitGetBlocks_1_15_2 { +public class BukkitGetBlocks_1_15_2_Copy implements IChunkGet { private final Map tiles = new HashMap<>(); private final Set entities = new HashSet<>(); private BiomeStorage biomeStorage; - private final char[][] blocks = new char[16][4096]; + private final char[][] blocks = new char[16][]; + private final WorldServer world; - protected BukkitGetBlocks_1_15_2_Copy(WorldServer world, int X, int Z) { - super(world, X, Z); + protected BukkitGetBlocks_1_15_2_Copy(WorldServer world) { + this.world = world; } protected void storeTile(TileEntity tile) { @@ -87,6 +94,16 @@ public class BukkitGetBlocks_1_15_2_Copy extends BukkitGetBlocks_1_15_2 { return null; } + @Override + public void setCreateCopy(boolean createCopy) { + + } + + @Override + public boolean isCreateCopy() { + return false; + } + protected void storeBiomes(BiomeStorage biomeStorage) { this.biomeStorage = new BiomeStorage(BukkitAdapter_1_15_2.getBiomeArray(biomeStorage).clone()); } @@ -105,8 +122,18 @@ public class BukkitGetBlocks_1_15_2_Copy extends BukkitGetBlocks_1_15_2 { return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null; } - protected void storeSection(int layer) { - blocks[layer] = update(layer, null).clone(); + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; } @Override @@ -115,15 +142,50 @@ public class BukkitGetBlocks_1_15_2_Copy extends BukkitGetBlocks_1_15_2 { return state.toBaseBlock(this, x, y, z); } + @Override + public boolean hasSection(@Range(from = 0, to = 15) int layer) { + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + return blocks[layer]; + } + @Override public BlockState getBlock(int x, int y, int z) { return BlockTypesCache.states[get(x, y, z)]; } @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + public char get(int x, int y, int z) { final int layer = y >> 4; final int index = (y & 15) << 8 | z << 4 | x; return blocks[layer][index]; } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/FAWEWorldNativeAccess_1_15_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/FAWEWorldNativeAccess_1_15_2.java index bd3767b9a..32359e353 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/FAWEWorldNativeAccess_1_15_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/FAWEWorldNativeAccess_1_15_2.java @@ -58,7 +58,7 @@ public class FAWEWorldNativeAccess_1_15_2 implements WorldNativeAccess> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException { - return this.adapter.setBlock(this.getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).bukkitChunk, position.getBlockX(), position.getBlockY(), position.getBlockZ(), block, sideEffectSet.shouldApply(SideEffect.LIGHTING)); - } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/nbt/LazyCompoundTag_1_15_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/nbt/LazyCompoundTag_1_15_2.java index 4b603d3b6..e37700956 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/nbt/LazyCompoundTag_1_15_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/nbt/LazyCompoundTag_1_15_2.java @@ -12,15 +12,18 @@ import net.minecraft.server.v1_15_R1.NBTTagList; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; public class LazyCompoundTag_1_15_2 extends CompoundTag { + private final Supplier nmsTag; + private CompoundTag cachedValue; public LazyCompoundTag_1_15_2(Supplier tag) { - super(null); + super(new HashMap<>()); this.nmsTag = tag; } @@ -34,12 +37,10 @@ public class LazyCompoundTag_1_15_2 extends CompoundTag { @Override public Map getValue() { - Map value = super.getValue(); - if (value == null) { - Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get()); - setValue(((CompoundTag) tag).getValue()); + if (cachedValue == null) { + cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get()); } - return super.getValue(); + return cachedValue.getValue(); } public boolean containsKey(String key) { @@ -149,4 +150,4 @@ public class LazyCompoundTag_1_15_2 extends CompoundTag { public String toString() { return nmsTag.get().toString(); } -} \ No newline at end of file +} diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitAdapter_1_16_1.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitAdapter_1_16_1.java index d148d8e81..d00432cb7 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitAdapter_1_16_1.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitAdapter_1_16_1.java @@ -187,35 +187,32 @@ public final class BukkitAdapter_1_16_1 extends NMSAdapter { return; } if (playerChunk.hasBeenLoaded()) { - TaskManager.IMP.sync(() -> { - try { - int dirtyBits = fieldDirtyBits.getInt(playerChunk); - if (dirtyBits == 0) { - nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk); - } - if (mask == 0) { - dirtyBits = 65535; - } else { - dirtyBits |= mask; - } - - fieldDirtyBits.set(playerChunk, dirtyBits); - fieldDirtyCount.set(playerChunk, 64); - - if (lighting) { - ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); - boolean trustEdges = false; //Added in 1.16.1 Not sure what it does. - PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges); - playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { - p.playerConnection.sendPacket(packet); - }); - } - - } catch (IllegalAccessException e) { - e.printStackTrace(); + try { + int dirtyBits = fieldDirtyBits.getInt(playerChunk); + if (dirtyBits == 0) { + nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk); } - return null; - }); + if (mask == 0) { + dirtyBits = 65535; + } else { + dirtyBits |= mask; + } + + fieldDirtyBits.set(playerChunk, dirtyBits); + fieldDirtyCount.set(playerChunk, 64); + + if (lighting) { + ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); + boolean trustEdges = false; //Added in 1.16.1 Not sure what it does. + PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges); + playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { + p.playerConnection.sendPacket(packet); + }); + } + + } catch (IllegalAccessException e) { + e.printStackTrace(); + } } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java index a2538a143..bf2ca9670 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java @@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; -import com.boydti.fawe.beta.implementation.blocks.CharBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.lighting.HeightMapType; import com.boydti.fawe.beta.implementation.queue.QueueHandler; @@ -90,6 +89,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { public NibbleArray[] skyLight = new NibbleArray[16]; private boolean createCopy = false; private BukkitGetBlocks_1_16_1_Copy copy = null; + private boolean forceLoadSections = true; public BukkitGetBlocks_1_16_1(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -316,7 +316,8 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { @Override public > T call(IChunkSet set, Runnable finalizer) { - copy = createCopy ? new BukkitGetBlocks_1_16_1_Copy(world, getChunkX(), getChunkZ()) : null; + forceLoadSections = false; + copy = createCopy ? new BukkitGetBlocks_1_16_1_Copy(world) : null; try { WorldServer nmsWorld = world; Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -357,13 +358,14 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { if (!set.hasSection(layer)) { continue; } - if (createCopy) { - copy.storeSection(layer); - } bitMask |= 1 << layer; - char[] setArr = set.load(layer); + char[] setArr = set.load(layer).clone(); + if (createCopy) { + copy.storeSection(layer, load(layer).clone()); + } + ChunkSection newSection; ChunkSection existingSection = sections[layer]; if (existingSection == null) { @@ -392,7 +394,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { this.nmsChunk = nmsChunk; this.sections = null; this.reset(); - } else if (existingSection != getSections()[layer]) { + } else if (existingSection != getSections(false)[layer]) { this.sections[layer] = existingSection; this.reset(); } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { @@ -405,7 +407,6 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { if (!BukkitAdapter_1_16_1 .setSectionAtomic(sections, existingSection, newSection, layer)) { log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer); - continue; } else { updateGet(this, nmsChunk, sections, newSection, setArr, layer); } @@ -472,9 +473,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { Set entityRemoves = set.getEntityRemoves(); if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } + syncTasks = new Runnable[3]; syncTasks[2] = () -> { final List[] entities = nmsChunk.getEntitySlices(); @@ -634,12 +633,14 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { } catch (Throwable e) { e.printStackTrace(); return null; + } finally { + forceLoadSections = true; } } @Override public synchronized char[] update(int layer, char[] data) { - ChunkSection section = getSections()[layer]; + ChunkSection section = getSections(true)[layer]; // Section is null, return empty array if (section == null) { data = new char[4096]; @@ -754,7 +755,10 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { } } - public ChunkSection[] getSections() { + public ChunkSection[] getSections(boolean force) { + if (force && forceLoadSections) { + return sections = getChunk().getSections().clone(); + } ChunkSection[] tmp = sections; if (tmp == null) { synchronized (this) { @@ -806,7 +810,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { @Override public boolean hasSection(int layer) { - return getSections()[layer] != null; + return getSections(false)[layer] != null; } @Override @@ -819,10 +823,10 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks { return super.trim(true); } else { for (int i = 0; i < 16; i++) { - if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) { + if (!hasSection(i) || !super.sections[i].isFull()) { continue; } - ChunkSection existing = getSections()[i]; + ChunkSection existing = getSections(true)[i]; try { final DataPaletteBlock blocksExisting = existing.getBlocks(); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1_Copy.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1_Copy.java index 9b9dc3697..634d2c5ff 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1_Copy.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1_Copy.java @@ -2,6 +2,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_16_1; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.IBlocks; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.lighting.HeightMapType; import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1; import com.google.common.base.Suppliers; import com.sk89q.jnbt.CompoundTag; @@ -16,28 +20,30 @@ import com.sk89q.worldedit.world.block.BlockTypesCache; import net.minecraft.server.v1_16_R1.BiomeBase; import net.minecraft.server.v1_16_R1.BiomeStorage; import net.minecraft.server.v1_16_R1.Entity; -import net.minecraft.server.v1_16_R1.IRegistry; import net.minecraft.server.v1_16_R1.NBTTagCompound; import net.minecraft.server.v1_16_R1.TileEntity; import net.minecraft.server.v1_16_R1.WorldServer; import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.Future; -public class BukkitGetBlocks_1_16_1_Copy extends BukkitGetBlocks_1_16_1 { +public class BukkitGetBlocks_1_16_1_Copy implements IChunkGet { private final Map tiles = new HashMap<>(); private final Set entities = new HashSet<>(); private BiomeStorage biomeStorage; - private final char[][] blocks = new char[16][4096]; + private final char[][] blocks = new char[16][]; + private final WorldServer world; - protected BukkitGetBlocks_1_16_1_Copy(WorldServer world, int X, int Z) { - super(world, X, Z); + protected BukkitGetBlocks_1_16_1_Copy(WorldServer world) { + this.world = world; } protected void storeTile(TileEntity tile) { @@ -88,6 +94,16 @@ public class BukkitGetBlocks_1_16_1_Copy extends BukkitGetBlocks_1_16_1 { return null; } + @Override + public void setCreateCopy(boolean createCopy) { + + } + + @Override + public boolean isCreateCopy() { + return false; + } + protected void storeBiomes(BiomeStorage biomeStorage) { this.biomeStorage = new BiomeStorage(BukkitAdapter_1_16_1.getBiomeArray(biomeStorage).clone()); } @@ -106,8 +122,18 @@ public class BukkitGetBlocks_1_16_1_Copy extends BukkitGetBlocks_1_16_1 { return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null; } - protected void storeSection(int layer) { - blocks[layer] = update(layer, null).clone(); + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; } @Override @@ -116,15 +142,50 @@ public class BukkitGetBlocks_1_16_1_Copy extends BukkitGetBlocks_1_16_1 { return state.toBaseBlock(this, x, y, z); } + @Override + public boolean hasSection(@Range(from = 0, to = 15) int layer) { + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + return blocks[layer]; + } + @Override public BlockState getBlock(int x, int y, int z) { return BlockTypesCache.states[get(x, y, z)]; } @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + public char get(int x, int y, int z) { final int layer = y >> 4; final int index = (y & 15) << 8 | z << 4 | x; return blocks[layer][index]; } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/FAWEWorldNativeAccess_1_16.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/FAWEWorldNativeAccess_1_16.java index d3a3072e8..a4cb0030b 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/FAWEWorldNativeAccess_1_16.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/FAWEWorldNativeAccess_1_16.java @@ -59,7 +59,7 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException { - return this.adapter.setBlock(this.getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).bukkitChunk, position.getBlockX(), position.getBlockY(), position.getBlockZ(), block, sideEffectSet.shouldApply(SideEffect.LIGHTING)); - } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/nbt/LazyCompoundTag_1_16_1.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/nbt/LazyCompoundTag_1_16_1.java index 07a6da3d5..cb77adb38 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/nbt/LazyCompoundTag_1_16_1.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/nbt/LazyCompoundTag_1_16_1.java @@ -12,15 +12,18 @@ import net.minecraft.server.v1_16_R1.NBTTagList; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; public class LazyCompoundTag_1_16_1 extends CompoundTag { + private final Supplier nmsTag; + private CompoundTag cachedValue; public LazyCompoundTag_1_16_1(Supplier tag) { - super(null); + super(new HashMap<>()); this.nmsTag = tag; } @@ -34,12 +37,10 @@ public class LazyCompoundTag_1_16_1 extends CompoundTag { @Override public Map getValue() { - Map value = super.getValue(); - if (value == null) { - Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get()); - setValue(((CompoundTag) tag).getValue()); + if (cachedValue == null) { + cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get()); } - return super.getValue(); + return cachedValue.getValue(); } public boolean containsKey(String key) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitAdapter_1_16_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitAdapter_1_16_2.java index f75477317..9ac20c248 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitAdapter_1_16_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitAdapter_1_16_2.java @@ -199,51 +199,49 @@ public final class BukkitAdapter_1_16_2 extends NMSAdapter { return; } if (playerChunk.hasBeenLoaded()) { - TaskManager.IMP.sync(() -> { - ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); - Optional optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); - if (optional.isPresent()) { - PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(optional.get(), 65535); + ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); + Optional optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); + if (optional.isPresent()) { + PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(optional.get(), 65535); + playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { + p.playerConnection.sendPacket(chunkpacket); + }); + + if (lighting) { + //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) + boolean trustEdges = true; + PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges); playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { - p.playerConnection.sendPacket(chunkpacket); + p.playerConnection.sendPacket(packet); }); + } + } else if (PaperLib.isPaper()) { + //Require generic here to work with multiple dependencies trying to take control. + PooledLinkedHashSets.PooledObjectLinkedOpenHashSet objects = + nmsWorld.getChunkProvider().playerChunkMap.playerViewDistanceNoTickMap.getObjectsInRange(chunkX, chunkZ); + if (objects == null) { + return; + } + for (Object obj : objects.getBackingSet()) { + if (obj == null) { + continue; + } + EntityPlayer p = (EntityPlayer) obj; + Chunk chunk = nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + if (chunk != null) { + PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(chunk, 65535); + p.playerConnection.sendPacket(chunkpacket); - if (lighting) { - boolean trustEdges = true; //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) - PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges); - playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { + if (lighting) { + //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) + boolean trustEdges = true; + PacketPlayOutLightUpdate packet = + new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges); p.playerConnection.sendPacket(packet); - }); - } - } else if (PaperLib.isPaper()) { - //Require generic here to work with multiple dependencies trying to take control. - PooledLinkedHashSets.PooledObjectLinkedOpenHashSet objects = - nmsWorld.getChunkProvider().playerChunkMap.playerViewDistanceNoTickMap.getObjectsInRange(chunkX, chunkZ); - if (objects == null) { - return null; - } - for (Object obj : objects.getBackingSet()) { - if (obj == null) { - continue; - } - EntityPlayer p = (EntityPlayer) obj; - Chunk chunk = nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ); - if (chunk != null) { - PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(chunk, 65535); - p.playerConnection.sendPacket(chunkpacket); - - if (lighting) { - boolean trustEdges = - true; //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) - PacketPlayOutLightUpdate packet = - new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges); - p.playerConnection.sendPacket(packet); - } } } } - return null; - }); + } } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java index e19038d48..e5c0dc447 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java @@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; -import com.boydti.fawe.beta.implementation.blocks.CharBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.lighting.HeightMapType; import com.boydti.fawe.beta.implementation.queue.QueueHandler; @@ -91,6 +90,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { public NibbleArray[] skyLight = new NibbleArray[16]; private boolean createCopy = false; private BukkitGetBlocks_1_16_2_Copy copy = null; + private boolean forceLoadSections = true; public BukkitGetBlocks_1_16_2(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -319,7 +319,8 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { @Override public > T call(IChunkSet set, Runnable finalizer) { - copy = createCopy ? new BukkitGetBlocks_1_16_2_Copy(world, getChunkX(), getChunkZ()) : null; + forceLoadSections = false; + copy = createCopy ? new BukkitGetBlocks_1_16_2_Copy(world) : null; try { WorldServer nmsWorld = world; Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -360,13 +361,14 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { if (!set.hasSection(layer)) { continue; } - if (createCopy) { - copy.storeSection(layer); - } bitMask |= 1 << layer; - char[] setArr = set.load(layer); + char[] setArr = set.load(layer).clone(); + if (createCopy) { + copy.storeSection(layer, load(layer).clone()); + } + ChunkSection newSection; ChunkSection existingSection = sections[layer]; if (existingSection == null) { @@ -395,7 +397,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { this.nmsChunk = nmsChunk; this.sections = null; this.reset(); - } else if (existingSection != getSections()[layer]) { + } else if (existingSection != getSections(false)[layer]) { this.sections[layer] = existingSection; this.reset(); } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { @@ -408,7 +410,6 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { if (!BukkitAdapter_1_16_2 .setSectionAtomic(sections, existingSection, newSection, layer)) { log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer); - continue; } else { updateGet(this, nmsChunk, sections, newSection, setArr, layer); } @@ -475,9 +476,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { Set entityRemoves = set.getEntityRemoves(); if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } + syncTasks = new Runnable[3]; syncTasks[2] = () -> { final List[] entities = nmsChunk.getEntitySlices(); @@ -637,12 +636,14 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { } catch (Throwable e) { e.printStackTrace(); return null; + } finally { + forceLoadSections = true; } } @Override public synchronized char[] update(int layer, char[] data) { - ChunkSection section = getSections()[layer]; + ChunkSection section = getSections(true)[layer]; // Section is null, return empty array if (section == null) { data = new char[4096]; @@ -757,7 +758,10 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { } } - public ChunkSection[] getSections() { + public ChunkSection[] getSections(boolean force) { + if (force && forceLoadSections) { + return sections = getChunk().getSections().clone(); + } ChunkSection[] tmp = sections; if (tmp == null) { synchronized (this) { @@ -809,7 +813,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { @Override public boolean hasSection(int layer) { - return getSections()[layer] != null; + return getSections(false)[layer] != null; } @Override @@ -822,10 +826,10 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks { return super.trim(true); } else { for (int i = 0; i < 16; i++) { - if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) { + if (!hasSection(i) || !super.sections[i].isFull()) { continue; } - ChunkSection existing = getSections()[i]; + ChunkSection existing = getSections(true)[i]; try { final DataPaletteBlock blocksExisting = existing.getBlocks(); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2_Copy.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2_Copy.java index ac80fe3f1..bb772de71 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2_Copy.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2_Copy.java @@ -2,6 +2,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_16_2; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.IBlocks; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.lighting.HeightMapType; import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2; import com.google.common.base.Suppliers; import com.sk89q.jnbt.CompoundTag; @@ -22,22 +26,25 @@ import net.minecraft.server.v1_16_R2.TileEntity; import net.minecraft.server.v1_16_R2.WorldServer; import org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.Future; -public class BukkitGetBlocks_1_16_2_Copy extends BukkitGetBlocks_1_16_2 { +public class BukkitGetBlocks_1_16_2_Copy implements IChunkGet { private final Map tiles = new HashMap<>(); private final Set entities = new HashSet<>(); private BiomeStorage biomeStorage; - private final char[][] blocks = new char[16][4096]; + private final char[][] blocks = new char[16][]; + private final WorldServer world; - protected BukkitGetBlocks_1_16_2_Copy(WorldServer world, int X, int Z) { - super(world, X, Z); + protected BukkitGetBlocks_1_16_2_Copy(WorldServer world) { + this.world = world; } protected void storeTile(TileEntity tile) { @@ -88,6 +95,16 @@ public class BukkitGetBlocks_1_16_2_Copy extends BukkitGetBlocks_1_16_2 { return null; } + @Override + public void setCreateCopy(boolean createCopy) { + + } + + @Override + public boolean isCreateCopy() { + return false; + } + protected void storeBiomes(BiomeStorage biomeStorage) { this.biomeStorage = new BiomeStorage(biomeStorage.g, BukkitAdapter_1_16_2.getBiomeArray(biomeStorage).clone()); } @@ -106,8 +123,18 @@ public class BukkitGetBlocks_1_16_2_Copy extends BukkitGetBlocks_1_16_2 { return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null; } - protected void storeSection(int layer) { - blocks[layer] = update(layer, null).clone(); + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; } @Override @@ -116,15 +143,50 @@ public class BukkitGetBlocks_1_16_2_Copy extends BukkitGetBlocks_1_16_2 { return state.toBaseBlock(this, x, y, z); } + @Override + public boolean hasSection(@Range(from = 0, to = 15) int layer) { + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + return blocks[layer]; + } + @Override public BlockState getBlock(int x, int y, int z) { return BlockTypesCache.states[get(x, y, z)]; } @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + public char get(int x, int y, int z) { final int layer = y >> 4; final int index = (y & 15) << 8 | z << 4 | x; return blocks[layer][index]; } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/FAWEWorldNativeAccess_1_16.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/FAWEWorldNativeAccess_1_16.java index 664fd0609..4c00de05e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/FAWEWorldNativeAccess_1_16.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/FAWEWorldNativeAccess_1_16.java @@ -59,7 +59,7 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException { - return this.adapter.setBlock(this.getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).bukkitChunk, position.getBlockX(), position.getBlockY(), position.getBlockZ(), block, sideEffectSet.shouldApply(SideEffect.LIGHTING)); - } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/nbt/LazyCompoundTag_1_16_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/nbt/LazyCompoundTag_1_16_2.java index bd1d869ff..d43ef3f11 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/nbt/LazyCompoundTag_1_16_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/nbt/LazyCompoundTag_1_16_2.java @@ -12,15 +12,18 @@ import net.minecraft.server.v1_16_R2.NBTTagList; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; public class LazyCompoundTag_1_16_2 extends CompoundTag { + private final Supplier nmsTag; + private CompoundTag cachedValue; public LazyCompoundTag_1_16_2(Supplier tag) { - super(null); + super(new HashMap<>()); this.nmsTag = tag; } @@ -34,12 +37,10 @@ public class LazyCompoundTag_1_16_2 extends CompoundTag { @Override public Map getValue() { - Map value = super.getValue(); - if (value == null) { - Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get()); - setValue(((CompoundTag) tag).getValue()); + if (cachedValue == null) { + cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get()); } - return super.getValue(); + return cachedValue.getValue(); } public boolean containsKey(String key) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitAdapter_1_16_4.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitAdapter_1_16_4.java index 6e0ca22a1..e4101a22f 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitAdapter_1_16_4.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitAdapter_1_16_4.java @@ -199,51 +199,52 @@ public final class BukkitAdapter_1_16_4 extends NMSAdapter { return; } if (playerChunk.hasBeenLoaded()) { - TaskManager.IMP.sync(() -> { - ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); - Optional optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); - if (optional.isPresent()) { - PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(optional.get(), 65535); + ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); + Optional optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); + if (optional.isPresent()) { + PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(optional.get(), 65535); + playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { + p.playerConnection.sendPacket(chunkpacket); + }); + + if (lighting) { + //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) + boolean trustEdges = true; + PacketPlayOutLightUpdate packet = + new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), + trustEdges); playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { - p.playerConnection.sendPacket(chunkpacket); + p.playerConnection.sendPacket(packet); }); + } + } else if (PaperLib.isPaper()) { + //Require generic here to work with multiple dependencies trying to take control. + PooledLinkedHashSets.PooledObjectLinkedOpenHashSet objects = + nmsWorld.getChunkProvider().playerChunkMap.playerViewDistanceNoTickMap + .getObjectsInRange(chunkX, chunkZ); + if (objects == null) { + return; + } + for (Object obj : objects.getBackingSet()) { + if (obj == null) { + continue; + } + EntityPlayer p = (EntityPlayer) obj; + Chunk chunk = nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ); + if (chunk != null) { + PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(chunk, 65535); + p.playerConnection.sendPacket(chunkpacket); - if (lighting) { - boolean trustEdges = true; //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) - PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges); - playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { + if (lighting) { + //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) + boolean trustEdges = true; + PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, + nmsWorld.getChunkProvider().getLightEngine(), trustEdges); p.playerConnection.sendPacket(packet); - }); - } - } else if (PaperLib.isPaper()) { - //Require generic here to work with multiple dependencies trying to take control. - PooledLinkedHashSets.PooledObjectLinkedOpenHashSet objects = - nmsWorld.getChunkProvider().playerChunkMap.playerViewDistanceNoTickMap.getObjectsInRange(chunkX, chunkZ); - if (objects == null) { - return null; - } - for (Object obj : objects.getBackingSet()) { - if (obj == null) { - continue; - } - EntityPlayer p = (EntityPlayer) obj; - Chunk chunk = nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ); - if (chunk != null) { - PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(chunk, 65535); - p.playerConnection.sendPacket(chunkpacket); - - if (lighting) { - boolean trustEdges = - true; //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad) - PacketPlayOutLightUpdate packet = - new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges); - p.playerConnection.sendPacket(packet); - } } } } - return null; - }); + } } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java index 962fd3a7b..d07e4b8f2 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java @@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; -import com.boydti.fawe.beta.implementation.blocks.CharBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.lighting.HeightMapType; import com.boydti.fawe.beta.implementation.queue.QueueHandler; @@ -91,6 +90,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { public NibbleArray[] skyLight = new NibbleArray[16]; private boolean createCopy = false; private BukkitGetBlocks_1_16_4_Copy copy = null; + private boolean forceLoadSections = true; public BukkitGetBlocks_1_16_4(World world, int chunkX, int chunkZ) { this(((CraftWorld) world).getHandle(), chunkX, chunkZ); @@ -319,7 +319,8 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { @Override public > T call(IChunkSet set, Runnable finalizer) { - copy = createCopy ? new BukkitGetBlocks_1_16_4_Copy(world, getChunkX(), getChunkZ()) : null; + forceLoadSections = false; + copy = createCopy ? new BukkitGetBlocks_1_16_4_Copy(world) : null; try { WorldServer nmsWorld = world; Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); @@ -360,13 +361,14 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { if (!set.hasSection(layer)) { continue; } - if (createCopy) { - copy.storeSection(layer); - } bitMask |= 1 << layer; - char[] setArr = set.load(layer); + char[] setArr = set.load(layer).clone(); + if (createCopy) { + copy.storeSection(layer, load(layer).clone()); + } + ChunkSection newSection; ChunkSection existingSection = sections[layer]; if (existingSection == null) { @@ -395,7 +397,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { this.nmsChunk = nmsChunk; this.sections = null; this.reset(); - } else if (existingSection != getSections()[layer]) { + } else if (existingSection != getSections(false)[layer]) { this.sections[layer] = existingSection; this.reset(); } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { @@ -408,7 +410,6 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { if (!BukkitAdapter_1_16_4 .setSectionAtomic(sections, existingSection, newSection, layer)) { log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer); - continue; } else { updateGet(this, nmsChunk, sections, newSection, setArr, layer); } @@ -475,9 +476,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { Set entityRemoves = set.getEntityRemoves(); if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } + syncTasks = new Runnable[3]; syncTasks[2] = () -> { final List[] entities = nmsChunk.getEntitySlices(); @@ -637,12 +636,14 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { } catch (Throwable e) { e.printStackTrace(); return null; + } finally { + forceLoadSections = true; } } @Override public synchronized char[] update(int layer, char[] data) { - ChunkSection section = getSections()[layer]; + ChunkSection section = getSections(true)[layer]; // Section is null, return empty array if (section == null) { data = new char[4096]; @@ -757,7 +758,10 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { } } - public ChunkSection[] getSections() { + public ChunkSection[] getSections(boolean force) { + if (force && forceLoadSections) { + return sections = getChunk().getSections().clone(); + } ChunkSection[] tmp = sections; if (tmp == null) { synchronized (this) { @@ -809,7 +813,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { @Override public boolean hasSection(int layer) { - return getSections()[layer] != null; + return getSections(false)[layer] != null; } @Override @@ -822,10 +826,10 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks { return super.trim(true); } else { for (int i = 0; i < 16; i++) { - if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) { + if (!hasSection(i) || !super.sections[i].isFull()) { continue; } - ChunkSection existing = getSections()[i]; + ChunkSection existing = getSections(true)[i]; try { final DataPaletteBlock blocksExisting = existing.getBlocks(); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4_Copy.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4_Copy.java index 2eec240cb..3f1db2730 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4_Copy.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4_Copy.java @@ -2,6 +2,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_16_4; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.IBlocks; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.lighting.HeightMapType; import com.boydti.fawe.bukkit.adapter.mc1_16_4.nbt.LazyCompoundTag_1_16_4; import com.google.common.base.Suppliers; import com.sk89q.jnbt.CompoundTag; @@ -22,22 +26,25 @@ import net.minecraft.server.v1_16_R3.TileEntity; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.Future; -public class BukkitGetBlocks_1_16_4_Copy extends BukkitGetBlocks_1_16_4 { +public class BukkitGetBlocks_1_16_4_Copy implements IChunkGet { private final Map tiles = new HashMap<>(); private final Set entities = new HashSet<>(); private BiomeStorage biomeStorage; - private final char[][] blocks = new char[16][4096]; + private final char[][] blocks = new char[16][]; + private final WorldServer world; - protected BukkitGetBlocks_1_16_4_Copy(WorldServer world, int X, int Z) { - super(world, X, Z); + protected BukkitGetBlocks_1_16_4_Copy(WorldServer world) { + this.world = world; } protected void storeTile(TileEntity tile) { @@ -88,6 +95,16 @@ public class BukkitGetBlocks_1_16_4_Copy extends BukkitGetBlocks_1_16_4 { return null; } + @Override + public void setCreateCopy(boolean createCopy) { + + } + + @Override + public boolean isCreateCopy() { + return false; + } + protected void storeBiomes(BiomeStorage biomeStorage) { this.biomeStorage = new BiomeStorage(biomeStorage.g, BukkitAdapter_1_16_4.getBiomeArray(biomeStorage).clone()); } @@ -106,8 +123,18 @@ public class BukkitGetBlocks_1_16_4_Copy extends BukkitGetBlocks_1_16_4 { return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null; } - protected void storeSection(int layer) { - blocks[layer] = update(layer, null).clone(); + @Override + public boolean trim(boolean aggressive, int layer) { + return false; + } + + @Override + public IBlocks reset() { + return null; + } + + protected void storeSection(int layer, char[] data) { + blocks[layer] = data; } @Override @@ -116,15 +143,50 @@ public class BukkitGetBlocks_1_16_4_Copy extends BukkitGetBlocks_1_16_4 { return state.toBaseBlock(this, x, y, z); } + @Override + public boolean hasSection(@Range(from = 0, to = 15) int layer) { + return blocks[layer] != null; + } + + @Override + public char[] load(int layer) { + return blocks[layer]; + } + @Override public BlockState getBlock(int x, int y, int z) { return BlockTypesCache.states[get(x, y, z)]; } @Override + public int getSkyLight(int x, int y, int z) { + return 0; + } + + @Override + public int getEmmittedLight(int x, int y, int z) { + return 0; + } + + @Override + public int[] getHeightMap(HeightMapType type) { + return new int[0]; + } + + @Override + public > T call(IChunkSet set, Runnable finalize) { + return null; + } + public char get(int x, int y, int z) { final int layer = y >> 4; final int index = (y & 15) << 8 | z << 4 | x; return blocks[layer][index]; } + + + @Override + public boolean trim(boolean aggressive) { + return false; + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/FAWEWorldNativeAccess_1_16.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/FAWEWorldNativeAccess_1_16.java index b86902067..3116a75d0 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/FAWEWorldNativeAccess_1_16.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/FAWEWorldNativeAccess_1_16.java @@ -60,7 +60,7 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException { - return this.adapter.setBlock(this.getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).bukkitChunk, position.getBlockX(), position.getBlockY(), position.getBlockZ(), block, sideEffectSet.shouldApply(SideEffect.LIGHTING)); - } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/nbt/LazyCompoundTag_1_16_4.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/nbt/LazyCompoundTag_1_16_4.java index 7cc5cdc87..73e416f35 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/nbt/LazyCompoundTag_1_16_4.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/nbt/LazyCompoundTag_1_16_4.java @@ -12,15 +12,18 @@ import net.minecraft.server.v1_16_R3.NBTTagList; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; public class LazyCompoundTag_1_16_4 extends CompoundTag { + private final Supplier nmsTag; + private CompoundTag cachedValue; public LazyCompoundTag_1_16_4(Supplier tag) { - super(null); + super(new HashMap<>()); this.nmsTag = tag; } @@ -34,12 +37,10 @@ public class LazyCompoundTag_1_16_4 extends CompoundTag { @Override public Map getValue() { - Map value = super.getValue(); - if (value == null) { - Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get()); - setValue(((CompoundTag) tag).getValue()); + if (cachedValue == null) { + cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get()); } - return super.getValue(); + return cachedValue.getValue(); } public boolean containsKey(String key) { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/regions/plotsquared/FaweSchematicHandler.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/regions/plotsquared/FaweSchematicHandler.java index 5704bb9e9..0a9b9b4f1 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/regions/plotsquared/FaweSchematicHandler.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/regions/plotsquared/FaweSchematicHandler.java @@ -1,6 +1,5 @@ package com.boydti.fawe.bukkit.regions.plotsquared; -import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.clipboard.ReadOnlyClipboard; import com.boydti.fawe.object.io.PGZIPOutputStream; @@ -9,36 +8,46 @@ import com.boydti.fawe.util.IOUtil; import com.boydti.fawe.util.TaskManager; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.location.Location; +import com.plotsquared.core.plot.schematic.Schematic; import com.plotsquared.core.queue.LocalBlockQueue; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.SchematicHandler; import com.plotsquared.core.util.task.RunnableVal; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompressedCompoundTag; -import com.sk89q.jnbt.CompressedSchematicTag; +import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.Tag; +import com.sk89q.jnbt.fawe.CompressedSchematicTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.FastSchematicReader; import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter; +import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader; +import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.World; import net.jpountz.lz4.LZ4BlockInputStream; +import org.jetbrains.annotations.NotNull; +import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.EOFException; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.zip.GZIPInputStream; import static org.bukkit.Bukkit.getWorld; @@ -114,16 +123,14 @@ public class FaweSchematicHandler extends SchematicHandler { com.plotsquared.core.util.task.TaskManager.runTask(whenDone); return; } - CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag); - if (weTag instanceof CompressedSchematicTag) { - Clipboard clipboard = ((CompressedSchematicTag) weTag).getSource(); - URL url = FaweAPI.upload(clipboard, BuiltInClipboardFormat.SPONGE_SCHEMATIC); - whenDone.run(url); - return; - } + final CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag); MainUtil.upload(uuid, file, "schem", new RunnableVal() { @Override public void run(OutputStream output) { + if (weTag instanceof CompressedSchematicTag) { + Clipboard clipboard = ((CompressedSchematicTag) weTag).getSource(); + BuiltInClipboardFormat.SPONGE_SCHEMATIC.write(output, clipboard); + } try { try (PGZIPOutputStream gzip = new PGZIPOutputStream(output)) { try (NBTOutputStream nos = new NBTOutputStream(gzip)) { @@ -137,4 +144,42 @@ public class FaweSchematicHandler extends SchematicHandler { } }, whenDone); } + + @Override + public Schematic getSchematic(@NotNull InputStream is) { + try { + FastSchematicReader schematicReader = new FastSchematicReader( + new NBTInputStream(new BufferedInputStream(new GZIPInputStream(new BufferedInputStream(is))))); + Clipboard clip = schematicReader.read(); + return new Schematic(clip); + } catch (IOException e) { + if (e instanceof EOFException) { + e.printStackTrace(); + return null; + } + try { + SpongeSchematicReader schematicReader = + new SpongeSchematicReader(new NBTInputStream(new GZIPInputStream(is))); + Clipboard clip = schematicReader.read(); + return new Schematic(clip); + } catch (IOException e2) { + if (e2 instanceof EOFException) { + e.printStackTrace(); + return null; + } + try { + MCEditSchematicReader schematicReader = + new MCEditSchematicReader(new NBTInputStream(new GZIPInputStream(is))); + Clipboard clip = schematicReader.read(); + return new Schematic(clip); + } catch (IOException e3) { + e.printStackTrace(); + PlotSquared.debug( + is.toString() + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e + .getMessage()); + } + } + } + return null; + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/regions/plotsquaredv4/FaweSchematicHandler.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/regions/plotsquaredv4/FaweSchematicHandler.java index c0539e682..2a2199b60 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/regions/plotsquaredv4/FaweSchematicHandler.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/regions/plotsquaredv4/FaweSchematicHandler.java @@ -15,7 +15,7 @@ import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler; import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompressedCompoundTag; -import com.sk89q.jnbt.CompressedSchematicTag; +import com.sk89q.jnbt.fawe.CompressedSchematicTag; import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.EditSession; @@ -65,6 +65,7 @@ public class FaweSchematicHandler extends SchematicHandler { ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region, false, true); Clipboard holder = new BlockArrayClipboard(region, clipboard); + CompressedSchematicTag tag = new CompressedSchematicTag(holder); whenDone.run(tag); }); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java index 59c2dc706..ad4b44712 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlock.java @@ -26,8 +26,8 @@ import org.bukkit.plugin.Plugin; import org.bukkit.util.BoundingBox; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -70,32 +70,32 @@ public class AsyncBlock implements Block { return world.getBlock(x, y, z).getBlockType().getInternalId(); } - @NotNull + @Nonnull @Override public AsyncBlock getRelative(int modX, int modY, int modZ) { return new AsyncBlock(world, x + modX, y + modY, z + modZ); } - @NotNull + @Nonnull @Override public AsyncBlock getRelative(BlockFace face) { return this.getRelative(face.getModX(), face.getModY(), face.getModZ()); } - @NotNull + @Nonnull @Override public AsyncBlock getRelative(BlockFace face, int distance) { return this.getRelative(face.getModX() * distance, face.getModY() * distance, face.getModZ() * distance); } - @NotNull + @Nonnull @Override public Material getType() { return getBlockData().getMaterial(); } - @NotNull + @Nonnull @Override public BlockData getBlockData() { return BukkitAdapter.adapt(world.getBlock(x, y, z)); @@ -141,7 +141,7 @@ public class AsyncBlock implements Block { return (byte) 15; } - @NotNull + @Nonnull @Override public AsyncWorld getWorld() { return world; @@ -162,7 +162,7 @@ public class AsyncBlock implements Block { return z; } - @NotNull + @Nonnull @Override public Location getLocation() { return new Location(world, x, y, z); @@ -179,14 +179,14 @@ public class AsyncBlock implements Block { return loc; } - @NotNull + @Nonnull @Override public AsyncChunk getChunk() { return world.getChunkAt(x >> 4, z >> 4); } @Override - public void setBlockData(@NotNull BlockData blockData) { + public void setBlockData(@Nonnull BlockData blockData) { try { world.setBlock(x, y, z, BukkitAdapter.adapt(blockData)); } catch (WorldEditException e) { @@ -195,12 +195,12 @@ public class AsyncBlock implements Block { } @Override - public void setBlockData(@NotNull BlockData blockData, boolean b) { + public void setBlockData(@Nonnull BlockData blockData, boolean b) { setBlockData(blockData); } @Override - public void setType(@NotNull Material type) { + public void setType(@Nonnull Material type) { try { world.setBlock(x, y, z, BukkitAdapter.asBlockType(type).getDefaultState()); } catch (WorldEditException e) { @@ -209,12 +209,12 @@ public class AsyncBlock implements Block { } @Override - public void setType(@NotNull Material type, boolean applyPhysics) { + public void setType(@Nonnull Material type, boolean applyPhysics) { setType(type); } @Override - public BlockFace getFace(@NotNull Block block) { + public BlockFace getFace(@Nonnull Block block) { BlockFace[] directions = BlockFace.values(); for (BlockFace face : directions) { if (this.getX() + face.getModX() == block.getX() @@ -226,7 +226,7 @@ public class AsyncBlock implements Block { return null; } - @NotNull + @Nonnull @Override public AsyncBlockState getState() { BaseBlock state = world.getFullBlock(x, y, z); @@ -250,19 +250,19 @@ public class AsyncBlock implements Block { } @Override - @NotNull + @Nonnull public AsyncBlockState getState(boolean useSnapshot) { return getState(); } - @NotNull + @Nonnull @Override public Biome getBiome() { return world.getAdapter().adapt(world.getBiomeType(x, y, z)); } @Override - public void setBiome(@NotNull Biome bio) { + public void setBiome(@Nonnull Biome bio) { BiomeType biome = world.getAdapter().adapt(bio); world.setBiome(x, 0, z, biome); } @@ -278,17 +278,17 @@ public class AsyncBlock implements Block { } @Override - public boolean isBlockFacePowered(@NotNull BlockFace face) { + public boolean isBlockFacePowered(@Nonnull BlockFace face) { return false; } @Override - public boolean isBlockFaceIndirectlyPowered(@NotNull BlockFace face) { + public boolean isBlockFaceIndirectlyPowered(@Nonnull BlockFace face) { return false; } @Override - public int getBlockPower(@NotNull BlockFace face) { + public int getBlockPower(@Nonnull BlockFace face) { return 0; } @@ -314,6 +314,21 @@ public class AsyncBlock implements Block { return world.getBlock(x, y, z).getMaterial().isLiquid(); } + @Override + public boolean isBuildable() { + return this.getUnsafeBlock().isBuildable(); + } + + @Override + public boolean isBurnable() { + return this.getType().isBurnable(); + } + + @Override + public boolean isReplaceable() { + return this.getUnsafeBlock().isReplaceable(); + } + @Override public double getTemperature() { return this.getWorld().getTemperature(this.getX(), this.getZ()); @@ -324,7 +339,7 @@ public class AsyncBlock implements Block { return this.getWorld().getHumidity(this.getX(), this.getZ()); } - @NotNull + @Nonnull @Override public PistonMoveReaction getPistonMoveReaction() { return PistonMoveReaction.IGNORE; @@ -341,23 +356,23 @@ public class AsyncBlock implements Block { } @Override - public boolean breakNaturally(@NotNull ItemStack tool) { + public boolean breakNaturally(@Nonnull ItemStack tool) { return TaskManager.IMP.sync(() -> getUnsafeBlock().breakNaturally(tool)); } - public boolean breakNaturally(@NotNull ItemStack tool, boolean value) { + public boolean breakNaturally(@Nonnull ItemStack tool, boolean value) { return TaskManager.IMP.sync(() -> getUnsafeBlock().breakNaturally(tool)); } - @NotNull + @Nonnull @Override public Collection getDrops() { return TaskManager.IMP.sync(() -> getUnsafeBlock().getDrops()); } - @NotNull + @Nonnull @Override - public Collection getDrops(@NotNull ItemStack tool) { + public Collection getDrops(@Nonnull ItemStack tool) { return TaskManager.IMP.sync(() -> getUnsafeBlock().getDrops(tool)); } @@ -366,23 +381,23 @@ public class AsyncBlock implements Block { } @Override - public void setMetadata(@NotNull String metadataKey, @NotNull MetadataValue newMetadataValue) { + public void setMetadata(@Nonnull String metadataKey, @Nonnull MetadataValue newMetadataValue) { this.getUnsafeBlock().setMetadata(metadataKey, newMetadataValue); } - @NotNull + @Nonnull @Override - public List getMetadata(@NotNull String metadataKey) { + public List getMetadata(@Nonnull String metadataKey) { return this.getUnsafeBlock().getMetadata(metadataKey); } @Override - public boolean hasMetadata(@NotNull String metadataKey) { + public boolean hasMetadata(@Nonnull String metadataKey) { return this.getUnsafeBlock().hasMetadata(metadataKey); } @Override - public void removeMetadata(@NotNull String metadataKey, @NotNull Plugin owningPlugin) { + public void removeMetadata(@Nonnull String metadataKey, @Nonnull Plugin owningPlugin) { this.getUnsafeBlock().removeMetadata(metadataKey, owningPlugin); } @@ -392,12 +407,12 @@ public class AsyncBlock implements Block { } @Override - public RayTraceResult rayTrace(@NotNull Location arg0, @NotNull Vector arg1, double arg2, - @NotNull FluidCollisionMode arg3) { + public RayTraceResult rayTrace(@Nonnull Location arg0, @Nonnull Vector arg1, double arg2, + @Nonnull FluidCollisionMode arg3) { return this.getUnsafeBlock().rayTrace(arg0, arg1, arg2, arg3); } - public boolean applyBoneMeal(@NotNull BlockFace face) { + public boolean applyBoneMeal(@Nonnull BlockFace face) { throw new UnsupportedOperationException("FAWE does not support this yet"); } @@ -405,22 +420,28 @@ public class AsyncBlock implements Block { throw new UnsupportedOperationException("FAWE does not support this yet"); } - @NotNull + @Nonnull @Override - public float getDestroySpeed(@NotNull ItemStack itemStack) { + public float getDestroySpeed(@Nonnull ItemStack itemStack) { throw new UnsupportedOperationException("FAWE does not support this yet"); } - @NotNull + @Nonnull @Override public BoundingBox getBoundingBox() { return this.getUnsafeBlock().getBoundingBox(); } @Override - @NotNull + @Nonnull public BlockSoundGroup getSoundGroup() { return TaskManager.IMP.sync(() -> getUnsafeBlock().getSoundGroup()); } + + @Override + @Nonnull + public boolean isSolid() { + return this.getType().isSolid(); + } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java index c8ab44cfe..03d1dd07c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncBlockState.java @@ -1,6 +1,7 @@ package com.boydti.fawe.bukkit.wrapper; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.world.block.BaseBlock; @@ -16,8 +17,12 @@ import org.bukkit.material.MaterialData; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Optional; public class AsyncBlockState implements BlockState { @@ -25,10 +30,6 @@ public class AsyncBlockState implements BlockState { private BlockData blockData; private final AsyncBlock block; - public AsyncBlockState(AsyncBlock block) { - this(block, block.world.getFullBlock(block.x, block.y, block.z)); - } - public AsyncBlockState(AsyncBlock block, BaseBlock state) { this.state = state; this.block = block; @@ -112,11 +113,11 @@ public class AsyncBlockState implements BlockState { @Override public void setBlockData(BlockData blockData) { this.blockData = blockData; - CompoundTag nbt = state.getNbtData(); + CompoundTag nbt = this.getNbtData(); BlockType oldType = state.getBlockType(); com.sk89q.worldedit.world.block.BlockState newState = BukkitAdapter.adapt(blockData); if (nbt != null && newState.getBlockType() == oldType) { - state = newState.toBaseBlock(nbt); + this.setNbtData(nbt); } else { state = newState.toBaseBlock(); } @@ -146,14 +147,47 @@ public class AsyncBlockState implements BlockState { } } - public CompoundTag getNbtData() { + /** + * Returns the (unmodifiable) tag compound that belongs to this block state. + * If the block state is null, this will return null. + * + * @return NBT data + */ + public synchronized @Nullable CompoundTag getNbtData() { + if (this.state == null) { + return null; + } return state.getNbtData(); } - public void setNbtData(CompoundTag nbt) { + /** + * Clone the NBT {@link CompoundTag} into a new {@link Map}. + * + * @return Modifiable clone of NBT data + */ + public @NotNull Map cloneNbtMap() { + return Optional.ofNullable(this.getNbtData()).map(CompoundTag::getValue) + .map(HashMap::new).orElse(new HashMap<>()); + } + + /** + * Set the NBT data of the block. + * + * @param nbt New NBT data + */ + public synchronized void setNbtData(@Nullable final CompoundTag nbt) { state = this.state.toBaseBlock(nbt); } + /** + * Set the NBT data of the block. + * + * @param map New NBT data + */ + public void setNbtData(@NotNull final Map map) { + this.setNbtData(new CompoundTag(map)); + } + @Override public byte getRawData() { return (byte) (state.getInternalId() >> BlockTypesCache.BIT_OFFSET); @@ -163,7 +197,7 @@ public class AsyncBlockState implements BlockState { public void setRawData(byte data) { int combinedId = getTypeId() + (data << BlockTypesCache.BIT_OFFSET); state = com.sk89q.worldedit.world.block.BlockState.getFromInternalId(combinedId) - .toBaseBlock(state.getNbtData()); + .toBaseBlock(this.getNbtData()); this.blockData = BukkitAdapter.adapt(state); } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java index 590668be6..030e86c78 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncChunk.java @@ -6,6 +6,7 @@ import com.boydti.fawe.util.TaskManager; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; @@ -14,6 +15,8 @@ import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; import java.util.Collection; +import java.util.Collections; +import java.util.function.Predicate; import java.util.function.Supplier; public class AsyncChunk implements Chunk { @@ -120,6 +123,16 @@ public class AsyncChunk implements Chunk { return TaskManager.IMP.sync(() -> world.getChunkAt(x, z).getTileEntities(useSnapshot)); } + @NotNull @Override + public Collection getTileEntities(@NotNull Predicate blockPredicate, + boolean useSnapshot) { + if (!isLoaded()) { + return Collections.emptyList(); + } + return TaskManager.IMP.sync(() -> world.getChunkAt(x, z) + .getTileEntities(blockPredicate, useSnapshot)); + } + @Override public boolean isLoaded() { return world.isChunkLoaded(x, z); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java index 0e29f2f19..f57ca8553 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncDataContainer.java @@ -16,17 +16,24 @@ import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; public final class AsyncDataContainer implements PersistentDataContainer { - private final CompoundTag root; - public AsyncDataContainer(CompoundTag root) { - this.root = root; + private final Supplier supplier; + private final Consumer consumer; + + public AsyncDataContainer( + final @NotNull Supplier supplier, + final @NotNull Consumer consumer + ) { + this.supplier = supplier; + this.consumer = consumer; } private CompoundTag root() { - CompoundTag value = (CompoundTag) root.getValue().get("PublicBukkitValues"); - return value; + return (CompoundTag) supplier.get().getValue().get("PublicBukkitValues"); } private Map get() { @@ -40,8 +47,9 @@ public final class AsyncDataContainer implements PersistentDataContainer { if (!create) { return Collections.emptyMap(); } - Map map = root.getValue(); + final Map map = new HashMap<>(root().getValue()); map.put("PublicBukkitValues", new CompoundTag(raw = new HashMap<>())); + this.consumer.accept(new CompoundTag(map)); } else { raw = tag.getValue(); } @@ -52,7 +60,14 @@ public final class AsyncDataContainer implements PersistentDataContainer { Validate.notNull(key, "The provided key for the custom value was null"); Validate.notNull(type, "The provided type for the custom value was null"); Validate.notNull(value, "The provided value for the custom value was null"); - get().put(key.toString(), FaweCache.IMP.asTag(type.toPrimitive(value, null))); + // Modify public values + final Map publicValues = new HashMap<>(this.get()); + publicValues.put(key.toString(), FaweCache.IMP.asTag(type.toPrimitive(value, null))); + // Modify the root tag + final Map map = new HashMap<>(root().getValue()); + map.put("PublicBukkitValues", new CompoundTag(publicValues)); + // Update the owning object + this.consumer.accept(new CompoundTag(map)); } public boolean has(NamespacedKey key, PersistentDataType type) { @@ -60,7 +75,7 @@ public final class AsyncDataContainer implements PersistentDataContainer { Validate.notNull(type, "The provided type for the custom value was null"); Tag value = get(false).get(key.toString()); if (value == null) { - return type == null; + return false; } return type.getPrimitiveType() == value.getValue().getClass(); } @@ -93,7 +108,14 @@ public final class AsyncDataContainer implements PersistentDataContainer { public void remove(NamespacedKey key) { Validate.notNull(key, "The provided key for the custom value was null"); - get(false).remove(key.toString()); + // Modify public values + final Map publicValues = new HashMap<>(this.get(false)); + publicValues.remove(key.toString()); + // Modify the root tag + final Map map = new HashMap<>(root().getValue()); + map.put("PublicBukkitValues", new CompoundTag(publicValues)); + // Update the owning object + this.consumer.accept(new CompoundTag(map)); } public boolean isEmpty() { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java index 85d7960e5..34e1c923e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/wrapper/state/AsyncSign.java @@ -19,6 +19,7 @@ import java.util.Locale; import java.util.Map; public class AsyncSign extends AsyncBlockState implements Sign { + public AsyncSign(AsyncBlock block, BaseBlock state) { super(block, state); } @@ -59,11 +60,12 @@ public class AsyncSign extends AsyncBlockState implements Sign { @Override public void setLine(int index, String line) throws IndexOutOfBoundsException { - CompoundTag nbt = getNbtData(); - if (nbt != null) { - Map map = nbt.getValue(); - map.put("Text" + (index + 1), new StringTag(toJson(line))); + final Map map = this.cloneNbtMap(); + if (map.isEmpty()) { + return; } + map.put("Text" + (index + 1), new StringTag(toJson(line))); + this.setNbtData(map); } @Override @@ -79,13 +81,13 @@ public class AsyncSign extends AsyncBlockState implements Sign { @Override @NotNull public PersistentDataContainer getPersistentDataContainer() { - return new AsyncDataContainer(getNbtData()); + return new AsyncDataContainer(this::getNbtData, this::setNbtData); } @Override @Nullable public DyeColor getColor() { - CompoundTag nbt = getNbtData(); + CompoundTag nbt = this.getNbtData(); if (nbt != null) { String color = nbt.getString("Color").toUpperCase(Locale.ROOT); if (!color.isEmpty()) { @@ -97,10 +99,11 @@ public class AsyncSign extends AsyncBlockState implements Sign { @Override public void setColor(DyeColor color) { - CompoundTag nbt = getNbtData(); - if (nbt != null) { - Map map = nbt.getValue(); - map.put("Color", new StringTag(color.name().toLowerCase(Locale.ROOT))); + final Map map = this.cloneNbtMap(); + if (map.isEmpty()) { + return; } + map.put("Color", new StringTag(color.name().toLowerCase(Locale.ROOT))); + this.setNbtData(map); } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index f2d2e1347..500d3796e 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.bukkit; - import com.boydti.fawe.Fawe; import com.boydti.fawe.bukkit.FaweBukkit; import com.google.common.base.Joiner; @@ -93,19 +92,6 @@ import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAM */ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter - // This must be before the Logger is initialized, which fails in 1.8 - private static final String FAILED_VERSION_CHECK = - "\n**********************************************\n" - + "** This Minecraft version (%s) is not supported by this version of WorldEdit.\n" - + "** Please download an OLDER version of WorldEdit which does.\n" - + "**********************************************\n"; - - static { - if (PaperLib.getMinecraftVersion() < 13) { - throw new IllegalStateException(String.format(FAILED_VERSION_CHECK, Bukkit.getVersion())); - } - } - private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class); public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; private static WorldEditPlugin INSTANCE; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_15_R2.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_15_R2.java index 58e86eb92..dec7822ca 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_15_R2.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_15_R2.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl; -import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.implementation.packet.ChunkPacket; @@ -93,20 +92,21 @@ import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack; import org.bukkit.entity.Player; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; +import java.util.HashMap; import java.util.Map; import java.util.OptionalInt; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Stream; -import javax.annotation.Nullable; -import static com.google.common.base.Preconditions.checkNotNull; import static org.slf4j.LoggerFactory.getLogger; public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter { private final Spigot_v1_15_R2 parent; private char[] ibdToStateOrdinal; + private int[] ordinalToIbdID; // ------------------------------------------------------------------------ // Code that may break between versions of Minecraft // ------------------------------------------------------------------------ @@ -124,12 +124,15 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { return false; } - ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size for (int i = 0; i < ibdToStateOrdinal.length; i++) { BlockState state = BlockTypesCache.states[i]; BlockMaterial_1_15_2 material = (BlockMaterial_1_15_2) state.getMaterial(); int id = Block.REGISTRY_ID.getId(material.getState()); - ibdToStateOrdinal[id] = state.getOrdinalChar(); + char ordinal = state.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; } return true; } @@ -267,13 +270,13 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { - NBTTagCompound tag = new NBTTagCompound(); - readEntityIntoTag(mcEntity, tag); - + final NBTTagCompound minecraftTag = new NBTTagCompound(); + readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - CompoundTag natve = (CompoundTag) toNative(tag); - natve.getValue().put("Id", new StringTag(id)); - return natve; + final CompoundTag tag = (CompoundTag) toNative(minecraftTag); + final Map tags = new HashMap<>(tag.getValue()); + tags.put("Id", new StringTag(id)); + return new CompoundTag(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -347,6 +350,16 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I } } } + public int ordinalToIbdID(char ordinal) { + synchronized (this) { + try { + return ordinalToIbdID[ordinal]; + } catch (NullPointerException e) { + init(); + return ordinalToIbdID(ordinal); + } + } + } @Override public > BlockData adapt(B state) { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R1.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R1.java index cd3625917..1040c913a 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R1.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R1.java @@ -92,20 +92,21 @@ import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack; import org.bukkit.entity.Player; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; +import java.util.HashMap; import java.util.Map; import java.util.OptionalInt; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Stream; -import javax.annotation.Nullable; -import static com.google.common.base.Preconditions.checkNotNull; import static org.slf4j.LoggerFactory.getLogger; public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter { private final Spigot_v1_16_R1 parent; private char[] ibdToStateOrdinal; + private int[] ordinalToIbdID; // ------------------------------------------------------------------------ // Code that may break between versions of Minecraft // ------------------------------------------------------------------------ @@ -123,12 +124,15 @@ public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements I if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { return false; } - ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size for (int i = 0; i < ibdToStateOrdinal.length; i++) { BlockState state = BlockTypesCache.states[i]; BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial(); int id = Block.REGISTRY_ID.getId(material.getState()); - ibdToStateOrdinal[id] = state.getOrdinalChar(); + char ordinal = state.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; } return true; } @@ -266,13 +270,13 @@ public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements I if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { - NBTTagCompound tag = new NBTTagCompound(); - readEntityIntoTag(mcEntity, tag); - + final NBTTagCompound minecraftTag = new NBTTagCompound(); + readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - CompoundTag natve = (CompoundTag) toNative(tag); - natve.getValue().put("Id", new StringTag(id)); - return natve; + final CompoundTag tag = (CompoundTag) toNative(minecraftTag); + final Map tags = new HashMap<>(tag.getValue()); + tags.put("Id", new StringTag(id)); + return new CompoundTag(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -347,6 +351,17 @@ public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements I } } + public int ordinalToIbdID(char ordinal) { + synchronized (this) { + try { + return ordinalToIbdID[ordinal]; + } catch (NullPointerException e) { + init(); + return ordinalToIbdID(ordinal); + } + } + } + @Override public > BlockData adapt(B state) { BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial(); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R2.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R2.java index 966831373..b22d4b3ef 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R2.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R2.java @@ -92,20 +92,22 @@ import org.bukkit.craftbukkit.v1_16_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack; import org.bukkit.entity.Player; + +import javax.annotation.Nullable; import java.lang.ref.WeakReference; +import java.util.HashMap; import java.util.Map; import java.util.OptionalInt; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Stream; -import javax.annotation.Nullable; -import static com.google.common.base.Preconditions.checkNotNull; import static org.slf4j.LoggerFactory.getLogger; public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter { private final Spigot_v1_16_R2 parent; private char[] ibdToStateOrdinal; + private int[] ordinalToIbdID; // ------------------------------------------------------------------------ // Code that may break between versions of Minecraft @@ -124,12 +126,15 @@ public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements I if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { return false; } - ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size for (int i = 0; i < ibdToStateOrdinal.length; i++) { BlockState state = BlockTypesCache.states[i]; BlockMaterial_1_16_2 material = (BlockMaterial_1_16_2) state.getMaterial(); int id = Block.REGISTRY_ID.getId(material.getState()); - ibdToStateOrdinal[id] = state.getOrdinalChar(); + char ordinal = state.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; } return true; } @@ -267,13 +272,13 @@ public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements I if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { - NBTTagCompound tag = new NBTTagCompound(); - readEntityIntoTag(mcEntity, tag); - + final NBTTagCompound minecraftTag = new NBTTagCompound(); + readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - CompoundTag natve = (CompoundTag) toNative(tag); - natve.getValue().put("Id", new StringTag(id)); - return natve; + final CompoundTag tag = (CompoundTag) toNative(minecraftTag); + final Map tags = new HashMap<>(tag.getValue()); + tags.put("Id", new StringTag(id)); + return new CompoundTag(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -347,6 +352,16 @@ public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements I } } } + public int ordinalToIbdID(char ordinal) { + synchronized (this) { + try { + return ordinalToIbdID[ordinal]; + } catch (NullPointerException e) { + init(); + return ordinalToIbdID(ordinal); + } + } + } @Override public > BlockData adapt(B state) { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R3.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R3.java index 79fc3499b..0682cdee9 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R3.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_16_R3.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl; -import com.bekvon.bukkit.residence.commands.material; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.implementation.packet.ChunkPacket; @@ -96,6 +95,7 @@ import org.bukkit.entity.Player; import javax.annotation.Nullable; import java.lang.ref.WeakReference; +import java.util.HashMap; import java.util.Map; import java.util.OptionalInt; import java.util.Set; @@ -107,6 +107,7 @@ import static org.slf4j.LoggerFactory.getLogger; public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter { private final Spigot_v1_16_R3 parent; private char[] ibdToStateOrdinal; + private int[] ordinalToIbdID; // ------------------------------------------------------------------------ // Code that may break between versions of Minecraft @@ -125,12 +126,15 @@ public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements I if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) { return false; } - ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size + ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size + ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size for (int i = 0; i < ibdToStateOrdinal.length; i++) { BlockState state = BlockTypesCache.states[i]; BlockMaterial_1_16_4 material = (BlockMaterial_1_16_4) state.getMaterial(); int id = Block.REGISTRY_ID.getId(material.getState()); - ibdToStateOrdinal[id] = state.getOrdinalChar(); + char ordinal = state.getOrdinalChar(); + ibdToStateOrdinal[id] = ordinal; + ordinalToIbdID[ordinal] = id; } return true; } @@ -268,13 +272,13 @@ public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements I if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { - NBTTagCompound tag = new NBTTagCompound(); - readEntityIntoTag(mcEntity, tag); - + final NBTTagCompound minecraftTag = new NBTTagCompound(); + readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - CompoundTag natve = (CompoundTag) toNative(tag); - natve.getValue().put("Id", new StringTag(id)); - return natve; + final CompoundTag tag = (CompoundTag) toNative(minecraftTag); + final Map tags = new HashMap<>(tag.getValue()); + tags.put("Id", new StringTag(id)); + return new CompoundTag(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -349,6 +353,17 @@ public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements I } } + public int ordinalToIbdID(char ordinal) { + synchronized (this) { + try { + return ordinalToIbdID[ordinal]; + } catch (NullPointerException e) { + init(); + return ordinalToIbdID(ordinal); + } + } + } + @Override public > BlockData adapt(B state) { BlockMaterial_1_16_4 material = (BlockMaterial_1_16_4) state.getMaterial(); diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index d9f5e8215..24da6be85 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -28,14 +28,14 @@ configurations.all { dependencies { "api"(project(":worldedit-libs:core")) - "implementation"("de.schlichtherle:truezip:6.8.3") - "implementation"("net.java.truevfs:truevfs-profile-default_2.13:0.12.1") + "implementation"("de.schlichtherle:truezip:6.8.4") + "implementation"("net.java.truevfs:truevfs-profile-default_2.13:0.12.2") "implementation"("org.mozilla:rhino-runtime:1.7.12") - "implementation"("org.yaml:snakeyaml:1.23") + "implementation"("org.yaml:snakeyaml:1.27") "implementation"("com.google.guava:guava:${Versions.GUAVA}") "implementation"("com.google.code.findbugs:jsr305:3.0.2") "implementation"("com.google.code.gson:gson:${Versions.GSON}") - "implementation"("org.slf4j:slf4j-api:1.7.27") + "implementation"("org.slf4j:slf4j-api:1.7.30") "implementation"("it.unimi.dsi:fastutil:${Versions.FAST_UTIL}") val antlrVersion = "4.7.2" @@ -51,14 +51,15 @@ dependencies { "annotationProcessor"("com.google.auto.value:auto-value:${Versions.AUTO_VALUE}") "testImplementation"("ch.qos.logback:logback-core:${Versions.LOGBACK}") "testImplementation"("ch.qos.logback:logback-classic:${Versions.LOGBACK}") - "compile"("com.github.luben:zstd-jni:1.4.3-1") + "compile"("com.github.luben:zstd-jni:1.4.8-1") "compileOnly"("net.fabiozumbi12:redprotect:1.9.6") "compile"("com.github.intellectualsites.plotsquared:PlotSquared-API:latest") { isTransitive = false } - "compile"("com.plotsquared:PlotSquared-Core:5.12.2") { + "compile"("com.plotsquared:PlotSquared-Core:5.13.3") { isTransitive = false } + "api"("com.intellectualsites.paster:Paster:1.0.1-SNAPSHOT") } tasks.named("test") { @@ -109,7 +110,7 @@ tasks.named("processResources") { } tasks.named("shadowJar") { dependencies { - include(dependency("com.github.luben:zstd-jni:1.4.3-1")) + include(dependency("com.github.luben:zstd-jni:1.4.8-1")) } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java index dab5fc305..41104b552 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/Fawe.java @@ -235,8 +235,8 @@ public class Fawe { // Setting up config.yml File file = new File(this.implementation.getDirectory(), "config.yml"); Settings.IMP.PLATFORM = implementation.getPlatform().replace("\"", ""); - try (InputStream stream = getClass().getResourceAsStream(File.separator + "fawe.properties"); - BufferedReader br = new BufferedReader(new InputStreamReader(stream))) { + try (InputStream stream = getClass().getResourceAsStream("/fawe.properties"); + BufferedReader br = new BufferedReader(new InputStreamReader(stream))) { String versionString = br.readLine(); String commitString = br.readLine(); String dateString = br.readLine(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java index 52ddbb1e7..7264b47ba 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -9,39 +9,57 @@ import org.jetbrains.annotations.Range; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.locks.ReentrantLock; + public abstract class CharBlocks implements IBlocks { public static final Logger logger = LoggerFactory.getLogger(CharBlocks.class); - public static final Section FULL = new Section() { + protected static final Section FULL = new Section() { @Override public final char[] get(CharBlocks blocks, int layer) { return blocks.blocks[layer]; } - }; - public static final Section EMPTY = new Section() { + @Override - public final synchronized char[] get(CharBlocks blocks, int layer) { - char[] arr = blocks.blocks[layer]; - if (arr == null) { - arr = blocks.blocks[layer] = blocks.update(layer, null); + public final boolean isFull() { + return true; + } + }; + protected static final Section EMPTY = new Section() { + @Override + public final char[] get(CharBlocks blocks, int layer) { + blocks.loadLock.lock(); + try { + char[] arr = blocks.blocks[layer]; if (arr == null) { - throw new IllegalStateException("Array cannot be null: " + blocks.getClass()); + arr = blocks.blocks[layer] = blocks.update(layer, null); + if (arr == null) { + throw new IllegalStateException("Array cannot be null: " + blocks.getClass()); + } + } else { + blocks.blocks[layer] = blocks.update(layer, arr); + if (blocks.blocks[layer] == null) { + throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass()); + } } - } else { - blocks.blocks[layer] = blocks.update(layer, arr); - if (blocks.blocks[layer] == null) { - throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass()); + if (blocks.blocks[layer] != null) { + blocks.sections[layer] = FULL; } + return arr; + } finally { + blocks.loadLock.unlock(); } - if (blocks.blocks[layer] != null) { - blocks.sections[layer] = FULL; - } - return arr; + } + + @Override + public final boolean isFull() { + return false; } }; public final char[][] blocks; public final Section[] sections; + private final ReentrantLock loadLock = new ReentrantLock (); public CharBlocks() { blocks = new char[16][]; @@ -55,7 +73,7 @@ public abstract class CharBlocks implements IBlocks { public boolean trim(boolean aggressive) { boolean result = true; for (int i = 0; i < 16; i++) { - if (sections[i] == EMPTY && blocks[i] != null) { + if (!sections[i].isFull() && blocks[i] != null) { blocks[i] = null; } else { result = false; @@ -67,7 +85,7 @@ public abstract class CharBlocks implements IBlocks { @Override public boolean trim(boolean aggressive, int layer) { boolean result = true; - if (sections[layer] == EMPTY && blocks[layer] != null) { + if (!sections[layer].isFull() && blocks[layer] != null) { blocks[layer] = null; } else { result = false; @@ -99,7 +117,7 @@ public abstract class CharBlocks implements IBlocks { @Override public boolean hasSection(@Range(from = 0, to = 15) int layer) { - return sections[layer] == FULL; + return sections[layer].isFull(); } @Override @@ -149,6 +167,8 @@ public abstract class CharBlocks implements IBlocks { public abstract char[] get(CharBlocks blocks, @Range(from = 0, to = 15) int layer); + public abstract boolean isFull(); + public final char get(CharBlocks blocks, @Range(from = 0, to = 15) int layer, int index) { return get(blocks, layer)[index]; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/ParallelQueueExtent.java index 0314c1b6e..1e8bd2301 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/ParallelQueueExtent.java @@ -140,7 +140,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap return // Apply a filter over a region apply(region, searchMask - .toFilter(new CountFilter()), false) // Adapt the mask to a filter which counts + .toFilter(new CountFilter()), searchMask.replacesAir()) // Adapt the mask to a filter which counts .getParent() // Get the counter of this mask .getTotal(); // Get the total from the counter } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/StreamDelegate.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/StreamDelegate.java index a404c8956..eea8b8545 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/StreamDelegate.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/StreamDelegate.java @@ -200,7 +200,7 @@ public class StreamDelegate { Object raw = is.readTagPayloadRaw(type, depth); valueReader.apply(0, raw); } else { - is.readTagPaylodLazy(type, depth + 1, this); + is.readTagPayloadLazy(type, depth + 1, this); } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/AbstractChangeSet.java index dad021ee1..7ee81bb94 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/changeset/AbstractChangeSet.java @@ -137,10 +137,8 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { } if (!tilesTo.isEmpty()) { for (Map.Entry entry : tilesTo.entrySet()) { - CompoundTag nbt = entry.getValue(); BlockVector3 pos = entry.getKey(); - MainUtil.setPosition(nbt, pos.getX() + bx, pos.getY(), pos.getZ() + bz); - addTileCreate(nbt); + addTileCreate(MainUtil.setPosition(entry.getValue(), pos.getX() + bx, pos.getY(), pos.getZ() + bz)); } } Set entRemoves = set.getEntityRemoves(); @@ -176,11 +174,12 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { int zz = z + bz; for (int x = 0; x < 16; x++, index++) { int xx = bx + x; - int combinedFrom = blocksGet[index]; - if (combinedFrom == 0) { - combinedFrom = BlockID.AIR; + int from = blocksGet[index]; + if (from == 0) { + from = BlockID.AIR; } - int combinedTo = blocksSet[index]; + final int combinedFrom = from; + final int combinedTo = blocksSet[index]; if (combinedTo != 0) { add(xx, yy, zz, combinedFrom, combinedTo); } @@ -249,14 +248,12 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { public void add(EntityCreate change) { CompoundTag tag = change.state.getNbtData(); - MainUtil.setEntityInfo(tag, change.getEntity()); - addEntityCreate(tag); + addEntityCreate(MainUtil.setEntityInfo(tag, change.getEntity())); } public void add(EntityRemove change) { CompoundTag tag = change.state.getNbtData(); - MainUtil.setEntityInfo(tag, change.getEntity()); - addEntityRemove(tag); + addEntityRemove(MainUtil.setEntityInfo(tag, change.getEntity())); } @Override @@ -299,14 +296,12 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { if (from.hasNbtData()) { CompoundTag nbt = from.getNbtData(); assert nbt != null; - MainUtil.setPosition(nbt, x, y, z); - addTileRemove(nbt); + addTileRemove(MainUtil.setPosition(nbt, x, y, z)); } if (to.hasNbtData()) { CompoundTag nbt = to.getNbtData(); assert nbt != null; - MainUtil.setPosition(nbt, x, y, z); - addTileCreate(nbt); + addTileCreate(MainUtil.setPosition(nbt, x, y, z)); } int combinedFrom = from.getOrdinal(); int combinedTo = to.getOrdinal(); @@ -322,8 +317,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { if (to.hasNbtData()) { CompoundTag nbt = to.getNbtData(); assert nbt != null; - MainUtil.setPosition(nbt, x, y, z); - addTileCreate(nbt); + addTileCreate(MainUtil.setPosition(nbt, x, y, z)); } int combinedTo = to.getInternalId(); add(x, y, z, combinedFrom, combinedTo); @@ -357,7 +351,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { wrappedTask.run(); return Futures.immediateCancelledFuture(); } else { - return Fawe.get().getQueueHandler().async(wrappedTask); + return Fawe.get().getQueueHandler().submit(wrappedTask); } } } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java index 944fb5446..d1dfc1280 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/CPUOptimizedClipboard.java @@ -152,10 +152,8 @@ public class CPUOptimizedClipboard extends LinearClipboard { @Override public Collection getTileEntities() { convertTilesToIndex(); - for (Map.Entry entry : nbtMapIndex.entrySet()) { - int index = entry.getKey(); - CompoundTag tag = entry.getValue(); - Map values = tag.getValue(); + nbtMapIndex.replaceAll((index, tag) -> { + Map values = new HashMap<>(tag.getValue()); if (!values.containsKey("x")) { int y = index / getArea(); index -= y * getArea(); @@ -164,23 +162,26 @@ public class CPUOptimizedClipboard extends LinearClipboard { values.put("x", new IntTag(x)); values.put("y", new IntTag(y)); values.put("z", new IntTag(z)); + return new CompoundTag(values); + } else { + return tag; } - } + }); return nbtMapIndex.values(); } @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - nbtMapLoc.put(new IntTriple(x, y, z), tag); + nbtMapLoc.put(new IntTriple(x, y, z), new CompoundTag(tag.getValue())); return true; } public boolean setTile(int index, CompoundTag tag) { - nbtMapIndex.put(index, tag); - Map values = tag.getValue(); + final Map values = new HashMap<>(tag.getValue()); values.remove("x"); values.remove("y"); values.remove("z"); + nbtMapIndex.put(index, new CompoundTag(values)); return true; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java index c7100a531..9b0dd5324 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; import java.io.Closeable; import java.io.DataInputStream; import java.io.File; @@ -44,7 +45,6 @@ import java.util.List; import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; -import javax.annotation.Nullable; /** * A clipboard with disk backed storage. (lower memory + loads on crash) @@ -390,11 +390,11 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - nbtMap.put(new IntTriple(x, y, z), tag); - Map values = tag.getValue(); + final Map values = new HashMap<>(tag.getValue()); values.put("x", new IntTag(x)); values.put("y", new IntTag(y)); values.put("z", new IntTag(z)); + nbtMap.put(new IntTriple(x, y, z), new CompoundTag(values)); return true; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/LinearClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/LinearClipboard.java index 962a73695..0be9cffcc 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/LinearClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/LinearClipboard.java @@ -21,10 +21,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.UUID; -/** - * Best used when clipboard selections are small, or using legacy formats - * (Small being < Integer.MAX_VALUE/BLOCK_SIZE_BYTES blocks) - */ public abstract class LinearClipboard extends SimpleClipboard { protected final HashSet entities = new HashSet<>(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java index 766057964..65ec74564 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java @@ -257,11 +257,11 @@ public class MemoryOptimizedClipboard extends LinearClipboard { @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - nbtMap.put(new IntTriple(x, y, z), tag); - Map values = tag.getValue(); + final Map values = new HashMap<>(tag.getValue()); values.put("x", new IntTag(x)); values.put("y", new IntTag(y)); values.put("z", new IntTag(z)); + nbtMap.put(new IntTriple(x, y, z), new CompoundTag(values)); return true; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/SimpleClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/SimpleClipboard.java index 06b250567..8317860b9 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/SimpleClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/SimpleClipboard.java @@ -14,7 +14,7 @@ public abstract class SimpleClipboard implements Clipboard { SimpleClipboard(BlockVector3 dimensions) { this.size = dimensions; long longVolume = (long) getWidth() * (long) getHeight() * (long) getLength(); - if (longVolume >= Integer.MAX_VALUE >> 2) { + if (longVolume >= Integer.MAX_VALUE) { throw new IllegalArgumentException("Dimensions are too large for this clipboard format."); } this.area = getWidth() * getLength(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AirMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AirMask.java index 950f1d9df..69f1bf9c2 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AirMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/AirMask.java @@ -16,4 +16,9 @@ public class AirMask extends BlockMask { return new AirMask(getExtent()); } + @Override + public boolean replacesAir() { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java index 0329f0b5c..105af3965 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdDataMask.java @@ -37,4 +37,9 @@ public class IdDataMask extends AbstractExtentMask implements ResettableMask { return new IdDataMask(getExtent()); } + @Override + public boolean replacesAir() { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java index 6528d5407..ebb2f5d9b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/mask/IdMask.java @@ -38,4 +38,9 @@ public class IdMask extends AbstractExtentMask implements ResettableMask { return new IdMask(getExtent()); } + @Override + public boolean replacesAir() { + return true; + } + } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java b/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java deleted file mode 100644 index f1b1a739f..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java +++ /dev/null @@ -1,298 +0,0 @@ -package com.boydti.fawe.util; - -import com.boydti.fawe.Fawe; -import com.google.common.base.Charsets; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.sk89q.worldedit.util.paste.Paster; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; - -/** - * Single class paster for the Incendo paste service - * - * @author Sauilitired - */ -@SuppressWarnings({"unused", "WeakerAccess"}) -public final class IncendoPaster implements Paster { - - /** - * Upload service URL - */ - public static final String UPLOAD_PATH = "https://athion.net/ISPaster/paste/upload"; - /** - * Valid paste applications - */ - public static final Collection - VALID_APPLICATIONS = Arrays - .asList("plotsquared", "fastasyncworldedit", "incendopermissions", "kvantum"); - - private final Collection files = new ArrayList<>(); - private final String pasteApplication; - - /** - * Construct a new paster - * - * @param pasteApplication The application that is sending the paste - */ - public IncendoPaster(final String pasteApplication) { - if (pasteApplication == null || pasteApplication.isEmpty()) { - throw new IllegalArgumentException("paste application cannot be null, nor empty"); - } - if (!VALID_APPLICATIONS.contains(pasteApplication.toLowerCase(Locale.ROOT))) { - throw new IllegalArgumentException( - String.format("Unknown application name: %s", pasteApplication)); - } - this.pasteApplication = pasteApplication; - } - - @Override - public Callable paste(String content) { - return new PasteTask(content); - } - - private final class PasteTask implements Callable { - - private PasteTask(String content) {} - - @Override - public URL call() throws Exception { - return new URL(debugPaste()); - } - - } - - /** - * Get an immutable collection containing all the files that have been added to this paster - * - * @return Unmodifiable collection - */ - public final Collection getFiles() { - return Collections.unmodifiableCollection(this.files); - } - - /** - * Add a file to the paster - * - * @param file File to paste - */ - public void addFile(final PasteFile file) { - if (file == null) { - throw new IllegalArgumentException("File cannot be null"); - } - // Check to see that no duplicate files are submitted - for (final PasteFile pasteFile : this.files) { - if (pasteFile.fileName.equalsIgnoreCase(file.getFileName())) { - throw new IllegalArgumentException(String.format("Found duplicate file with name %s", - file.getFileName())); - } - } - this.files.add(file); - } - - /** - * Create a JSON string from the submitted information - * - * @return compiled JSON string - */ - private String toJsonString() { - final StringBuilder builder = new StringBuilder("{\n"); - builder.append("\"paste_application\": \"").append(this.pasteApplication).append("\",\n\"files\": \""); - Iterator fileIterator = this.files.iterator(); - while (fileIterator.hasNext()) { - final PasteFile file = fileIterator.next(); - builder.append(file.getFileName()); - if (fileIterator.hasNext()) { - builder.append(","); - } - } - builder.append("\",\n"); - fileIterator = this.files.iterator(); - while (fileIterator.hasNext()) { - final PasteFile file = fileIterator.next(); - builder.append("\"file-").append(file.getFileName()).append("\": \"") - .append(file.getContent().replaceAll("\"", "\\\\\"")).append("\""); - if (fileIterator.hasNext()) { - builder.append(",\n"); - } - } - builder.append("\n}"); - return builder.toString(); - } - - /** - * Upload the paste and return the status message - * - * @return Status message - * @throws Throwable any and all exceptions - */ - public final String upload() throws Throwable { - final URL url = new URL(UPLOAD_PATH); - final URLConnection connection = url.openConnection(); - final HttpURLConnection httpURLConnection = (HttpURLConnection) connection; - httpURLConnection.setRequestMethod("POST"); - httpURLConnection.setDoOutput(true); - final byte[] content = toJsonString().getBytes(Charsets.UTF_8); - httpURLConnection.setFixedLengthStreamingMode(content.length); - httpURLConnection.setRequestProperty("Content-Type", "application/json"); - httpURLConnection.setRequestProperty("Accept", "*/*"); - httpURLConnection.connect(); - try (final OutputStream stream = httpURLConnection.getOutputStream()) { - stream.write(content); - } - if (!httpURLConnection.getResponseMessage().contains("OK")) { - throw new IllegalStateException(String.format("Server returned status: %d %s", - httpURLConnection.getResponseCode(), httpURLConnection.getResponseMessage())); - } - final StringBuilder input = new StringBuilder(); - try (final BufferedReader inputStream = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()))) { - String line; - while ((line = inputStream.readLine()) != null) { - input.append(line).append("\n"); - } - } - return input.toString(); - } - - /** - * Simple class that represents a paste file - */ - public static class PasteFile { - - private final String fileName; - private final String content; - - /** - * Construct a new paste file - * - * @param fileName File name, cannot be empty, nor null - * @param content File content, cannot be empty, nor null - */ - public PasteFile(final String fileName, final String content) { - if (fileName == null || fileName.isEmpty()) { - throw new IllegalArgumentException("file name cannot be null, nor empty"); - } - if (content == null || content.isEmpty()) { - throw new IllegalArgumentException("content cannot be null, nor empty"); - } - this.fileName = fileName; - this.content = content; - } - - /** - * Get the file name - * - * @return File name - */ - public String getFileName() { - return this.fileName; - } - - /** - * Get the file content as a single string - * - * @return File content - */ - public String getContent() { - return this.content; - } - } - - public static String debugPaste() throws IOException { - final IncendoPaster incendoPaster = new IncendoPaster("fastasyncworldedit"); - - StringBuilder b = new StringBuilder(); - b.append( - "# Welcome to this paste\n# It is meant to provide us at IntellectualSites with better information about your " - + "problem\n"); - b.append("\n# Server Information\n"); - b.append(Fawe.imp().getDebugInfo()); - b.append("\n# YAY! Now, let's see what we can find in your JVM\n"); - Runtime runtime = Runtime.getRuntime(); - RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean(); - b.append("Uptime: ").append(TimeUnit.MINUTES.convert(rb.getUptime(), TimeUnit.MILLISECONDS)) - .append(" minutes").append('\n'); - b.append("JVM Flags: ").append(rb.getInputArguments()).append('\n'); - b.append("Free Memory: ").append(runtime.freeMemory() / 1024 / 1024).append(" MB").append('\n'); - b.append("Max Memory: ").append(runtime.maxMemory() / 1024 / 1024).append(" MB").append('\n'); - b.append("Total Memory: ").append(runtime.totalMemory() / 1024 / 1024).append(" MB").append('\n'); - b.append("Available Processors: ").append(runtime.availableProcessors()).append('\n'); - b.append("Java Name: ").append(rb.getVmName()).append('\n'); - b.append("Java Version: '").append(System.getProperty("java.version")).append("'\n"); - b.append("Java Vendor: '").append(System.getProperty("java.vendor")).append("'\n"); - b.append("Operating System: '").append(System.getProperty("os.name")).append("'\n"); - b.append("OS Version: ").append(System.getProperty("os.version")).append('\n'); - b.append("OS Arch: ").append(System.getProperty("os.arch")).append('\n'); - b.append("# Okay :D Great. You are now ready to create your bug report!"); - b.append("\n# You can do so at https://github.com/IntellectualSites/FastAsyncWorldEdit/issues"); - b.append("\n# or via our Discord at https://discord.gg/KxkjDVg"); - incendoPaster.addFile(new IncendoPaster.PasteFile("information", b.toString())); - - try { - final File logFile = new File(Fawe.imp().getDirectory(), "../../logs/latest.log"); - final String file; - if (Files.size(logFile.toPath()) > 14_000_000) { - file = "too big :("; - } else { - file = readFile(logFile); - } - incendoPaster.addFile(new IncendoPaster.PasteFile("latest.log", file)); - } catch (IOException ignored) { - } - - incendoPaster.addFile(new PasteFile("config.yml", readFile(new File(Fawe.imp().getDirectory(), "config.yml")))); - incendoPaster.addFile(new PasteFile("config-legacy.yml", readFile(new File(Fawe.imp().getDirectory(), "config-legacy.yml")))); - - final String rawResponse; - try { - rawResponse = incendoPaster.upload(); - } catch (Throwable throwable) { - throw new IOException(String.format("Failed to upload files: %s", throwable.getMessage()), throwable); - } - final JsonObject jsonObject = new JsonParser().parse(rawResponse).getAsJsonObject(); - - if (jsonObject.has("created")) { - final String pasteId = jsonObject.get("paste_id").getAsString(); - return String.format("https://athion.net/ISPaster/paste/view/%s", pasteId); - } else { - throw new IOException(String.format("Failed to upload files: %s", - jsonObject.get("response").getAsString())); - } - } - - private static String readFile(final File file) throws IOException { - final StringBuilder content = new StringBuilder(); - final List lines = new ArrayList<>(); - try (final BufferedReader reader = new BufferedReader(new FileReader(file))) { - String line; - while ((line = reader.readLine()) != null) { - lines.add(line); - } - } - for (int i = Math.max(0, lines.size() - 1000); i < lines.size(); i++) { - content.append(lines.get(i)).append("\n"); - } - return content.toString(); - } - -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/MainUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/MainUtil.java index 5993104a8..ec054018c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/MainUtil.java @@ -34,6 +34,9 @@ import net.jpountz.lz4.LZ4InputStream; import net.jpountz.lz4.LZ4Utils; import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.imageio.ImageIO; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; @@ -66,6 +69,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -83,8 +87,6 @@ import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import javax.annotation.Nullable; -import javax.imageio.ImageIO; import static java.lang.System.arraycopy; import static org.slf4j.LoggerFactory.getLogger; @@ -448,24 +450,44 @@ public class MainUtil { } } - public static void setPosition(CompoundTag tag, int x, int y, int z) { - Map value = tag.getValue(); + /** + * Create a copy of the tag and modify the (x, y, z) coordinates + * + * @param tag Tag to copy + * @param x New X coordinate + * @param y New Y coordinate + * @param z New Z coordinate + * @return New tag + */ + public static @NotNull CompoundTag setPosition(@Nonnull CompoundTag tag, int x, int y, int z) { + Map value = new HashMap<>(tag.getValue()); value.put("x", new IntTag(x)); value.put("y", new IntTag(y)); value.put("z", new IntTag(z)); + return new CompoundTag(value); } - public static void setEntityInfo(CompoundTag tag, Entity entity) { - Map map = tag.getValue(); + /** + * Create a copy of the tag and modify the entity inf + * + * @param tag Tag to copy + * @param entity Entity + * @return New tag + */ + public static @NotNull CompoundTag setEntityInfo(@NotNull CompoundTag tag, @NotNull Entity entity) { + Map map = new HashMap<>(tag.getValue()); map.put("Id", new StringTag(entity.getState().getType().getId())); ListTag pos = (ListTag) map.get("Pos"); if (pos != null) { Location loc = entity.getLocation(); - List posList = ReflectionUtils.getList(pos.getValue()); + // Create a copy, because the list is immutable... + List posList = new ArrayList<>(pos.getValue()); posList.set(0, new DoubleTag(loc.getX())); posList.set(1, new DoubleTag(loc.getY())); posList.set(2, new DoubleTag(loc.getZ())); + map.put("Pos", new ListTag(pos.getType(), posList)); } + return new CompoundTag(map); } public static String getText(String url) throws IOException { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/RandomTextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/RandomTextureUtil.java index bb2b23076..e47621944 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/RandomTextureUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/RandomTextureUtil.java @@ -1,5 +1,6 @@ package com.boydti.fawe.util; +import com.plotsquared.core.util.PseudoRandom; import com.sk89q.worldedit.world.block.BlockType; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -34,6 +35,8 @@ public class RandomTextureUtil extends CachedTextureUtil { if (i < 0) { int i1 = -i; return -ThreadLocalRandom.current().nextInt(i1); + } else if( i == 0) { + return 0; } else { return ThreadLocalRandom.current().nextInt(i); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java index 869d5dce8..a7c8a3dc7 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils.java @@ -67,22 +67,6 @@ public class ReflectionUtils { blankField(enumClass, "enumConstants"); // IBM JDK } - public static List getList(List list) { - try { - Class> clazz = (Class>) Class - .forName("java.util.Collections$UnmodifiableList"); - if (!clazz.isInstance(list)) { - return list; - } - Field m = clazz.getDeclaredField("list"); - m.setAccessible(true); - return (List) m.get(list); - } catch (Throwable e) { - e.printStackTrace(); - return list; - } - } - public static Object getHandle(Object wrapper) { final Method getHandle = makeMethod(wrapper.getClass(), "getHandle"); return callMethod(getHandle, wrapper); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java index 6c112c83f..ab52685f5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/TextureUtil.java @@ -629,7 +629,6 @@ public class TextureUtil implements TextureHolder { mods.add(modId); } } - continue; } String modelsDir = "assets/%1$s/models/block/%2$s.json"; String texturesDir = "assets/%1$s/textures/%2$s.png"; @@ -638,14 +637,14 @@ public class TextureUtil implements TextureHolder { }.getType(); for (BlockType blockType : BlockTypesCache.values) { - if (!blockType.getMaterial().isFullCube()) { + if (!blockType.getMaterial().isFullCube() || blockType.getId().toLowerCase().contains("shulker")) { continue; } int combined = blockType.getInternalId(); String id = blockType.getId(); String[] split = id.split(":", 2); String name = split.length == 1 ? id : split[1]; - String nameSpace = split.length == 1 ? "minecraft" : split[0]; + String nameSpace = split.length == 1 ? "" : split[0]; Map texturesMap = new ConcurrentHashMap<>(); // Read models @@ -684,8 +683,11 @@ public class TextureUtil implements TextureHolder { continue; } + String[] texSplit = models.iterator().next().split(":"); + String texture = texSplit[texSplit.length - 1]; + textureFileName = - String.format(texturesDir, nameSpace, models.iterator().next()); + String.format(texturesDir, nameSpace, texture); } BufferedImage image = readImage(zipFile, textureFileName); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java index 41c495426..8311b7c55 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java @@ -26,11 +26,6 @@ import java.util.Locale; */ public final class ByteArrayTag extends Tag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_BYTE_ARRAY; - } - private final byte[] value; /** @@ -61,4 +56,11 @@ public final class ByteArrayTag extends Tag { return "TAG_Byte_Array(" + hex + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_BYTE_ARRAY; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java index 4dcffa700..53a3adcd3 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java @@ -19,14 +19,12 @@ package com.sk89q.jnbt; +import com.sk89q.jnbt.fawe.NumberTag; + /** * The {@code TAG_Byte} tag. */ public final class ByteTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_BYTE; - } private final byte value; @@ -50,4 +48,11 @@ public final class ByteTag extends NumberTag { return "TAG_Byte(" + value + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_BYTE; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java index 82754e61a..01ab56e75 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -19,6 +19,7 @@ package com.sk89q.jnbt; +import com.sk89q.jnbt.fawe.NumberTag; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Location; @@ -34,12 +35,7 @@ import java.util.UUID; */ public class CompoundTag extends Tag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_COMPOUND; - } - - private Map value; + private final Map value; /** * Creates the tag with an empty name. @@ -48,7 +44,7 @@ public class CompoundTag extends Tag { */ public CompoundTag(Map value) { super(); - this.value = value; + this.value = Collections.unmodifiableMap(value); } /** @@ -58,7 +54,7 @@ public class CompoundTag extends Tag { * @return true if the tag contains the given key */ public boolean containsKey(String key) { - return getValue().containsKey(key); + return value.containsKey(key); } @Override @@ -66,17 +62,6 @@ public class CompoundTag extends Tag { return value; } - /** - * Return a new compound tag with the given values. - * - * @param value the value - * @return the new compound tag - */ - public CompoundTag setValue(Map value) { - this.value = value; - return this; - } - /** * Create a compound tag builder. * @@ -96,7 +81,7 @@ public class CompoundTag extends Tag { * @return a byte array */ public byte[] getByteArray(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof ByteArrayTag) { return ((ByteArrayTag) tag).getValue(); } else { @@ -114,7 +99,7 @@ public class CompoundTag extends Tag { * @return a byte */ public byte getByte(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof ByteTag) { return ((ByteTag) tag).getValue(); } else { @@ -132,7 +117,7 @@ public class CompoundTag extends Tag { * @return a double */ public double getDouble(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof DoubleTag) { return ((DoubleTag) tag).getValue(); } else { @@ -151,9 +136,25 @@ public class CompoundTag extends Tag { * @return a double */ public double asDouble(String key) { - Tag tag = getValue().get(key); - if (tag instanceof NumberTag) { - return ((NumberTag) tag).getValue().doubleValue(); + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue(); + } else { return 0; } @@ -169,7 +170,7 @@ public class CompoundTag extends Tag { * @return a float */ public float getFloat(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof FloatTag) { return ((FloatTag) tag).getValue(); } else { @@ -187,7 +188,7 @@ public class CompoundTag extends Tag { * @return an int array */ public int[] getIntArray(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof IntArrayTag) { return ((IntArrayTag) tag).getValue(); } else { @@ -205,7 +206,7 @@ public class CompoundTag extends Tag { * @return an int */ public int getInt(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof IntTag) { return ((IntTag) tag).getValue(); } else { @@ -224,9 +225,25 @@ public class CompoundTag extends Tag { * @return an int */ public int asInt(String key) { - Tag tag = getValue().get(key); - if (tag instanceof NumberTag) { - return ((NumberTag) tag).getValue().intValue(); + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue().intValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().intValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().intValue(); + } else { return 0; } @@ -242,7 +259,7 @@ public class CompoundTag extends Tag { * @return a list of tags */ public List getList(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof ListTag) { return ((ListTag) tag).getValue(); } else { @@ -260,7 +277,7 @@ public class CompoundTag extends Tag { * @return a tag list instance */ public ListTag getListTag(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof ListTag) { return (ListTag) tag; } else { @@ -273,7 +290,7 @@ public class CompoundTag extends Tag { * *

If the key does not exist or its value is not a list tag, * then an empty list will be returned. If the given key references - * a list but the list of a different type, then an empty + * a list but the list of of a different type, then an empty * list will also be returned.

* * @param key the key @@ -283,7 +300,7 @@ public class CompoundTag extends Tag { */ @SuppressWarnings("unchecked") public List getList(String key, Class listType) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof ListTag) { ListTag listTag = (ListTag) tag; if (listTag.getType().equals(listType)) { @@ -299,14 +316,14 @@ public class CompoundTag extends Tag { /** * Get a {@code long[]} named with the given key. * - *

If the key does not exist or its value is not a long array tag, + *

If the key does not exist or its value is not an long array tag, * then an empty array will be returned.

* * @param key the key * @return an int array */ public long[] getLongArray(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof LongArrayTag) { return ((LongArrayTag) tag).getValue(); } else { @@ -324,7 +341,7 @@ public class CompoundTag extends Tag { * @return a long */ public long getLong(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof LongTag) { return ((LongTag) tag).getValue(); } else { @@ -343,9 +360,25 @@ public class CompoundTag extends Tag { * @return a long */ public long asLong(String key) { - Tag tag = getValue().get(key); - if (tag instanceof NumberTag) { - return ((NumberTag) tag).getValue().longValue(); + Tag tag = value.get(key); + if (tag instanceof ByteTag) { + return ((ByteTag) tag).getValue(); + + } else if (tag instanceof ShortTag) { + return ((ShortTag) tag).getValue(); + + } else if (tag instanceof IntTag) { + return ((IntTag) tag).getValue(); + + } else if (tag instanceof LongTag) { + return ((LongTag) tag).getValue(); + + } else if (tag instanceof FloatTag) { + return ((FloatTag) tag).getValue().longValue(); + + } else if (tag instanceof DoubleTag) { + return ((DoubleTag) tag).getValue().longValue(); + } else { return 0L; } @@ -361,7 +394,7 @@ public class CompoundTag extends Tag { * @return a short */ public short getShort(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof ShortTag) { return ((ShortTag) tag).getValue(); } else { @@ -379,7 +412,7 @@ public class CompoundTag extends Tag { * @return a string */ public String getString(String key) { - Tag tag = getValue().get(key); + Tag tag = value.get(key); if (tag instanceof StringTag) { return ((StringTag) tag).getValue(); } else { @@ -388,17 +421,17 @@ public class CompoundTag extends Tag { } @Override - public Map toRaw() { - HashMap raw = new HashMap<>(); - if (this.getValue().isEmpty()) { - return raw; + public String toString() { + StringBuilder bldr = new StringBuilder(); + bldr.append("TAG_Compound").append(": ").append(value.size()).append(" entries\r\n{\r\n"); + for (Map.Entry entry : value.entrySet()) { + bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); } - for (Map.Entry entry : getValue().entrySet()) { - raw.put(entry.getKey(), entry.getValue().toRaw()); - } - return raw; + bldr.append("}"); + return bldr.toString(); } + // FAWE Start public UUID getUUID() { long most = getLong("UUIDMost"); long least = getLong("UUIDLeast"); @@ -421,15 +454,21 @@ public class CompoundTag extends Tag { } @Override - public String toString() { - Map value = getValue(); - StringBuilder bldr = new StringBuilder(); - bldr.append("TAG_Compound").append(": ").append(getValue().size()).append(" entries\r\n{\r\n"); - for (Map.Entry entry : getValue().entrySet()) { - bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); - } - bldr.append("}"); - return bldr.toString(); + public int getTypeCode() { + return NBTConstants.TYPE_COMPOUND; } + @Override + public Map toRaw() { + HashMap raw = new HashMap<>(); + if (this.getValue().isEmpty()) { + return raw; + } + for (Map.Entry entry : getValue().entrySet()) { + raw.put(entry.getKey(), entry.getValue().toRaw()); + } + return raw; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java index 9dcfe6db2..211405791 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java @@ -19,14 +19,12 @@ package com.sk89q.jnbt; +import com.sk89q.jnbt.fawe.NumberTag; + /** * The {@code TAG_Double} tag. */ public final class DoubleTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_DOUBLE; - } private final double value; @@ -50,4 +48,11 @@ public final class DoubleTag extends NumberTag { return "TAG_Double(" + value + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_DOUBLE; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java index a845d636d..557f9173b 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java @@ -24,11 +24,6 @@ package com.sk89q.jnbt; */ public final class EndTag extends Tag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_END; - } - @Override public Object getValue() { return null; @@ -39,4 +34,11 @@ public final class EndTag extends Tag { return "TAG_End"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_END; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java index 78b5a87e8..6e107b154 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java @@ -19,14 +19,12 @@ package com.sk89q.jnbt; +import com.sk89q.jnbt.fawe.NumberTag; + /** * The {@code TAG_Float} tag. */ public final class FloatTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_FLOAT; - } private final float value; @@ -50,4 +48,11 @@ public final class FloatTag extends NumberTag { return "TAG_Float(" + value + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_FLOAT; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java index 22119aa9f..4fdb56be4 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java @@ -28,11 +28,6 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public final class IntArrayTag extends Tag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_INT_ARRAY; - } - private final int[] value; /** @@ -64,4 +59,11 @@ public final class IntArrayTag extends Tag { return "TAG_Int_Array(" + hex + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_INT_ARRAY; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java index dbcfd8f3c..8107a87b2 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java @@ -19,14 +19,12 @@ package com.sk89q.jnbt; +import com.sk89q.jnbt.fawe.NumberTag; + /** * The {@code TAG_Int} tag. */ public final class IntTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_INT; - } private final int value; @@ -50,4 +48,11 @@ public final class IntTag extends NumberTag { return "TAG_Int(" + value + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_INT; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java index 175375a24..afcde02bc 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java @@ -19,10 +19,9 @@ package com.sk89q.jnbt; -import java.util.ArrayList; +import javax.annotation.Nullable; import java.util.Collections; import java.util.List; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; @@ -31,11 +30,6 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public final class ListTag extends Tag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_LIST; - } - private final Class type; private final List value; @@ -421,18 +415,6 @@ public final class ListTag extends Tag { } } - @Override - public ArrayList toRaw() { - ArrayList raw = new ArrayList<>(); - if (this.value.isEmpty()) { - return raw; - } - for (Tag elem : this.value) { - raw.add(elem.toRaw()); - } - return raw; - } - @Override public String toString() { StringBuilder bldr = new StringBuilder(); @@ -444,4 +426,11 @@ public final class ListTag extends Tag { return bldr.toString(); } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_LIST; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java index 138029ce3..34c31d26b 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java @@ -28,11 +28,6 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class LongArrayTag extends Tag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_LONG_ARRAY; - } - private final long[] value; /** @@ -64,4 +59,11 @@ public class LongArrayTag extends Tag { return "TAG_Long_Array(" + hex + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_LONG_ARRAY; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java index cf5a7aee6..7b9c87858 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java @@ -19,14 +19,12 @@ package com.sk89q.jnbt; +import com.sk89q.jnbt.fawe.NumberTag; + /** * The {@code TAG_Long} tag. */ public final class LongTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_LONG; - } private final long value; @@ -50,4 +48,11 @@ public final class LongTag extends NumberTag { return "TAG_Long(" + value + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_LONG; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java index 1703fad79..db6689cb5 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java @@ -20,14 +20,13 @@ package com.sk89q.jnbt; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; /** * A class which holds constant values. */ public final class NBTConstants { - public static final Charset CHARSET = StandardCharsets.UTF_8; + public static final Charset CHARSET = Charset.forName("UTF-8"); public static final int TYPE_END = 0; public static final int TYPE_BYTE = 1; diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java index c2282e9fc..50c98ddc1 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -32,6 +32,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +// THIS CLASS HAS BEEN HEAVILY MODIFIED BY FAWE + /** * This class reads NBT, or Named Binary Tag * streams, and produces an object graph of subclasses of the {@code Tag} @@ -61,6 +63,14 @@ public final class NBTInputStream implements Closeable { this.is = dis; } + public void mark(int mark) { + is.mark(mark); + } + + public void reset() throws IOException { + is.reset(); + } + /** * Reads an NBT tag from the stream. * @@ -99,7 +109,7 @@ public final class NBTInputStream implements Closeable { if (child != null) { child.acceptRoot(this, type, 0); } else { - readTagPaylodLazy(type, 0); + readTagPayloadLazy(type, 0); } } catch (Throwable e) { e.printStackTrace(); @@ -119,7 +129,7 @@ public final class NBTInputStream implements Closeable { private byte[] buf; - public void readTagPaylodLazy(int type, int depth) throws IOException { + public void readTagPayloadLazy(int type, int depth) throws IOException { switch (type) { case NBTConstants.TYPE_END: return; @@ -152,7 +162,7 @@ public final class NBTInputStream implements Closeable { int childType = is.readByte(); length = is.readInt(); for (int i = 0; i < length; ++i) { - readTagPaylodLazy(childType, depth + 1); + readTagPayloadLazy(childType, depth + 1); } return; } @@ -165,7 +175,7 @@ public final class NBTInputStream implements Closeable { return; } is.skipBytes(is.readShort() & 0xFFFF); - readTagPaylodLazy(childType, depth + 1); + readTagPayloadLazy(childType, depth + 1); } } case NBTConstants.TYPE_INT_ARRAY: { @@ -181,7 +191,7 @@ public final class NBTInputStream implements Closeable { } } - public void readTagPaylodLazy(int type, int depth, StreamDelegate scope) throws IOException { + public void readTagPayloadLazy(int type, int depth, StreamDelegate scope) throws IOException { switch (type) { case NBTConstants.TYPE_END: return; @@ -293,11 +303,11 @@ public final class NBTInputStream implements Closeable { child = scope.get0(); if (child == null) { for (int i = 0; i < length; ++i) { - readTagPaylodLazy(childType, depth + 1); + readTagPayloadLazy(childType, depth + 1); } } else { for (int i = 0; i < length; ++i) { - readTagPaylodLazy(childType, depth + 1, child); + readTagPayloadLazy(childType, depth + 1, child); } } return; @@ -330,9 +340,9 @@ public final class NBTInputStream implements Closeable { } StreamDelegate child = scope.get(is); if (child == null) { - readTagPaylodLazy(childType, depth + 1); + readTagPayloadLazy(childType, depth + 1); } else { - readTagPaylodLazy(childType, depth + 1, child); + readTagPayloadLazy(childType, depth + 1, child); } } } @@ -461,7 +471,7 @@ public final class NBTInputStream implements Closeable { case NBTConstants.TYPE_END: if (depth == 0) { throw new IOException( - "TAG_End found without a TAG_Compound/TAG_List tag preceding it."); + "TAG_End found without a TAG_Compound/TAG_List tag preceding it."); } else { return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java index 4378e818b..9a4299841 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java @@ -32,6 +32,8 @@ import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; +// THIS CLASS HAS BEEN HEAVILY MODIFIED BY FAWE + /** * This class writes NBT, or Named Binary Tag * {@code Tag} objects to an underlying {@code OutputStream}. diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java index 82fbf940c..f2b6e008a 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -49,7 +49,7 @@ public final class NBTUtils { return "TAG_Byte_Array"; } else if (clazz.equals(ByteTag.class)) { return "TAG_Byte"; - } else if (CompoundTag.class.isAssignableFrom(clazz)) { + } else if (clazz.equals(CompoundTag.class)) { return "TAG_Compound"; } else if (clazz.equals(DoubleTag.class)) { return "TAG_Double"; diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NamedData.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NamedData.java deleted file mode 100644 index fbedac286..000000000 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NamedData.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.sk89q.jnbt; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Some data with a name - */ -public class NamedData { - private final String name; - private final T data; - - /** - * Create a new named tag. - * - * @param name the name - * @param data the data - */ - public NamedData(String name, T data) { - checkNotNull(name); - this.name = name; - this.data = data; - } - - /** - * Get the name of the tag. - * - * @return the name - */ - public String getName() { - return name; - } - - /** - * Get the tag. - * - * @return the tag - */ - public T getValue() { - return data; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java index 5f17df74f..87b69d480 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java @@ -19,14 +19,12 @@ package com.sk89q.jnbt; +import com.sk89q.jnbt.fawe.NumberTag; + /** * The {@code TAG_Short} tag. */ public final class ShortTag extends NumberTag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_SHORT; - } private final short value; @@ -50,4 +48,11 @@ public final class ShortTag extends NumberTag { return "TAG_Short(" + value + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_SHORT; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java index eb794ebf5..ae173441b 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java @@ -26,11 +26,6 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public final class StringTag extends Tag { - @Override - public int getTypeCode() { - return NBTConstants.TYPE_STRING; - } - private final String value; /** @@ -54,4 +49,11 @@ public final class StringTag extends Tag { return "TAG_String(" + value + ")"; } + // FAWE Start + @Override + public int getTypeCode() { + return NBTConstants.TYPE_STRING; + } + // FAWE End + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java index 7b105c950..3d415da86 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java @@ -31,10 +31,12 @@ public abstract class Tag { */ public abstract Object getValue(); + // FAWE Start public Object toRaw() { return getValue(); } public abstract int getTypeCode(); + // FAWE End } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompressedCompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/CompressedCompoundTag.java similarity index 99% rename from worldedit-core/src/main/java/com/sk89q/jnbt/CompressedCompoundTag.java rename to worldedit-core/src/main/java/com/sk89q/jnbt/fawe/CompressedCompoundTag.java index ca9241ccb..39eca054c 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompressedCompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/CompressedCompoundTag.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Map; public abstract class CompressedCompoundTag extends CompoundTag { + private T in; public CompressedCompoundTag(T in) { @@ -41,4 +42,5 @@ public abstract class CompressedCompoundTag extends CompoundTag { throw new RuntimeException(e); } } + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompressedSchematicTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/CompressedSchematicTag.java similarity index 90% rename from worldedit-core/src/main/java/com/sk89q/jnbt/CompressedSchematicTag.java rename to worldedit-core/src/main/java/com/sk89q/jnbt/fawe/CompressedSchematicTag.java index 189b2bb2b..6c9812a20 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompressedSchematicTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/CompressedSchematicTag.java @@ -1,7 +1,9 @@ -package com.sk89q.jnbt; +package com.sk89q.jnbt.fawe; import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.io.FastByteArraysInputStream; +import com.sk89q.jnbt.CompressedCompoundTag; +import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter; import net.jpountz.lz4.LZ4BlockInputStream; @@ -10,6 +12,7 @@ import net.jpountz.lz4.LZ4BlockOutputStream; import java.io.IOException; public class CompressedSchematicTag extends CompressedCompoundTag { + public CompressedSchematicTag(Clipboard holder) { super(holder); } @@ -26,4 +29,5 @@ public class CompressedSchematicTag extends CompressedCompoundTag { FastByteArraysInputStream in = new FastByteArraysInputStream(blocksOut.toByteArrays()); return new LZ4BlockInputStream(in); } + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NumberTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/NumberTag.java similarity index 52% rename from worldedit-core/src/main/java/com/sk89q/jnbt/NumberTag.java rename to worldedit-core/src/main/java/com/sk89q/jnbt/fawe/NumberTag.java index db7b78cb1..c90428e8d 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NumberTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/NumberTag.java @@ -1,6 +1,13 @@ -package com.sk89q.jnbt; +package com.sk89q.jnbt.fawe; +import com.sk89q.jnbt.Tag; + +/** + * A numerical {@link Tag} + */ public abstract class NumberTag extends Tag { + @Override public abstract Number getValue(); + } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/package-info.java b/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/package-info.java new file mode 100644 index 000000000..e86928e02 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/fawe/package-info.java @@ -0,0 +1,4 @@ +/** + * These are classes added by FAWE. They do not exist in WorldEdit + */ +package com.sk89q.jnbt.fawe; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index e6051f754..0bb02566f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -125,8 +125,6 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockCategories; -import com.sk89q.worldedit.world.block.BlockID; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; @@ -148,6 +146,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -2046,18 +2045,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { int yy; - double nextXn = invRadiusX; + double nextXn = 0; forX: for (int x = 0; x <= ceilRadiusX; ++x) { final double xn = nextXn; double dx = xn * xn; nextXn = (x + 1) * invRadiusX; - double nextZn = invRadiusZ; + double nextZn = 0; forZ: for (int z = 0; z <= ceilRadiusZ; ++z) { final double zn = nextZn; double dz = zn * zn; double dxz = dx + dz; nextZn = (z + 1) * invRadiusZ; - double nextYn = invRadiusY; + double nextYn = 0; forY: for (int y = 0; y <= ceilRadiusY; ++y) { final double yn = nextYn; @@ -2767,7 +2766,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { newVset = this.getHollowed(newVset); } } - return setBlocks(newVset, pattern); + return this.changes += setBlocks(newVset, pattern); } /** @@ -2840,7 +2839,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { if (!filled) { vset = getHollowed(vset); } - return setBlocks(vset, pattern); + return this.changes += setBlocks(vset, pattern); } /** @@ -2892,7 +2891,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { if (!filled) { newVset = this.getHollowed(newVset); } - return setBlocks(newVset, pattern); + return this.changes += setBlocks(newVset, pattern); } return changes; } @@ -3008,23 +3007,21 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BiomeType biomeType, - final String expressionString, final boolean hollow) - throws ExpressionException, MaxChangedBlocksException { + final String expressionString, final boolean hollow) throws ExpressionException { return makeBiomeShape(region, zero, unit, biomeType, expressionString, hollow, WorldEdit.getInstance().getConfiguration().calculationTimeout); } public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BiomeType biomeType, - final String expressionString, final boolean hollow, final int timeout) - throws ExpressionException, MaxChangedBlocksException { + final String expressionString, final boolean hollow, final int timeout) throws ExpressionException { - final Expression expression = Expression.compile(expressionString, "x", "z"); + final Expression expression = Expression.compile(expressionString, "x", "y", "z"); expression.optimize(); final EditSession editSession = this; final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(editSession, unit, zero); expression.setEnvironment(environment); - final int[] timedOut = {0}; + AtomicInteger timedOut = new AtomicInteger(); final ArbitraryBiomeShape shape = new ArbitraryBiomeShape(region) { @Override protected BiomeType getBiome(int x, int y, int z, BiomeType defaultBiomeType) { @@ -3041,7 +3038,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { // TODO: Allow biome setting via a script variable (needs BiomeType<->int mapping) return defaultBiomeType; } catch (ExpressionTimeoutException e) { - timedOut[0] = timedOut[0] + 1; + timedOut.getAndIncrement(); return null; } catch (Exception e) { log.warn("Failed to create shape", e); @@ -3050,10 +3047,10 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { } }; int changed = shape.generate(this, biomeType, hollow); - if (timedOut[0] > 0) { + if (timedOut.get() > 0) { throw new ExpressionTimeoutException( - String.format("%d blocks changed. %d blocks took too long to evaluate (increase time with //timeout)", - changed, timedOut[0])); + String.format("%d biomes changed. %d biomes took too long to evaluate (increase time with //timeout)", + changed, timedOut.get())); } return changed; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 916a93ae5..0e173d269 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -85,7 +85,6 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CreatureButcher; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extension.platform.binding.ProvideBindings; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.function.Contextual; @@ -130,6 +129,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.net.URL; import java.nio.file.FileSystems; import java.util.List; @@ -498,22 +498,23 @@ public class BrushCommands { set(context, brush).setSize(radius).setFill(fill); } - @Command( - name = "image", + @Command(name = "image", desc = "Use a height map to paint a surface", - descFooter = "Use a height map to paint any surface.\n" - ) - @CommandPermissions("worldedit.brush.stencil") - public void imageBrush(LocalSession session, InjectedValueAccess context, - @Arg(desc = "The size of the brush", def = "5") - Expression radius, ProvideBindings.ImageUri imageUri, - @Arg(def = "1", desc = "scale height") - double yscale, - @Switch(name = 'a', desc = "Use image Alpha") - boolean alpha, - @Switch(name = 'f', desc = "Blend the image with existing terrain") - boolean fadeOut) throws WorldEditException, IOException { - BufferedImage image = imageUri.load(); + descFooter = "Use a height map to paint any surface.\n") + @CommandPermissions("worldedit.brush.image") + public void imageBrush(LocalSession session, + InjectedValueAccess context, + @Arg(desc = "Image URL (imgur only)") String imageURL, + @Arg(desc = "The size of the brush", def = "5") Expression radius, + @Arg(def = "1", desc = "scale height") double yscale, + @Switch(name = 'a', desc = "Use image Alpha") boolean alpha, + @Switch(name = 'f', desc = "Blend the image with existing terrain") boolean fadeOut) + throws WorldEditException, IOException { + URL url = new URL(imageURL); + if (!url.getHost().equalsIgnoreCase("i.imgur.com")) { + throw new IOException("Only i.imgur.com links are allowed!"); + } + BufferedImage image = MainUtil.readImage(url); worldEdit.checkMaxBrushRadius(radius); if (yscale != 1) { ImageUtil.scaleAlpha(image, yscale); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index 1b324914d..468ded6b3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -277,7 +277,7 @@ public class ClipboardCommands { ) @Deprecated @CommandPermissions({"worldedit.clipboard.download"}) - public void download(final Player player, final LocalSession session, @Arg(name = "format", desc = "String", def = "schem") final String formatName) throws WorldEditException { + public void download(final Player player, final LocalSession session, @Arg(name = "format", desc = "String", def = "fast") final String formatName) throws WorldEditException { final ClipboardFormat format = ClipboardFormats.findByAlias(formatName); if (format == null) { player.print(Caption.of("fawe.worldedit.clipboard.clipboard.invalid.format", formatName)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index a7d65b216..4ceeef74e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -58,7 +58,7 @@ import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Switch; import org.jetbrains.annotations.Range; -import java.awt.RenderingHints; +import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; @@ -131,20 +131,26 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.image") @Logging(PLACEMENT) - public void image(Actor actor, LocalSession session, EditSession editSession, String argStr, @Arg(desc = "boolean", def = "true") boolean randomize, - @Arg(desc = "TODO", def = "100") int threshold, @Arg(desc = "BlockVector2", def = "") BlockVector2 dimensions) throws WorldEditException, IOException { + public void image(Actor actor, + LocalSession session, + EditSession editSession, + @Arg(desc = "Image URL (imgur only)") String imageURL, + @Arg(desc = "boolean", def = "true") boolean randomize, + @Arg(desc = "TODO", def = "100") int threshold, + @Arg(desc = "BlockVector2", def = "") BlockVector2 dimensions) throws WorldEditException, IOException { TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold); - URL url = new URL(argStr); + URL url = new URL(imageURL); if (!url.getHost().equalsIgnoreCase("i.imgur.com")) { throw new IOException("Only i.imgur.com links are allowed!"); } BufferedImage image = MainUtil.readImage(url); if (dimensions != null) { - image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(), RenderingHints.VALUE_INTERPOLATION_BILINEAR, false); + image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(), + RenderingHints.VALUE_INTERPOLATION_BILINEAR, false); } - BlockVector3 pos1 = session.getPlacementPosition(actor); - BlockVector3 pos2 = pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1); + BlockVector3 pos1 = session.getPlacementPosition(actor); + BlockVector3 pos2 = pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1); CuboidRegion region = new CuboidRegion(pos1, pos2); int[] count = new int[1]; final BufferedImage finalImage = image; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 037cae63c..cf3488921 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -147,7 +147,7 @@ public class SchematicCommands { @Deprecated @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.web", "worldedit.schematic.load.asset"}) public void loadall(Player player, LocalSession session, - @Arg(desc = "Format name.", def = "schematic") + @Arg(desc = "Format name.", def = "fast") String formatName, @Arg(desc = "File name.") String filename, @@ -223,7 +223,7 @@ public class SchematicCommands { public void load(Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, - @Arg(desc = "Format name.", def = "sponge") + @Arg(desc = "Format name.", def = "fast") String formatName) throws FilenameException { LocalConfiguration config = worldEdit.getConfiguration(); @@ -323,7 +323,7 @@ public class SchematicCommands { public void save(Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, - @Arg(desc = "Format name.", def = "sponge") + @Arg(desc = "Format name.", def = "fast") String formatName, @Switch(name = 'f', desc = "Overwrite an existing file.") boolean allowOverwrite, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java index 76afac4b8..b84c814a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.command; import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweVersion; import com.boydti.fawe.config.Settings; -import com.boydti.fawe.util.IncendoPaster; +import com.intellectualsites.paster.IncendoPaster; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -47,6 +47,7 @@ import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; +import java.io.File; import java.io.IOException; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -139,7 +140,10 @@ public class WorldEditCommands { public void report(Actor actor) throws WorldEditException { String dest; try { - dest = IncendoPaster.debugPaste(); + final File logFile = new File(Fawe.imp().getDirectory(), "../../logs/latest.log"); + final File config = new File(Fawe.imp().getDirectory(), "config.yml"); + final File legacyConfig = new File(Fawe.imp().getDirectory(), "config-legacy.yml"); + dest = IncendoPaster.debugPaste(logFile, Fawe.imp().getDebugInfo(), config, legacyConfig); } catch (IOException e) { actor.printInfo(TextComponent.of(e.getMessage())); return; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index d01db5dbb..7d563d4ee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -24,8 +24,11 @@ import com.boydti.fawe.object.io.ResettableFileInputStream; import com.boydti.fawe.object.schematic.MinecraftStructure; import com.boydti.fawe.object.schematic.PNGWriter; import com.google.common.collect.ImmutableSet; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.jnbt.NamedTag; +import com.sk89q.jnbt.Tag; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -35,6 +38,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -44,40 +48,7 @@ import java.util.zip.GZIPOutputStream; */ public enum BuiltInClipboardFormat implements ClipboardFormat { - /** - * The Schematic format used by MCEdit. - */ - MCEDIT_SCHEMATIC("mcedit", "mce", "schematic") { - - @Override - public String getPrimaryFileExtension() { - return "schematic"; - } - - @Override - public ClipboardReader getReader(InputStream inputStream) throws IOException { - if (inputStream instanceof FileInputStream) { - inputStream = new ResettableFileInputStream((FileInputStream) inputStream); - } - BufferedInputStream buffered = new BufferedInputStream(inputStream); - NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); - SchematicReader input = new SchematicReader(nbtStream); - input.setUnderlyingStream(inputStream); - return input; - } - - @Override - public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { - throw new IOException("This format does not support saving, use `schem` or `sponge` as format"); // Is more helpful - } - - @Override - public boolean isFormat(File file) { - String name = file.getName().toLowerCase(Locale.ROOT); - return name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce"); - } - }, - SPONGE_SCHEMATIC("sponge", "schem") { + FAST("fast", "fawe") { @Override public String getPrimaryFileExtension() { @@ -115,6 +86,129 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { }, + SPONGE_SCHEMATIC("sponge", "schem") { + + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); + return new SpongeSchematicReader(nbtStream); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(outputStream)); + return new SpongeSchematicWriter(nbtStream); + } + + @Override + public boolean isFormat(File file) { + try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) { + NamedTag rootTag = str.readNamedTag(); + if (!rootTag.getName().equals("Schematic")) { + return false; + } + CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + + // Check + Map schematic = schematicTag.getValue(); + if (!schematic.containsKey("Version")) { + return false; + } + } catch (Exception e) { + return false; + } + + return true; + } + }, + + /** + * The Schematic format used by MCEdit. + */ + MCEDIT_SCHEMATIC("mcedit", "mce", "schematic") { + + @Override + public String getPrimaryFileExtension() { + return "schematic"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); + return new MCEditSchematicReader(nbtStream); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + throw new IOException("This format does not support saving"); + } + + @Override + public boolean isFormat(File file) { + try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) { + NamedTag rootTag = str.readNamedTag(); + if (!rootTag.getName().equals("Schematic")) { + return false; + } + CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + + // Check + Map schematic = schematicTag.getValue(); + if (!schematic.containsKey("Materials")) { + return false; + } + } catch (Exception e) { + return false; + } + return true; + } + }, + + BROKENENTITY("brokenentity", "legacyentity", "le", "be", "brokenentities", "legacyentities") { + + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + if (inputStream instanceof FileInputStream) { + inputStream = new ResettableFileInputStream((FileInputStream) inputStream); + } + BufferedInputStream buffered = new BufferedInputStream(inputStream); + NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); + FastSchematicReader reader = new FastSchematicReader(nbtStream); + reader.setBrokenEntities(true); + return reader; + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + OutputStream gzip; + if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) { + gzip = outputStream; + } else { + outputStream = new BufferedOutputStream(outputStream); + gzip = new PGZIPOutputStream(outputStream); + } + NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); + FastSchematicWriter writer = new FastSchematicWriter(nbtStream); + writer.setBrokenEntities(true); + return writer; + } + + @Override + public boolean isFormat(File file) { + return false; + } + + }, + /** * The structure block format: * http://minecraft.gamepedia.com/Structure_block_file_format diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FastSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FastSchematicReader.java index c0c413689..9fdebeb06 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FastSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FastSchematicReader.java @@ -30,10 +30,12 @@ import com.boydti.fawe.object.io.FastByteArraysInputStream; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NamedTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -45,6 +47,7 @@ import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; @@ -55,9 +58,11 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.OptionalInt; import java.util.UUID; import java.util.function.Function; @@ -70,9 +75,10 @@ public class FastSchematicReader extends NBTSchematicReader { private static final Logger log = LoggerFactory.getLogger(FastSchematicReader.class); private final NBTInputStream inputStream; - private DataFixer fixer = null; + private DataFixer fixer; private int dataVersion = -1; private int version = -1; + private int faweWritten = -1; private FastByteArrayOutputStream blocksOut; private FaweOutputStream blocks; @@ -92,6 +98,8 @@ public class FastSchematicReader extends NBTSchematicReader { private char[] palette; private char[] biomePalette; private BlockVector3 min = BlockVector3.ZERO; + private boolean brokenEntities = false; + private boolean isWorldEdit = false; /** @@ -105,6 +113,10 @@ public class FastSchematicReader extends NBTSchematicReader { this.fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer(); } + public void setBrokenEntities(boolean brokenEntities) { + this.brokenEntities = brokenEntities; + } + private String fix(String palettePart) { if (fixer == null || dataVersion == -1) { return palettePart; @@ -133,7 +145,7 @@ public class FastSchematicReader extends NBTSchematicReader { return fixer.fixUp(DataFixer.FixTypes.BIOME, biomePalettePart, dataVersion); } - public StreamDelegate createDelegate() { + public StreamDelegate createVersionDelegate() { StreamDelegate root = new StreamDelegate(); StreamDelegate schematic = root.add("Schematic"); schematic.add("DataVersion").withInt((i, v) -> dataVersion = v); @@ -143,6 +155,12 @@ public class FastSchematicReader extends NBTSchematicReader { dataVersion = Constants.DATA_VERSION_MC_1_13_2; } }); + return root; + } + + public StreamDelegate createDelegate() { + StreamDelegate root = new StreamDelegate(); + StreamDelegate schematic = root.add("Schematic"); schematic.add("Width").withInt((i, v) -> width = v); schematic.add("Height").withInt((i, v) -> height = v); schematic.add("Length").withInt((i, v) -> length = v); @@ -152,17 +170,23 @@ public class FastSchematicReader extends NBTSchematicReader { metadata.add("WEOffsetX").withInt((i, v) -> offsetX = v); metadata.add("WEOffsetY").withInt((i, v) -> offsetY = v); metadata.add("WEOffsetZ").withInt((i, v) -> offsetZ = v); + metadata.add("FAWEVersion").withInt((i, v) -> faweWritten = v); + + StreamDelegate worldEditSection = metadata.add("WorldEdit"); + worldEditSection.withValue((ValueReader) (index, v) -> isWorldEdit = true); + StreamDelegate paletteDelegate = schematic.add("Palette"); paletteDelegate.withValue((ValueReader>) (ignore, v) -> { palette = new char[v.size()]; for (Entry entry : v.entrySet()) { - BlockState state = null; + BlockState state; + String palettePart = fix(entry.getKey()); try { - String palettePart = fix(entry.getKey()); state = BlockState.get(palettePart); - } catch (InputParseException e) { - e.printStackTrace(); + } catch (InputParseException ignored) { + log.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air."); + state = BlockTypes.AIR.getDefaultState(); } int index = (int) entry.getValue(); palette[index] = (char) state.getOrdinal(); @@ -224,10 +248,14 @@ public class FastSchematicReader extends NBTSchematicReader { @Override public Clipboard read(UUID uuid, Function createOutput) throws IOException { StreamDelegate root = createDelegate(); + StreamDelegate versions = createVersionDelegate(); + inputStream.mark(Integer.MAX_VALUE); + inputStream.readNamedTagLazy(versions); + inputStream.reset(); inputStream.readNamedTagLazy(root); if (version != 1 && version != 2) { - throw new IOException("This schematic version is currently not supported"); + throw new IOException("This schematic version is currently not supported (" + version + ")"); } if (blocks != null) { @@ -240,9 +268,11 @@ public class FastSchematicReader extends NBTSchematicReader { biomes = null; BlockVector3 dimensions = BlockVector3.at(width, height, length); - BlockVector3 origin = BlockVector3.ZERO; + BlockVector3 origin; if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) { origin = BlockVector3.at(-offsetX, -offsetY, -offsetZ); + } else { + origin = BlockVector3.ZERO; } Clipboard clipboard = createOutput.apply(dimensions); @@ -326,7 +356,7 @@ public class FastSchematicReader extends NBTSchematicReader { y = pos[1]; z = pos[2]; } - Map values = tile.getValue(); + Map values = new HashMap<>(tile.getValue()); Tag id = values.get("Id"); if (id != null) { values.put("x", new IntTag(x)); @@ -337,22 +367,19 @@ public class FastSchematicReader extends NBTSchematicReader { values.remove("Id"); values.remove("Pos"); - tile = fixBlockEntity(tile); - clipboard.setTile(x, y, z, tile); + clipboard.setTile(x, y, z, fixBlockEntity(new CompoundTag(values))); } } // entities if (entities != null && !entities.isEmpty()) { for (Map entRaw : entities) { - CompoundTag ent = FaweCache.IMP.asTag(entRaw); - - Map value = ent.getValue(); + Map value = new HashMap<>(FaweCache.IMP.asTag(entRaw).getValue()); StringTag id = (StringTag) value.get("Id"); if (id == null) { id = (StringTag) value.get("id"); if (id == null) { - return null; + continue; } } value.put("id", id); @@ -360,10 +387,29 @@ public class FastSchematicReader extends NBTSchematicReader { EntityType type = EntityTypes.parse(id.getValue()); if (type != null) { - ent = fixEntity(ent); + final CompoundTag ent = fixEntity(new CompoundTag(value)); BaseEntity state = new BaseEntity(type, ent); Location loc = ent.getEntityLocation(clipboard); - clipboard.createEntity(loc, state); + if (brokenEntities) { + clipboard.createEntity(loc, state); + continue; + } + if (!isWorldEdit && faweWritten == -1) { + int locX = loc.getBlockX(); + int locY = loc.getBlockY(); + int locZ = loc.getBlockZ(); + BlockVector3 max = min.add(dimensions).subtract(BlockVector3.ONE); + if (locX < min.getX() || locY < min.getY() || locZ < min.getZ() + || locX > max.getX() || locY > max.getY() || locZ > max.getZ()) { + for (Entity e : clipboard.getEntities()) { + clipboard.removeEntity(e); + } + log.error("Detected schematic entity outside clipboard region. FAWE will not load entities. " + + "Please try loading the schematic with the format \"legacyentity\""); + break; + } + } + clipboard.createEntity(loc.setPosition(loc.subtract(min.toVector3())), state); } else { log.debug("Invalid entity: " + id); } @@ -372,7 +418,7 @@ public class FastSchematicReader extends NBTSchematicReader { clipboard.setOrigin(origin); if (!min.equals(BlockVector3.ZERO)) { - new BlockArrayClipboard(clipboard, min); + clipboard = new BlockArrayClipboard(clipboard, min); } return clipboard; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FastSchematicWriter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FastSchematicWriter.java index 092bc94d0..c5e7fe56e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FastSchematicWriter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FastSchematicWriter.java @@ -19,10 +19,10 @@ package com.sk89q.worldedit.extent.clipboard.io; +import com.boydti.fawe.Fawe; import com.boydti.fawe.jnbt.streamer.IntValueReader; import com.boydti.fawe.object.FaweOutputStream; import com.boydti.fawe.util.IOUtil; -import com.google.common.collect.Maps; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntArrayTag; import com.sk89q.jnbt.ListTag; @@ -39,6 +39,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.visitor.Order; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -58,8 +59,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -72,6 +71,7 @@ public class FastSchematicWriter implements ClipboardWriter { private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; private final NBTOutputStream outputStream; + private boolean brokenEntities = false; /** * Create a new schematic writer. @@ -83,6 +83,10 @@ public class FastSchematicWriter implements ClipboardWriter { this.outputStream = outputStream; } + public void setBrokenEntities(boolean brokenEntities) { + this.brokenEntities = brokenEntities; + } + @Override public void write(Clipboard clipboard) throws IOException { // For now always write the latest version. Maybe provide support for earlier if more appear. @@ -123,15 +127,16 @@ public class FastSchematicWriter implements ClipboardWriter { // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin' out.writeNamedTag("Offset", new int[]{ - min.getBlockX(), - min.getBlockY(), - min.getBlockZ(), + min.getBlockX(), + min.getBlockY(), + min.getBlockZ(), }); out.writeLazyCompoundTag("Metadata", out1 -> { out1.writeNamedTag("WEOffsetX", offset.getBlockX()); out1.writeNamedTag("WEOffsetY", offset.getBlockY()); out1.writeNamedTag("WEOffsetZ", offset.getBlockZ()); + out1.writeNamedTag("FAWEVersion", Fawe.get().getVersion().build); }); ByteArrayOutputStream blocksCompressed = new ByteArrayOutputStream(); @@ -157,7 +162,7 @@ public class FastSchematicWriter implements ClipboardWriter { BaseBlock block = pos.getFullBlock(finalClipboard); CompoundTag nbt = block.getNbtData(); if (nbt != null) { - Map values = nbt.getValue(); + Map values = new HashMap<>(nbt.getValue()); // Positions are kept in NBT, we don't want that. values.remove("x"); @@ -170,12 +175,13 @@ public class FastSchematicWriter implements ClipboardWriter { // Dum. values.remove("id"); values.put("Pos", new IntArrayTag(new int[]{ - pos.getX(), - pos.getY(), - pos.getZ() + pos.getX(), + pos.getY(), + pos.getZ() })); numTiles++; - tilesOut.writeTagPayload(block.getNbtData()); + + tilesOut.writeTagPayload(new CompoundTag(values)); } int ordinal = block.getOrdinal(); @@ -240,8 +246,12 @@ public class FastSchematicWriter implements ClipboardWriter { // Store our location data, overwriting any values.remove("id"); + Location loc = entity.getLocation(); + if (!brokenEntities) { + loc = loc.setPosition(loc.add(min.toVector3())); + } values.put("Id", new StringTag(state.getType().getId())); - values.put("Pos", writeVector(entity.getLocation())); + values.put("Pos", writeVector(loc)); values.put("Rotation", writeRotation(entity.getLocation())); CompoundTag entityTag = new CompoundTag(values); @@ -311,30 +321,6 @@ public class FastSchematicWriter implements ClipboardWriter { } } - private void writeEntities(Clipboard clipboard, NBTOutputStream schematic) throws IOException { - List entities = clipboard.getEntities().stream().map(e -> { - BaseEntity state = e.getState(); - if (state == null) { - return null; - } - Map values = Maps.newHashMap(); - CompoundTag rawData = state.getNbtData(); - if (rawData != null) { - values.putAll(rawData.getValue()); - } - values.remove("id"); - values.put("Id", new StringTag(state.getType().getId())); - values.put("Pos", writeVector(e.getLocation().toVector())); - values.put("Rotation", writeRotation(e.getLocation())); - - return new CompoundTag(values); - }).filter(Objects::nonNull).collect(Collectors.toList()); - if (entities.isEmpty()) { - return; - } - schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities)); - } - @Override public void close() throws IOException { outputStream.close(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FaweFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FaweFormat.java deleted file mode 100644 index 0daf069f9..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/FaweFormat.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.sk89q.worldedit.extent.clipboard.io; - -public class FaweFormat { -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java index cc56d5bb7..619c30037 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java @@ -68,26 +68,24 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Reads schematic files that are compatible with MCEdit and other editors. - * @deprecated Use SchematicStreamer */ -@Deprecated public class MCEditSchematicReader extends NBTSchematicReader { private static final Logger log = LoggerFactory.getLogger(MCEditSchematicReader.class); private final NBTInputStream inputStream; private final DataFixer fixer; private static final ImmutableList COMPATIBILITY_HANDLERS - = ImmutableList.of( - new SignCompatibilityHandler(), - new FlowerPotCompatibilityHandler(), - new NoteBlockCompatibilityHandler(), - new SkullBlockCompatibilityHandler(), - new BannerBlockCompatibilityHandler(), - new BedBlockCompatibilityHandler() + = ImmutableList.of( + new SignCompatibilityHandler(), + new FlowerPotCompatibilityHandler(), + new NoteBlockCompatibilityHandler(), + new SkullBlockCompatibilityHandler(), + new BannerBlockCompatibilityHandler(), + new BedBlockCompatibilityHandler() ); private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS - = ImmutableList.of( - new Pre13HangingCompatibilityHandler() + = ImmutableList.of( + new Pre13HangingCompatibilityHandler() ); /** @@ -99,8 +97,8 @@ public class MCEditSchematicReader extends NBTSchematicReader { checkNotNull(inputStream); this.inputStream = inputStream; this.fixer = null; - //com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability( - //com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer(); + //com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability( + //com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer(); } @Override @@ -207,7 +205,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { if (newBlock != null) { for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { if (handler.isAffectedBlock(newBlock)) { - newBlock = handler.updateNBT(block, values); + newBlock = handler.updateNBT(block, values).toImmutableState(); if (newBlock == null || values.isEmpty()) { break; } @@ -256,7 +254,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { int combined = block << 8 | data; if (unknownBlocks.add(combined)) { log.warn("Unknown block when loading schematic: " - + block + ":" + data + ". This is most likely a bad schematic."); + + block + ":" + data + ". This is most likely a bad schematic."); } } } catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this @@ -302,7 +300,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { } private String convertEntityId(String id) { - switch(id) { + switch (id) { case "AreaEffectCloud": return "area_effect_cloud"; case "ArmorStand": return "armor_stand"; case "CaveSpider": return "cave_spider"; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java deleted file mode 100644 index 14f363009..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java +++ /dev/null @@ -1,536 +0,0 @@ -/* - * 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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.extent.clipboard.io; - -import com.boydti.fawe.FaweCache; -import com.boydti.fawe.jnbt.streamer.StreamDelegate; -import com.boydti.fawe.jnbt.streamer.ValueReader; -import com.boydti.fawe.object.FaweInputStream; -import com.boydti.fawe.object.FaweOutputStream; -import com.boydti.fawe.object.clipboard.LinearClipboard; -import com.boydti.fawe.object.io.FastByteArrayOutputStream; -import com.boydti.fawe.object.io.FastByteArraysInputStream; -import com.boydti.fawe.object.io.ResettableFileInputStream; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.BannerBlockCompatibilityHandler; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.BedBlockCompatibilityHandler; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.EntityNBTCompatibilityHandler; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.FlowerPotCompatibilityHandler; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NoteBlockCompatibilityHandler; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.Pre13HangingCompatibilityHandler; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SignCompatibilityHandler; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SkullBlockCompatibilityHandler; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.registry.state.PropertyKey; -import com.sk89q.worldedit.util.Direction; -import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockCategories; -import com.sk89q.worldedit.world.block.BlockID; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypeSwitch; -import com.sk89q.worldedit.world.block.BlockTypeSwitchBuilder; -import com.sk89q.worldedit.world.entity.EntityType; -import com.sk89q.worldedit.world.entity.EntityTypes; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import com.sk89q.worldedit.world.registry.LegacyMapper; -import net.jpountz.lz4.LZ4BlockInputStream; -import net.jpountz.lz4.LZ4BlockOutputStream; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedInputStream; -import java.io.EOFException; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Function; -import java.util.zip.GZIPInputStream; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.slf4j.LoggerFactory.getLogger; - -/** - * Reads schematic files based that are compatible with MCEdit and other editors. - */ -public class SchematicReader implements ClipboardReader { - - private static final Logger log = LoggerFactory.getLogger(SchematicReader.class); - - private static final NBTCompatibilityHandler[] COMPATIBILITY_HANDLERS = { - new SignCompatibilityHandler(), - new FlowerPotCompatibilityHandler(), - new NoteBlockCompatibilityHandler(), - new SkullBlockCompatibilityHandler(), - new BannerBlockCompatibilityHandler(), - new BedBlockCompatibilityHandler() - }; - private static final EntityNBTCompatibilityHandler[] ENTITY_COMPATIBILITY_HANDLERS = { - new Pre13HangingCompatibilityHandler() - }; - - private NBTInputStream inputStream; - private InputStream rootStream; - - // private final DataFixer fixer; TODO - - private FastByteArrayOutputStream idOut = new FastByteArrayOutputStream(); - private FastByteArrayOutputStream dataOut = new FastByteArrayOutputStream(); - private FastByteArrayOutputStream addOut; - private FastByteArrayOutputStream biomesOut; - - private FaweOutputStream ids; - private FaweOutputStream datas; - private FaweOutputStream adds; - private FaweOutputStream biomes; - - private List> tiles; - private List> entities; - - private int width; - private int height; - private int length; - private int offsetX; - private int offsetY; - private int offsetZ; - private int originX; - private int originY; - private int originZ; - - /** - * Create a new instance. - * - * @param inputStream the input stream to read from - */ - public SchematicReader(NBTInputStream inputStream) { - checkNotNull(inputStream); - this.inputStream = inputStream; - } - - public void setUnderlyingStream(InputStream in) { - this.rootStream = in; - } - - public StreamDelegate createDelegate() { - StreamDelegate root = new StreamDelegate(); - StreamDelegate schematic = root.add("Schematic"); - schematic.add("Width").withInt((i, v) -> width = v); - schematic.add("Height").withInt((i, v) -> height = v); - schematic.add("Length").withInt((i, v) -> length = v); - - schematic.add("WEOriginX").withInt((i, v) -> originX = v); - schematic.add("WEOriginY").withInt((i, v) -> originY = v); - schematic.add("WEOriginZ").withInt((i, v) -> originZ = v); - - StreamDelegate metadata = schematic.add("Metadata"); - metadata.add("WEOffsetX").withInt((i, v) -> offsetX = v); - metadata.add("WEOffsetY").withInt((i, v) -> offsetY = v); - metadata.add("WEOffsetZ").withInt((i, v) -> offsetZ = v); - - StreamDelegate blocksDelegate = schematic.add("Blocks"); - blocksDelegate.withInfo((length, type) -> ids = new FaweOutputStream(new LZ4BlockOutputStream(idOut))); - blocksDelegate.withInt((index, value) -> ids.write(value)); - - StreamDelegate dataDelegate = schematic.add("Data"); - dataDelegate.withInfo((length, type) -> datas = new FaweOutputStream(new LZ4BlockOutputStream(dataOut))); - dataDelegate.withInt((index, value) -> datas.write(value)); - - StreamDelegate addDelegate = schematic.add("AddBlocks"); - addDelegate.withInfo((length, type) -> { - addOut = new FastByteArrayOutputStream(); - adds = new FaweOutputStream(new LZ4BlockOutputStream(addOut)); - }); - addDelegate.withInt((index, value) -> { - if (value != 0) { - int first = value & 0x0F; - int second = (value & 0xF0) >> 4; - adds.write(first); - adds.write(second); - } else { - adds.write(0); - adds.write(0); - } - }); - - StreamDelegate tilesDelegate = schematic.add("TileEntities"); - tilesDelegate.withInfo((length, type) -> tiles = new ArrayList<>(length)); - tilesDelegate.withElem((ValueReader>) (index, tile) -> tiles.add(tile)); - - StreamDelegate entitiesDelegate = schematic.add("Entities"); - entitiesDelegate.withInfo((length, type) -> entities = new ArrayList<>(length)); - entitiesDelegate.withElem( - (ValueReader>) (index, entity) -> entities.add(entity)); - return root; - } - - private int readCombined(InputStream idIn, InputStream dataIn) throws IOException { - return ((idIn.read() & 0xFF) << 4) + (dataIn.read() & 0xF); - } - - private int readCombined(InputStream idIn, InputStream dataIn, InputStream addIn) throws IOException { - return ((addIn.read() & 0xFF) << 8) + readCombined(idIn, dataIn); - } - - private BlockState getBlock(int combined) { - BlockState state = LegacyMapper.getInstance().getBlockFromLegacyCombinedId(combined); - return state; - } - - private void write(int index, BlockState block, LinearClipboard clipboard) { - clipboard.setBlock(index, block); - } - - private void write(int x, int y, int z, BlockState block, Clipboard clipboard) { - clipboard.setBlock(x, y, z, block); - } - - private void readwrite(int index, InputStream idIn, InputStream dataIn, LinearClipboard out) throws IOException { - readwrite(index, readCombined(idIn, dataIn), out); - } - - private void readwrite(int x, int y, int z, InputStream idIn, InputStream dataIn, Clipboard out) throws IOException { - readwrite(x, y, z, readCombined(idIn, dataIn), out); - } - - private void readwrite(int index, InputStream idIn, InputStream dataIn, InputStream addIn, LinearClipboard out) throws IOException { - readwrite(index, readCombined(idIn, dataIn, addIn), out); - } - - private void readwrite(int x, int y, int z, InputStream idIn, InputStream dataIn, InputStream addIn, Clipboard out) throws IOException { - readwrite(x, y, z, readCombined(idIn, dataIn, addIn), out); - } - - private void readwrite(int index, int combined, LinearClipboard out) throws IOException { - write(index, getBlock(combined), out); - } - - private void readwrite(int x, int y, int z, int combined, Clipboard out) throws IOException { - write(x, y, z, getBlock(combined), out); - } - - @Override - public Clipboard read(UUID uuid, Function createOutput) throws IOException { - try { - return readInternal(uuid, createOutput); - } catch (EOFException e) { - log.error("EOFException read in schematic. Did you give the schematic the wrong extension?"); - log.error("We will attempt to rectify your mistake for you and load the schematic assuming it is named .schem not .schematic"); - e.printStackTrace(); - final InputStream stream; - if (rootStream instanceof FileInputStream) { - stream = new ResettableFileInputStream((FileInputStream) rootStream); - } else { - stream = rootStream; - } - BufferedInputStream buffered = new BufferedInputStream(stream); - NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); - return (new FastSchematicReader(nbtStream)).read(uuid, createOutput); - } - } - - private Clipboard readInternal(UUID uuid, Function createOutput) throws IOException { - StreamDelegate root = createDelegate(); - inputStream.readNamedTagLazy(root); - - if (ids != null) { - ids.close(); - } - if (datas != null) { - datas.close(); - } - if (adds != null) { - adds.close(); - } - if (biomes != null) { - biomes.close(); - } - ids = null; - datas = null; - adds = null; - biomes = null; - - BlockVector3 dimensions = BlockVector3.at(width, height, length); - BlockVector3 origin = BlockVector3.ZERO; - if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) { - origin = BlockVector3.at(-offsetX, -offsetY, -offsetZ); - } - - Clipboard clipboard = createOutput.apply(dimensions); - try (InputStream dataIn = new LZ4BlockInputStream(new FastByteArraysInputStream(dataOut.toByteArrays())); InputStream idIn = new LZ4BlockInputStream(new FastByteArraysInputStream(idOut.toByteArrays()))) { - if (addOut != null) { - try (FaweInputStream addIn = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(addOut.toByteArrays())))) { - if (clipboard instanceof LinearClipboard) { - LinearClipboard linear = (LinearClipboard) clipboard; - for (int y = 0, index = 0; y < height; y++) { - for (int z = 0; z < length; z++) { - for (int x = 0; x < width; x++, index++) { - readwrite(index, idIn, dataIn, addIn, linear); - } - } - } - } else { - for (int y = 0; y < height; y++) { - for (int z = 0; z < length; z++) { - for (int x = 0; x < width; x++) { - readwrite(x, y, z, idIn, dataIn, addIn, clipboard); - } - } - } - } - } - } else { - if (clipboard instanceof LinearClipboard) { - LinearClipboard linear = (LinearClipboard) clipboard; - for (int y = 0, index = 0; y < height; y++) { - for (int z = 0; z < length; z++) { - for (int x = 0; x < width; x++, index++) { - readwrite(index, idIn, dataIn, linear); - } - } - } - } else { - for (int y = 0; y < height; y++) { - for (int z = 0; z < length; z++) { - for (int x = 0; x < width; x++) { - readwrite(x, y, z, idIn, dataIn, clipboard); - } - } - } - } - } - } - - // tiles - if (tiles != null && !tiles.isEmpty()) { - outer: - for (Map tileRaw : tiles) { - CompoundTag tile = FaweCache.IMP.asTag(tileRaw); - int x = (int) tileRaw.get("x"); - int y = (int) tileRaw.get("y"); - int z = (int) tileRaw.get("z"); - - BlockState block = clipboard.getBlock(x, y, z); - for (NBTCompatibilityHandler compat : COMPATIBILITY_HANDLERS) { - if (compat.isAffectedBlock(block)) { - block = compat.updateNBT(block, tile.getValue()); - BaseBlock baseBlock = block.toBaseBlock(tile); - clipboard.setBlock(x, y, z, baseBlock); - continue outer; - } - } - clipboard.setTile(x, y, z, tile); - } - } - - // entities - if (entities != null && !entities.isEmpty()) { - for (Map entRaw : entities) { - String id = (String) entRaw.get("id"); - if (id == null) { - continue; - } - entRaw.put("Id", id); - EntityType type = EntityTypes.parse(id); - if (type != null) { - CompoundTag ent = FaweCache.IMP.asTag(entRaw); - for (EntityNBTCompatibilityHandler compat : ENTITY_COMPATIBILITY_HANDLERS) { - if (compat.isAffectedEntity(type, ent)) { - ent = compat.updateNBT(type, ent); - } - } - BaseEntity state = new BaseEntity(type, ent); - Location loc = ent.getEntityLocation(clipboard); - clipboard.createEntity(loc, state); - } else { - getLogger(SchematicReader.class).debug("Invalid entity: " + id); - } - } - } - fixStates(clipboard); - clipboard.setOrigin(origin); - - BlockVector3 min = BlockVector3.at(originX, originY, originZ); - if (!min.equals(BlockVector3.ZERO)) { - new BlockArrayClipboard(clipboard, min); - } - return clipboard; - } - - private void fixStates(Clipboard fc) { - for (BlockVector3 pos : fc) { - BlockState block = pos.getBlock(fc); - if (block.getMaterial().isAir()) { - continue; - } - - int x = pos.getX(); - int y = pos.getY(); - int z = pos.getZ(); - - BlockType type = block.getBlockType(); - if (BlockCategories.STAIRS.contains(type)) { - Direction facing = block.getState(PropertyKey.FACING); - - BlockVector3 forward = facing.toBlockVector(); - Direction left = facing.getLeft(); - Direction right = facing.getRight(); - - BlockState forwardBlock = fc.getBlock(x + forward.getBlockX(), y + forward.getBlockY(), z + forward.getBlockZ()); - BlockType forwardType = forwardBlock.getBlockType(); - if (forwardType.hasProperty(PropertyKey.SHAPE) && forwardType.hasProperty(PropertyKey.FACING)) { - Direction forwardFacing = forwardBlock.getState(PropertyKey.FACING); - if (forwardFacing == left) { - BlockState rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ()); - BlockType rightType = rightBlock.getBlockType(); - if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) { - pos.setBlock(fc, block.with(PropertyKey.SHAPE, "inner_left")); - } - return; - } else if (forwardFacing == right) { - BlockState leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ()); - BlockType leftType = leftBlock.getBlockType(); - if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) { - fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_right")); - } - return; - } - } - - BlockState backwardsBlock = fc.getBlock(x - forward.getBlockX(), y - forward.getBlockY(), z - forward.getBlockZ()); - BlockType backwardsType = backwardsBlock.getBlockType(); - if (backwardsType.hasProperty(PropertyKey.SHAPE) && backwardsType.hasProperty(PropertyKey.FACING)) { - Direction backwardsFacing = (Direction) backwardsBlock.getState(PropertyKey.FACING); - if (backwardsFacing == left) { - BlockState rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ()); - BlockType rightType = rightBlock.getBlockType(); - if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) { - pos.setBlock(fc, block.with(PropertyKey.SHAPE, "outer_left")); - } - return; - } else if (backwardsFacing == right) { - BlockState leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ()); - BlockType leftType = leftBlock.getBlockType(); - if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) { - pos.setBlock(fc, block.with(PropertyKey.SHAPE, "outer_right")); - } - return; - } - } - } else { - int group = group(type); - if (group == -1) { - return; - } - BlockState set = block; - - if (set.getState(PropertyKey.NORTH) == Boolean.FALSE && merge(fc, group, x, y, z - 1)) { - set = set.with(PropertyKey.NORTH, true); - } - if (set.getState(PropertyKey.EAST) == Boolean.FALSE && merge(fc, group, x + 1, y, z)) { - set = set.with(PropertyKey.EAST, true); - } - if (set.getState(PropertyKey.SOUTH) == Boolean.FALSE && merge(fc, group, x, y, z + 1)) { - set = set.with(PropertyKey.SOUTH, true); - } - if (set.getState(PropertyKey.WEST) == Boolean.FALSE && merge(fc, group, x - 1, y, z)) { - set = set.with(PropertyKey.WEST, true); - } - - if (group == 2) { - int ns = (set.getState(PropertyKey.NORTH) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.SOUTH) ? 1 : 0); - int ew = (set.getState(PropertyKey.EAST) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.WEST) ? 1 : 0); - if (Math.abs(ns - ew) != 2 || fc.getBlock(x, y + 1, z).getBlockType().getMaterial().isSolid()) { - set = set.with(PropertyKey.UP, true); - } - } - - if (set != block) { - pos.setBlock(fc, set); - } - } - } - } - - - private BlockTypeSwitch fullCube = new BlockTypeSwitchBuilder<>(false).add(type -> { - BlockMaterial mat = type.getMaterial(); - return (mat.isFullCube() && !mat.isFragileWhenPushed() && mat.getLightValue() == 0 && mat.isOpaque() && mat.isSolid() && !mat.isTranslucent()); - }, true).build(); - - private boolean merge(Clipboard fc, int group, int x, int y, int z) { - BlockState block = fc.getBlock(x, y, z); - BlockType type = block.getBlockType(); - return group(type) == group || fullCube.apply(type); - } - - private int group(BlockType type) { - switch (type.getInternalId()) { - case BlockID.ACACIA_FENCE: - case BlockID.BIRCH_FENCE: - case BlockID.DARK_OAK_FENCE: - case BlockID.JUNGLE_FENCE: - case BlockID.OAK_FENCE: - case BlockID.SPRUCE_FENCE: - return 0; - case BlockID.NETHER_BRICK_FENCE: - return 1; - case BlockID.COBBLESTONE_WALL: - case BlockID.MOSSY_COBBLESTONE_WALL: - return 2; - case BlockID.IRON_BARS: - case BlockID.BLACK_STAINED_GLASS_PANE: - case BlockID.BLUE_STAINED_GLASS_PANE: - case BlockID.BROWN_MUSHROOM_BLOCK: - case BlockID.BROWN_STAINED_GLASS_PANE: - case BlockID.CYAN_STAINED_GLASS_PANE: - case BlockID.GLASS_PANE: - case BlockID.GRAY_STAINED_GLASS_PANE: - case BlockID.GREEN_STAINED_GLASS_PANE: - case BlockID.LIGHT_BLUE_STAINED_GLASS_PANE: - case BlockID.LIGHT_GRAY_STAINED_GLASS_PANE: - case BlockID.LIME_STAINED_GLASS_PANE: - case BlockID.MAGENTA_STAINED_GLASS_PANE: - case BlockID.ORANGE_STAINED_GLASS_PANE: - case BlockID.PINK_STAINED_GLASS_PANE: - case BlockID.PURPLE_STAINED_GLASS_PANE: - case BlockID.RED_STAINED_GLASS_PANE: - case BlockID.WHITE_STAINED_GLASS_PANE: - case BlockID.YELLOW_STAINED_GLASS_PANE: - return 3; - default: - return -1; - } - } - - @Override - public void close() throws IOException { - inputStream.close(); - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java index 53e05567c..d3e6f2685 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java @@ -68,7 +68,6 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Reads schematic files using the Sponge Schematic Specification. */ -@Deprecated // High mem usage + slow public class SpongeSchematicReader extends NBTSchematicReader { private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.class); @@ -93,7 +92,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { Map schematic = schematicTag.getValue(); final Platform platform = WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.WORLD_EDITING); + .queryCapability(Capability.WORLD_EDITING); int liveDataVersion = platform.getDataVersion(); if (schematicVersion == 1) { @@ -102,17 +101,23 @@ public class SpongeSchematicReader extends NBTSchematicReader { return readVersion1(schematicTag); } else if (schematicVersion == 2) { dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); + if (dataVersion < 0) { + log.warn("Schematic has an unknown data version ({}). Data may be incompatible.", + dataVersion); + // Do not DFU unknown data + dataVersion = liveDataVersion; + } if (dataVersion > liveDataVersion) { log.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.", - dataVersion, liveDataVersion); + dataVersion, liveDataVersion); } else if (dataVersion < liveDataVersion) { fixer = platform.getDataFixer(); if (fixer != null) { log.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", - dataVersion, liveDataVersion); + dataVersion, liveDataVersion); } else { log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.", - dataVersion, liveDataVersion); + dataVersion, liveDataVersion); } } @@ -130,7 +135,11 @@ public class SpongeSchematicReader extends NBTSchematicReader { if (schematicVersion == 1) { return OptionalInt.of(Constants.DATA_VERSION_MC_1_13_2); } else if (schematicVersion == 2) { - return OptionalInt.of(requireTag(schematic, "DataVersion", IntTag.class).getValue()); + int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); + if (dataVersion < 0) { + return OptionalInt.empty(); + } + return OptionalInt.of(dataVersion); } return OptionalInt.empty(); } catch (IOException e) { @@ -140,9 +149,6 @@ public class SpongeSchematicReader extends NBTSchematicReader { private CompoundTag getBaseTag() throws IOException { NamedTag rootTag = inputStream.readNamedTag(); - if (!rootTag.getName().equals("Schematic")) { - throw new IOException("Tag 'Schematic' does not exist or is not first"); - } CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); // Check @@ -226,9 +232,9 @@ public class SpongeSchematicReader extends NBTSchematicReader { } if (tileEntities != null) { List> tileEntityTags = tileEntities.getValue().stream() - .map(tag -> (CompoundTag) tag) - .map(CompoundTag::getValue) - .collect(Collectors.toList()); + .map(tag -> (CompoundTag) tag) + .map(CompoundTag::getValue) + .collect(Collectors.toList()); for (Map tileEntity : tileEntityTags) { int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); @@ -321,8 +327,8 @@ public class SpongeSchematicReader extends NBTSchematicReader { } BiomeType biome = BiomeTypes.get(key); if (biome == null) { - log.warn("Unknown biome type :" + key + - " in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?"); + log.warn("Unknown biome type :" + key + + " in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?"); } Tag idTag = palettePart.getValue(); if (!(idTag instanceof IntTag)) { @@ -385,8 +391,8 @@ public class SpongeSchematicReader extends NBTSchematicReader { EntityType entityType = EntityTypes.get(id); if (entityType != null) { Location location = NBTConversions.toLocation(clipboard, - requireTag(tags, "Pos", ListTag.class), - requireTag(tags, "Rotation", ListTag.class)); + requireTag(tags, "Pos", ListTag.class), + requireTag(tags, "Rotation", ListTag.class)); BaseEntity state = new BaseEntity(entityType, entityTag); clipboard.createEntity(location, state); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java index c556febf9..b0753f623 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java @@ -19,11 +19,10 @@ package com.sk89q.worldedit.extent.clipboard.io; +import com.boydti.fawe.Fawe; import com.google.common.collect.Maps; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.FloatTag; import com.sk89q.jnbt.IntArrayTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.ListTag; @@ -36,7 +35,6 @@ import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; @@ -56,7 +54,6 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Writes schematic files using the Sponge schematic format. */ -@Deprecated // High mem usage + slow public class SpongeSchematicWriter implements ClipboardWriter { private static final int CURRENT_VERSION = 2; @@ -108,12 +105,13 @@ public class SpongeSchematicWriter implements ClipboardWriter { Map schematic = new HashMap<>(); schematic.put("Version", new IntTag(CURRENT_VERSION)); schematic.put("DataVersion", new IntTag( - WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); Map metadata = new HashMap<>(); metadata.put("WEOffsetX", new IntTag(offset.getBlockX())); metadata.put("WEOffsetY", new IntTag(offset.getBlockY())); metadata.put("WEOffsetZ", new IntTag(offset.getBlockZ())); + metadata.put("FAWEVersion", new IntTag(Fawe.get().getVersion().build)); schematic.put("Metadata", new CompoundTag(metadata)); @@ -123,9 +121,9 @@ public class SpongeSchematicWriter implements ClipboardWriter { // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin' schematic.put("Offset", new IntArrayTag(new int[]{ - min.getBlockX(), - min.getBlockY(), - min.getBlockZ(), + min.getBlockX(), + min.getBlockY(), + min.getBlockZ(), })); int paletteMax = 0; @@ -268,21 +266,6 @@ public class SpongeSchematicWriter implements ClipboardWriter { schematic.put("Entities", new ListTag(CompoundTag.class, entities)); } - public Tag writeVector(Vector3 vector) { - List list = new ArrayList<>(); - list.add(new DoubleTag(vector.getX())); - list.add(new DoubleTag(vector.getY())); - list.add(new DoubleTag(vector.getZ())); - return new ListTag(DoubleTag.class, list); - } - - public Tag writeRotation(Location location) { - List list = new ArrayList<>(); - list.add(new FloatTag(location.getYaw())); - list.add(new FloatTag(location.getPitch())); - return new ListTag(FloatTag.class, list); - } - @Override public void close() throws IOException { outputStream.close(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java index 5144f4498..873f5b5bd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java @@ -24,9 +24,8 @@ import com.sk89q.jnbt.CompoundTagBuilder; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.registry.state.DirectionalProperty; -import com.sk89q.worldedit.registry.state.IntegerProperty; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; @@ -38,15 +37,15 @@ import java.util.Map; public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler { - private static final DirectionalProperty FacingProperty; - private static final IntegerProperty RotationProperty; + private static final Property FacingProperty; + private static final Property RotationProperty; static { - DirectionalProperty tempFacing; - IntegerProperty tempRotation; + Property tempFacing; + Property tempRotation; try { - tempFacing = (DirectionalProperty) (Property) BlockTypes.WHITE_WALL_BANNER.getProperty("facing"); - tempRotation = (IntegerProperty) (Property) BlockTypes.WHITE_BANNER.getProperty("rotation"); + tempFacing = BlockTypes.WHITE_WALL_BANNER.getProperty("facing"); + tempRotation = BlockTypes.WHITE_BANNER.getProperty("rotation"); } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { tempFacing = null; tempRotation = null; @@ -62,7 +61,7 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler } @Override - public > B updateNBT(B block, Map values) { + public > BlockStateHolder updateNBT(B block, Map values) { Tag typeTag = values.get("Base"); if (typeTag instanceof IntTag) { boolean isWall = block.getBlockType() == BlockTypes.WHITE_WALL_BANNER; @@ -73,10 +72,10 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler BlockState state = type.getDefaultState(); if (isWall) { - Property facingProp = type.getProperty("facing"); + Property facingProp = type.getProperty("facing"); state = state.with(facingProp, block.getState(FacingProperty)); } else { - Property rotationProp = type.getProperty("rotation"); + Property rotationProp = type.getProperty("rotation"); state = state.with(rotationProp, block.getState(RotationProperty)); } @@ -102,7 +101,7 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler } values.put("Patterns", new ListTag(((ListTag) patternsTag).getType(), tempList)); } - return (B) state; + return state; } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java index b7414b238..d95c2ac92 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java @@ -21,9 +21,8 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.registry.state.DirectionalProperty; -import com.sk89q.worldedit.registry.state.EnumProperty; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; @@ -31,23 +30,24 @@ import com.sk89q.worldedit.world.block.BlockTypes; import java.util.Map; +@SuppressWarnings("") public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler { - private static final DirectionalProperty FacingProperty; - private static final EnumProperty PartProperty; + private static final Property FACING_PROPERTY; + private static final Property PART_PROPERTY; static { - DirectionalProperty tempFacing; - EnumProperty tempPart; + Property tempFacing; + Property tempPart; try { - tempFacing = (DirectionalProperty) (Property) BlockTypes.RED_BED.getProperty("facing"); - tempPart = (EnumProperty) (Property) BlockTypes.RED_BED.getProperty("part"); + tempFacing = BlockTypes.RED_BED.getProperty("facing"); + tempPart = BlockTypes.RED_BED.getProperty("part"); } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { tempFacing = null; tempPart = null; } - FacingProperty = tempFacing; - PartProperty = tempPart; + FACING_PROPERTY = tempFacing; + PART_PROPERTY = tempPart; } @Override @@ -56,7 +56,7 @@ public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler { } @Override - public > B updateNBT(B block, Map values) { + public > BlockStateHolder updateNBT(B block, Map values) { Tag typeTag = values.get("color"); if (typeTag instanceof IntTag) { String bedType = convertBedType(((IntTag) typeTag).getValue()); @@ -65,17 +65,17 @@ public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler { if (type != null) { BlockState state = type.getDefaultState(); - Property facingProp = type.getProperty("facing"); - state = state.with(facingProp, block.getState(FacingProperty)); + Property facingProp = type.getProperty("facing"); + state = state.with(facingProp, block.getState(FACING_PROPERTY)); - Property occupiedProp = type.getProperty("occupied"); + Property occupiedProp = type.getProperty("occupied"); state = state.with(occupiedProp, false); - Property partProp = type.getProperty("part"); - state = state.with(partProp, block.getState(PartProperty)); + Property partProp = type.getProperty("part"); + state = state.with(partProp, block.getState(PART_PROPERTY)); values.remove("color"); - return (B) state; + return state; } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java index 826fb46ce..f49779656 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java @@ -37,12 +37,12 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { } @Override - public > B updateNBT(B block, Map values) { + public > BlockStateHolder updateNBT(B block, Map values) { Tag item = values.get("Item"); if (item instanceof StringTag) { String id = ((StringTag) item).getValue(); if (id.isEmpty()) { - return (B) BlockTypes.FLOWER_POT.getDefaultState(); + return BlockTypes.FLOWER_POT.getDefaultState(); } int data = 0; Tag dataTag = values.get("Data"); @@ -52,7 +52,7 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { BlockState newState = convertLegacyBlockType(id, data); if (newState != null) { values.clear(); - return (B) newState; // generics pls :\ + return newState; } } return block; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java index af4011ad8..efded2896 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java @@ -26,5 +26,6 @@ import java.util.Map; public interface NBTCompatibilityHandler { > boolean isAffectedBlock(B block); - > B updateNBT(B block, Map values); + + > BlockStateHolder updateNBT(B block, Map values); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java index b425d1373..01d01cc92 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java @@ -47,7 +47,7 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { } @Override - public > B updateNBT(B block, Map values) { + public > BlockStateHolder updateNBT(B block, Map values) { // note that instrument was not stored (in state or nbt) previously. // it will be updated to the block below when it gets set into the world for the first time Tag noteTag = values.get("note"); @@ -55,7 +55,7 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { Byte note = ((ByteTag) noteTag).getValue(); if (note != null) { values.clear(); - return (B) block.with(NoteProperty, (int) note).toImmutableState(); + return block.with(NoteProperty, (int) note).toImmutableState(); } } return block; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java index 664faf1da..ea21e7b10 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java @@ -26,8 +26,8 @@ import com.google.gson.JsonPrimitive; import com.google.gson.JsonSyntaxException; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.internal.util.DeprecationUtil; import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockTypes; import java.util.Map; @@ -35,11 +35,11 @@ public class SignCompatibilityHandler implements NBTCompatibilityHandler { @Override public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.SIGN || block.getBlockType() == BlockTypes.WALL_SIGN; + return DeprecationUtil.isSign(block.getBlockType()); } @Override - public > B updateNBT(B block, Map values) { + public > BlockStateHolder updateNBT(B block, Map values) { for (int i = 0; i < 4; ++i) { String key = "Text" + (i + 1); Tag value = values.get(key); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java index fe1774095..b728102c7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java @@ -21,8 +21,8 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.registry.state.DirectionalProperty; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; @@ -32,12 +32,12 @@ import java.util.Map; public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { - private static final DirectionalProperty FacingProperty; + private static final Property FacingProperty; static { - DirectionalProperty tempFacing; + Property tempFacing; try { - tempFacing = (DirectionalProperty) (Property) BlockTypes.SKELETON_WALL_SKULL.getProperty("facing"); + tempFacing = BlockTypes.SKELETON_WALL_SKULL.getProperty("facing"); } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { tempFacing = null; } @@ -51,7 +51,7 @@ public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { } @Override - public > B updateNBT(B block, Map values) { + public > BlockStateHolder updateNBT(B block, Map values) { boolean isWall = block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; Tag typeTag = values.get("SkullType"); if (typeTag instanceof ByteTag) { @@ -61,18 +61,18 @@ public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { if (type != null) { BlockState state = type.getDefaultState(); if (isWall) { - Property newProp = type.getProperty("facing"); + Property newProp = type.getProperty("facing"); state = state.with(newProp, block.getState(FacingProperty)); } else { Tag rotTag = values.get("Rot"); if (rotTag instanceof ByteTag) { - Property newProp = type.getProperty("rotation"); + Property newProp = type.getProperty("rotation"); state = state.with(newProp, (int) ((ByteTag) rotTag).getValue()); } } values.remove("SkullType"); values.remove("Rot"); - return (B) state; + return state; } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java index e600929b3..a38a77e04 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockCategoryMask.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nullable; @@ -61,4 +62,9 @@ public class BlockCategoryMask extends AbstractExtentMask { public Mask copy() { return new BlockCategoryMask(getExtent(), category); } + + @Override + public boolean replacesAir() { + return category.contains(BlockTypes.AIR); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java index 665415618..efe910dd3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockMask.java @@ -29,12 +29,12 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.ImmutableBaseBlock; +import javax.annotation.Nullable; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.function.Predicate; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; @@ -185,7 +185,7 @@ public class BlockMask extends ABlockMask { @Override public boolean test(BlockState state) { - return ordinals[state.getOrdinal()] || replacesAir() && state.getOrdinal() <= 3; + return ordinals[state.getOrdinal()] || replacesAir() && state.getOrdinal() == 0; } @Override @@ -259,19 +259,16 @@ public class BlockMask extends ABlockMask { int setTypes = 0; BlockType setType = null; - BlockType unsetType = null; int totalTypes = 0; for (BlockType type : BlockTypesCache.values) { if (type != null) { totalTypes++; boolean hasAll = true; - boolean hasAny = false; List all = type.getAllStates(); for (BlockState state : all) { totalStates++; hasAll &= test(state); - hasAny = true; } if (hasAll) { setTypes++; @@ -326,6 +323,7 @@ public class BlockMask extends ABlockMask { cloned[BlockTypes.AIR.getDefaultState().getOrdinal()] = false; cloned[BlockTypes.CAVE_AIR.getDefaultState().getOrdinal()] = false; cloned[BlockTypes.VOID_AIR.getDefaultState().getOrdinal()] = false; + cloned[0] = false; } return new BlockMask(getExtent(), cloned); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java index ed86f6bc0..2389eb981 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseMask.java @@ -36,4 +36,9 @@ public class InverseMask extends AbstractMask { public Mask copy() { return new InverseMask(mask.copy()); } + + @Override + public boolean replacesAir() { + return mask.replacesAir(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java index fa6da2278..a8dcd3c18 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/InverseSingleBlockTypeMask.java @@ -8,10 +8,12 @@ import com.sk89q.worldedit.world.block.BlockTypesCache; public class InverseSingleBlockTypeMask extends ABlockMask { private final int internalId; + private final boolean replacesAir; public InverseSingleBlockTypeMask(Extent extent, BlockType type) { super(extent); this.internalId = type.getInternalId(); + this.replacesAir = type.getMaterial().isAir(); } @Override @@ -33,4 +35,9 @@ public class InverseSingleBlockTypeMask extends ABlockMask { // The mask is not mutable. There is no need to clone it. return this; } + + @Override + public boolean replacesAir() { + return replacesAir; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java index 2b3968744..ab8b95b0b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskIntersection.java @@ -275,4 +275,14 @@ public class MaskIntersection extends AbstractMask { return new MaskIntersection(masks); } + @Override + public boolean replacesAir() { + for (Mask mask : masksArray) { + if (mask.replacesAir()) { + return true; + } + } + return false; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java index 25174efd6..4adf197de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/MaskUnion.java @@ -118,4 +118,14 @@ public class MaskUnion extends MaskIntersection { Set masksCopy = masks.stream().map(Mask::copy).collect(Collectors.toSet()); return new MaskUnion(masksCopy); } + + @Override + public boolean replacesAir() { + for (Mask mask : getMasksArray()) { + if (mask.replacesAir()) { + return true; + } + } + return false; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java index e4d5488ef..d95ecfc4d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/RepeatingExtentPattern.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.function.pattern; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; import static com.google.common.base.Preconditions.checkNotNull; @@ -88,9 +87,9 @@ public class RepeatingExtentPattern extends AbstractExtentPattern { @Override public BaseBlock apply(BlockVector3 position) { - int x = Math.abs(position.getX() + offset.getX()) % size.getBlockX() + origin.getX(); - int y = Math.abs(position.getY() + offset.getY()) % size.getBlockY() + origin.getY(); - int z = Math.abs(position.getZ() + offset.getZ()) % size.getBlockZ() + origin.getZ(); + int x = Math.floorMod(position.getBlockX() + offset.getBlockX(), size.getBlockX()) + origin.getBlockX(); + int y = Math.floorMod(position.getBlockY() + offset.getBlockY(), size.getBlockY()) + origin.getBlockY(); + int z = Math.floorMod(position.getBlockZ() + offset.getBlockZ(), size.getBlockZ()) + origin.getBlockZ(); return getExtent().getFullBlock(x, y, z); } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 4bfae49f3..108294c80 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -397,7 +397,7 @@ "worldedit.pumpkins.created": "{0} pumpkin patches created.", "worldedit.pyramid.created": "{0} blocks have been created.", "worldedit.generate.created": "{0} blocks have been created.", - "worldedit.generate.changed": "{0} columns affected.", + "worldedit.generatebiome.changed": "{0} biomes affected.", "worldedit.reload.config": "Configuration reloaded!", "worldedit.report.written": "FAWE report written to {0}", diff --git a/worldedit-libs/core/build.gradle.kts b/worldedit-libs/core/build.gradle.kts index 915c530b5..8a025d445 100644 --- a/worldedit-libs/core/build.gradle.kts +++ b/worldedit-libs/core/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { exclude(group = "junit", module = "junit") } "shade"("com.thoughtworks.paranamer:paranamer:2.6") - "shade"("com.github.luben:zstd-jni:1.4.3-1") + "shade"("com.github.luben:zstd-jni:1.4.8-1") "shade"("com.sk89q.lib:jlibnoise:1.0.0") "shade"("org.enginehub.piston:core:${Versions.PISTON}") "shade"("org.enginehub.piston.core-ap:runtime:${Versions.PISTON}")