diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/DelegateLock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/DelegateLock.java index e351f9a23..5dc34791a 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/DelegateLock.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/DelegateLock.java @@ -73,12 +73,12 @@ public class DelegateLock extends ReentrantLockWithGetOwner { @Override public synchronized int getHoldCount() { - throw new UnsupportedOperationException(); + return parent.getHoldCount(); } @Override public synchronized boolean isHeldByCurrentThread() { - throw new UnsupportedOperationException(); + return parent.isHeldByCurrentThread(); } @Override @@ -96,12 +96,12 @@ public class DelegateLock extends ReentrantLockWithGetOwner { @Override public synchronized boolean hasWaiters(Condition condition) { - throw new UnsupportedOperationException(); + return parent.hasWaiters(condition); } @Override public synchronized int getWaitQueueLength(Condition condition) { - throw new UnsupportedOperationException(); + return parent.getWaitQueueLength(condition); } @Override 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 4e67ef329..e5153bcad 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 @@ -104,7 +104,7 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter { } protected static DelegateLock applyLock(ChunkSection section) { - //todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which aquires the lock in NMS? + //todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS? try { synchronized (section) { DataPaletteBlock blocks = section.getBlocks(); 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 965c73d54..3578a5549 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 @@ -221,10 +221,9 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { if (this.sections == null) { this.sections = sections.clone(); } - //TODO: Understand why this causes #329, what the purpose of this is, and what may or may not break after commenting this out. -// if (this.sections[layer] != section) { -// this.sections[layer] = section; -// } + if (this.sections[layer] != section) { + this.sections[layer] = new ChunkSection[]{section}.clone()[0]; + } this.blocks[layer] = arr; } } @@ -299,19 +298,17 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks { synchronized (this) { synchronized (lock) { lock.untilFree(); - ChunkSection getSection; if (this.nmsChunk != nmsChunk) { this.nmsChunk = nmsChunk; this.sections = null; this.reset(); - } else { - getSection = this.getSections()[layer]; - if (getSection != existingSection) { - this.sections[layer] = existingSection; - this.reset(); - } else if (lock.isModified()) { - this.reset(layer); - } + } else if (existingSection != getSections()[layer]) { + this.sections[layer] = existingSection; + this.reset(); + } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { + this.reset(layer); + } else if (lock.isModified()) { + this.reset(layer); } newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr); if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index fd38b7748..2818a8434 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -184,7 +184,7 @@ public class BukkitWorld extends AbstractWorld { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); try { if (adapter != null) { - return adapter.regenerate(getWorld(), region, null, null, editSession); + return adapter.regenerate(getWorld(), region, editSession); } else { throw new UnsupportedOperationException("Missing BukkitImplAdapater for this version."); } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index 7eb54e8f9..591626f0f 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -240,11 +240,7 @@ public interface BukkitImplAdapter extends IBukkitAdapter { * @return true on success, false on failure */ default boolean regenerate(org.bukkit.World world, Region region, EditSession session) { - return regenerate(world, region, null, null, session); - } - - default boolean regenerate(org.bukkit.World world, Region region, @Nullable Long seed, @Nullable BiomeType biome, EditSession editSession) { - return editSession.regenerate(region); + return session.regenerate(region); } default IChunkGet get(World world, int chunkX, int chunkZ) { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_14_R4.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_14_R4.java index a3dc483f3..b5094f0db 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_14_R4.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_14_R4.java @@ -54,6 +54,7 @@ import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.server.v1_14_R1.*; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.World.Environment; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; @@ -361,7 +362,7 @@ public final class FAWE_Spigot_v1_14_R4 extends CachedBukkitAdapter implements I } @Override - public boolean regenerate(org.bukkit.World world, Region region, @Nullable Long seed, @Nullable BiomeType biome, EditSession editSession) { + public boolean regenerate(org.bukkit.World world, Region region, EditSession editSession) { WorldServer originalWorld = ((CraftWorld) world).getHandle(); ChunkProviderServer provider = originalWorld.getChunkProvider(); if (!(provider instanceof ChunkProviderServer)) { @@ -379,26 +380,16 @@ public final class FAWE_Spigot_v1_14_R4 extends CachedBukkitAdapter implements I WorldData newWorldData = new WorldData(originalWorld.worldData.a((NBTTagCompound) null), server.dataConverterManager, getDataVersion(), null); - ChunkGenerator generator = world.getGenerator(); - org.bukkit.World.Environment environment = world.getEnvironment(); - if (seed != null) { - if (biome == BiomeTypes.NETHER) { - environment = org.bukkit.World.Environment.NETHER; - } else if (biome == BiomeTypes.THE_END) { - environment = org.bukkit.World.Environment.THE_END; - } else { - environment = org.bukkit.World.Environment.NORMAL; - } - generator = null; - } + ChunkGenerator gen = world.getGenerator(); + Environment env = world.getEnvironment(); try (WorldServer freshWorld = new WorldServer(server, server.executorService, saveHandler, newWorldData, originalWorld.worldProvider.getDimensionManager(), originalWorld.getMethodProfiler(), server.worldLoadListenerFactory.create(11), - environment, - generator){ + env, + gen){ @Override public boolean addEntityChunk(net.minecraft.server.v1_14_R1.Entity entity) { //Fixes #320; Prevent adding entities so we aren't attempting to spawn them asynchronously diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_15_R1.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_15_R1.java index ce6091bb9..49dfea72f 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_15_R1.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/FAWE_Spigot_v1_15_R1.java @@ -56,6 +56,7 @@ import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.server.v1_15_R1.*; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.World.Environment; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_15_R1.CraftChunk; import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; @@ -368,7 +369,7 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I } @Override - public boolean regenerate(org.bukkit.World world, Region region, @Nullable Long seed, @Nullable BiomeType biome, EditSession editSession) { + public boolean regenerate(org.bukkit.World world, Region region, EditSession editSession) { WorldServer originalWorld = ((CraftWorld) world).getHandle(); ChunkProviderServer provider = originalWorld.getChunkProvider(); if (!(provider instanceof ChunkProviderServer)) { @@ -387,26 +388,16 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I server.dataConverterManager, getDataVersion(), null); newWorldData.setName(UUID.randomUUID().toString()); - ChunkGenerator generator = world.getGenerator(); - org.bukkit.World.Environment environment = world.getEnvironment(); - if (seed != null) { - if (biome == BiomeTypes.NETHER) { - environment = org.bukkit.World.Environment.NETHER; - } else if (biome == BiomeTypes.THE_END) { - environment = org.bukkit.World.Environment.THE_END; - } else { - environment = org.bukkit.World.Environment.NORMAL; - } - generator = null; - } + ChunkGenerator gen = world.getGenerator(); + Environment env = world.getEnvironment(); try (WorldServer freshWorld = new WorldServer(server, server.executorService, saveHandler, newWorldData, originalWorld.worldProvider.getDimensionManager(), originalWorld.getMethodProfiler(), server.worldLoadListenerFactory.create(11), - environment, - generator){ + env, + gen){ @Override public boolean addEntityChunk(net.minecraft.server.v1_15_R1.Entity entity) { //Fixes #320; Prevent adding entities so we aren't attempting to spawn them asynchronously 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 e384bd4e4..3ee354bd6 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 @@ -56,6 +56,7 @@ import com.sk89q.worldedit.world.registry.BlockMaterial; import net.minecraft.server.v1_15_R1.*; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.World.Environment; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_15_R1.CraftChunk; import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; @@ -370,7 +371,7 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I } @Override - public boolean regenerate(org.bukkit.World world, Region region, @Nullable Long seed, @Nullable BiomeType biome, EditSession editSession) { + public boolean regenerate(org.bukkit.World world, Region region, EditSession editSession) { WorldServer originalWorld = ((CraftWorld) world).getHandle(); ChunkProviderServer provider = originalWorld.getChunkProvider(); if (!(provider instanceof ChunkProviderServer)) { @@ -389,26 +390,16 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I server.dataConverterManager, getDataVersion(), null); newWorldData.setName(UUID.randomUUID().toString()); - ChunkGenerator generator = world.getGenerator(); - org.bukkit.World.Environment environment = world.getEnvironment(); - if (seed != null) { - if (biome == BiomeTypes.NETHER) { - environment = org.bukkit.World.Environment.NETHER; - } else if (biome == BiomeTypes.THE_END) { - environment = org.bukkit.World.Environment.THE_END; - } else { - environment = org.bukkit.World.Environment.NORMAL; - } - generator = null; - } + ChunkGenerator gen = world.getGenerator(); + Environment env = world.getEnvironment(); try (WorldServer freshWorld = new WorldServer(server, server.executorService, saveHandler, newWorldData, originalWorld.worldProvider.getDimensionManager(), originalWorld.getMethodProfiler(), server.worldLoadListenerFactory.create(11), - environment, - generator){ + env, + gen){ @Override public boolean addEntityChunk(net.minecraft.server.v1_15_R1.Entity entity) { //Fixes #320; Prevent adding entities so we aren't attempting to spawn them asynchronously diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index 0b17c0202..f88a2a6ac 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -31,7 +31,7 @@ dependencies { "compile"(project(":worldedit-libs:core")) "compile"("de.schlichtherle:truezip:6.8.3") "compile"("net.java.truevfs:truevfs-profile-default_2.13:0.12.1") - "compile"("org.mozilla:rhino:1.7.11") + "compile"("org.mozilla:rhino-runtime:1.7.12") "compile"("org.yaml:snakeyaml:1.23") "compile"("com.google.guava:guava:21.0") "compile"("com.google.code.findbugs:jsr305:3.0.2") diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/ChunkHolder.java index 443c310ff..50fa4e8ca 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/chunk/ChunkHolder.java @@ -243,6 +243,7 @@ public class ChunkHolder> implements IQueueChunk { public IChunkGet get(ChunkHolder chunk) { chunk.getOrCreateGet(); chunk.delegate = BOTH; + chunk.chunkExisting.trim(false); return chunk.chunkExisting; } @@ -271,6 +272,7 @@ public class ChunkHolder> implements IQueueChunk { public BiomeType getBiome(ChunkHolder chunk, int x, int y, int z) { chunk.getOrCreateGet(); chunk.delegate = GET; + chunk.chunkExisting.trim(false); return chunk.getBiomeType(x, y, z); } @@ -278,6 +280,7 @@ public class ChunkHolder> implements IQueueChunk { public BlockState getBlock(ChunkHolder chunk, int x, int y, int z) { chunk.getOrCreateGet(); chunk.delegate = GET; + chunk.chunkExisting.trim(false); return chunk.getBlock(x, y, z); } @@ -286,6 +289,7 @@ public class ChunkHolder> implements IQueueChunk { int z) { chunk.getOrCreateGet(); chunk.delegate = GET; + chunk.chunkExisting.trim(false); return chunk.getFullBlock(x, y, z); } }; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/QueueHandler.java index fc9ef1af8..60a8e5bb8 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/QueueHandler.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/QueueHandler.java @@ -167,7 +167,7 @@ public abstract class QueueHandler implements Trimable, Runnable { return sync(call, syncTasks); } - // Lower priorty sync task (runs only when there are no other tasks) + // Lower priority sync task (runs only when there are no other tasks) public Future syncWhenFree(Runnable run, T value) { return sync(run, value, syncWhenFree); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java index c97b3c5cc..b5bbaba4c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ReadOnlyClipboard.java @@ -61,7 +61,7 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard { if (current.getWorld().equals(world)) { return current; } - throw new UnsupportedOperationException("TODO: Cannot lazy copy accross worlds (bug jesse)"); + throw new UnsupportedOperationException("TODO: Cannot lazy copy across worlds (bug jesse)"); } throw new IllegalStateException("No world"); }; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/SparseBitSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/SparseBitSet.java index 79055a77b..0aa67d72d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/SparseBitSet.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/SparseBitSet.java @@ -100,7 +100,7 @@ public class SparseBitSet implements Cloneable, Serializable bits (setting, flipping, clearing, etc.) do not attempt to normalize the set, in the interests of speed. However, when a set is scanned as the resultant set of some operation, then, in most cases, the set will be - normalized--the exception being level2 areas that are not completly scanned + normalized--the exception being level2 areas that are not completely scanned in a particular pass. The sizes of the blocks and areas has been the result of some investigation @@ -338,8 +338,8 @@ public class SparseBitSet implements Cloneable, Serializable * needed actions to initialise the bit set. *

* The capacity is taken to be a suggestion for a size of the bit set, - * in bits. An appropiate table size (a power of two) is then determined and - * used. The size will be grown as needed to accomodate any bits addressed + * in bits. An appropriate table size (a power of two) is then determined and + * used. The size will be grown as needed to accommodate any bits addressed * during the use of the bit set. * * @param capacity a size in terms of bits @@ -530,7 +530,7 @@ public class SparseBitSet implements Cloneable, Serializable } /** - * Creates a bit set from thie first SparseBitSet whose + * Creates a bit set from the first SparseBitSet whose * corresponding bits are cleared by the set bits of the second * SparseBitSet. The resulting bit set is created so that a bit * in it has the value true if and only if the corresponding bit @@ -1669,7 +1669,7 @@ public class SparseBitSet implements Cloneable, Serializable } /** - * Intializes all the additional objects required for correct operation. + * Initializes all the additional objects required for correct operation. * * @since 1.6 */ 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 548cbc78a..a3dfdd2f8 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 @@ -513,11 +513,11 @@ public class MainUtil { } try (FileInputStream fIn = new FileInputStream(sourceFile); FileChannel source = fIn.getChannel(); FileOutputStream fOut = new FileOutputStream(destFile); FileChannel destination = fOut.getChannel()) { - long transfered = 0; + long transferred = 0; long bytes = source.size(); - while (transfered < bytes) { - transfered += destination.transferFrom(source, 0, source.size()); - destination.position(transfered); + while (transferred < bytes) { + transferred += destination.transferFrom(source, 0, source.size()); + destination.position(transferred); } } return destFile; 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 3bae038c9..97505fd85 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 @@ -131,13 +131,13 @@ public class ReflectionUtils { } } - public static T callConstructor(Constructor constructor, Object... paramaters) { + public static T callConstructor(Constructor constructor, Object... parameters) { if (constructor == null) { throw new RuntimeException("No such constructor"); } constructor.setAccessible(true); try { - return constructor.newInstance(paramaters); + return constructor.newInstance(parameters); } catch (InvocationTargetException ex) { throw new RuntimeException(ex.getCause()); } catch (Exception ex) { diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java index 09582039d..aba4d40a5 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/ReflectionUtils9.java @@ -37,7 +37,7 @@ public class ReflectionUtils9 { // 3. build new enum T newValue = (T) makeEnum(enumType, // The target enum class enumName, // THE NEW ENUM INSTANCE TO BE DYNAMICALLY ADDED - values.size()); // can be used to pass values to the enum constuctor + values.size()); // can be used to pass values to the enum constructor // 4. add new value values.add(newValue); 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 0199ad04b..1941d9508 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -72,7 +72,7 @@ public final class NBTUtils { } else if (clazz.equals(LongArrayTag.class)) { return "TAG_Long_Array"; } else { - throw new IllegalArgumentException("Invalid tag classs (" + throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")."); } } @@ -112,7 +112,7 @@ public final class NBTUtils { } else if (clazz.equals(LongArrayTag.class)) { return NBTConstants.TYPE_LONG_ARRAY; } else { - throw new IllegalArgumentException("Invalid tag classs (" + throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java index dd4bf4b29..1aceda930 100644 --- a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java @@ -36,7 +36,7 @@ public final class StringUtil { /** * Trim a string if it is longer than a certain length. * - * @param str the stirng + * @param str the string * @param len the length to trim to * @return a new string */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformInitializeEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformInitializeEvent.java index 49aeecd2b..03ae4565c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformInitializeEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/PlatformInitializeEvent.java @@ -23,7 +23,7 @@ import com.sk89q.worldedit.event.Event; /** * Fired when configuration has been loaded and the platform is in the - * intialization stage. + * initialization stage. * *

This event is fired once.

*/ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java index eaf4fe3d1..19bc026b6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultBlockParser.java @@ -381,6 +381,14 @@ public class DefaultBlockParser extends InputParser { // Check if the item is allowed BlockType blockType = state.getBlockType(); + + if (context.isRestricted()) { + Actor actor = context.requireActor(); + if (actor != null && !actor.hasPermission("worldedit.anyblock") + && worldEdit.getConfiguration().disallowedBlocks.contains(blockType.getId())) { + throw new DisallowedUsageException("You are not allowed to use '" + input + "'"); + } + } if (nbt != null) return validate(context, state.toBaseBlock(nbt)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java index f7daa16be..30d7c633d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/invoke/CompilingVisitor.java @@ -84,7 +84,7 @@ class CompilingVisitor extends ExpressionBaseVisitor { * General idea is that we don't need to pass around variables, they're all in ExecutionData. * We do need to pass that around, so most MethodHandles will be of the type * (ExecutionData)Double, with a few as (ExecutionData,Double)Double where it needs an existing - * value passed in. EVERY handle returned from an overriden method must be of the first type. + * value passed in. EVERY handle returned from an overridden method must be of the first type. */ private final Functions functions; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java index 3286d63f5..e38f2a9c2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/RegionSelector.java @@ -93,7 +93,7 @@ public interface RegionSelector { void explainSecondarySelection(Actor actor, LocalSession session, BlockVector3 position); /** - * The the player information about the region's changes. This may resend + * Tell the player information about the region's changes. This may resend * all the defining region information if needed. * * @param actor the actor diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java index 8cad2670b..8d56d86db 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/RhinoCraftScriptEngine.java @@ -19,7 +19,10 @@ package com.sk89q.worldedit.scripting; +import com.google.common.io.CharStreams; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.scripting.compat.BabelScriptTranspiler; +import com.sk89q.worldedit.scripting.compat.ScriptTranspiler; import org.mozilla.javascript.Context; import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.JavaScriptException; @@ -28,11 +31,13 @@ import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.WrappedException; +import javax.script.ScriptException; +import java.io.StringReader; import java.util.Map; -import javax.script.ScriptException; - public class RhinoCraftScriptEngine implements CraftScriptEngine { + + private static final ScriptTranspiler TRANSPILER = new BabelScriptTranspiler(); private int timeLimit; @Override @@ -48,6 +53,7 @@ public class RhinoCraftScriptEngine implements CraftScriptEngine { @Override public Object evaluate(String script, String filename, Map args) throws ScriptException, Throwable { + String transpiled = CharStreams.toString(TRANSPILER.transpile(new StringReader(script))); RhinoContextFactory factory = new RhinoContextFactory(timeLimit); Context cx = factory.enterContext(); cx.setClassShutter(new MinecraftHidingClassShutter()); @@ -59,7 +65,7 @@ public class RhinoCraftScriptEngine implements CraftScriptEngine { Context.javaToJS(entry.getValue(), scope)); } try { - return cx.evaluateString(scope, script, filename, 1, null); + return cx.evaluateString(scope, transpiled, filename, 1, null); } catch (Error e) { throw new ScriptException(e.getMessage()); } catch (RhinoException e) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/BabelScriptTranspiler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/BabelScriptTranspiler.java new file mode 100644 index 000000000..5fe83c587 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/BabelScriptTranspiler.java @@ -0,0 +1,83 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.scripting.compat; + +import com.google.common.io.CharStreams; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.Scriptable; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.util.concurrent.TimeUnit; + +public class BabelScriptTranspiler implements ScriptTranspiler { + + private static final RemoteScript BABEL = new RemoteScript( + "https://unpkg.com/@babel/standalone@7.9/babel.min.js", + "babel.min.js", + new RemoteScript( + "https://unpkg.com/core-js-bundle@3.6.5/index.js", + "core-js-bundle.js" + ), + new RemoteScript( + "https://unpkg.com/regenerator-runtime@0.13.5/runtime.js", + "regenerator-runtime.js" + ) + ); + + private final ContextFactory contextFactory = new ContextFactory() { + @Override + protected Context makeContext() { + Context context = super.makeContext(); + context.setLanguageVersion(Context.VERSION_ES6); + return context; + } + }; + private final Function executeBabel; + + public BabelScriptTranspiler() { + Scriptable babel = BABEL.getScope(); + executeBabel = contextFactory.call(ctx -> { + ctx.setOptimizationLevel(9); + String execBabelSource = "function(source) {\n" + + "return Babel.transform(source, { presets: ['env'] }).code;\n" + + "}\n"; + return ctx.compileFunction( + babel, execBabelSource, "", 1, null + ); + }); + } + + @Override + public Reader transpile(Reader script) throws IOException { + long startTranspile = System.nanoTime(); + Scriptable babel = BABEL.getScope(); + String source = CharStreams.toString(script); + String result = (String) contextFactory.call(ctx -> + executeBabel.call(ctx, babel, null, new Object[] { source }) + ); + System.err.println(result); + System.err.println("Took " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTranspile)); + return new StringReader(result); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/RemoteScript.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/RemoteScript.java new file mode 100644 index 000000000..ee59db817 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/RemoteScript.java @@ -0,0 +1,120 @@ +package com.sk89q.worldedit.scripting.compat; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.util.net.HttpRequest; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.TopLevel; + +import java.io.IOException; +import java.io.Reader; +import java.io.UncheckedIOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import static com.google.common.base.Preconditions.checkState; + +public class RemoteScript { + + private static final int MAX_REDIRECTS = 100; + + + private final ContextFactory contextFactory = new ContextFactory() { + @Override + protected boolean hasFeature(Context cx, int featureIndex) { + if (featureIndex == Context.FEATURE_OLD_UNDEF_NULL_THIS) { + return true; + } + return super.hasFeature(cx, featureIndex); + } + + @Override + protected Context makeContext() { + Context context = super.makeContext(); + context.setLanguageVersion(Context.VERSION_ES6); + return context; + } + }; + private final Path cacheDir = WorldEdit.getInstance() + .getWorkingDirectoryFile("craftscripts/.cache").toPath(); + private final URL source; + private final String cacheFileName; + private final Path cachePath; + private final List dependencies; + + private volatile Scriptable cachedScope; + + public RemoteScript(String source, String cacheFileName, RemoteScript... dependencies) { + this.source = HttpRequest.url(source); + this.cacheFileName = cacheFileName; + this.cachePath = cacheDir.resolve(cacheFileName); + this.dependencies = ImmutableList.copyOf(dependencies); + } + + private synchronized void ensureCached() throws IOException { + if (!Files.exists(cacheDir)) { + Files.createDirectories(cacheDir); + } + if (!Files.exists(cachePath)) { + boolean downloadedBabel = false; + int redirects = 0; + URL url = source; + while (redirects < MAX_REDIRECTS && !downloadedBabel) { + try (HttpRequest request = HttpRequest.get(url)) { + request.execute(); + request.expectResponseCode(200, 301, 302); + if (request.getResponseCode() > 300) { + redirects++; + url = HttpRequest.url(request.getSingleHeaderValue("Location")); + continue; + } + request.saveContent(cachePath.toFile()); + downloadedBabel = true; + } + } + checkState(downloadedBabel, "Too many redirects following: %s", url); + checkState(Files.exists(cachePath), "Failed to actually download %s", cacheFileName); + } + } + + protected synchronized void loadIntoScope(Context ctx, Scriptable scope) { + try { + ensureCached(); + try (Reader reader = Files.newBufferedReader(cachePath)) { + ctx.evaluateReader(scope, reader, cacheFileName, 1, null); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Get a scope that the script has been evaluated in. + * + * @return the scope + */ + public synchronized Scriptable getScope() { + if (cachedScope != null) { + return cachedScope; + } + + // parse + execute standalone script to load it into the scope + cachedScope = contextFactory.call(ctx -> { + ScriptableObject scriptable = new TopLevel(); + Scriptable newScope = ctx.initStandardObjects(scriptable); + ctx.setOptimizationLevel(9); + for (RemoteScript dependency : dependencies) { + dependency.loadIntoScope(ctx, newScope); + } + loadIntoScope(ctx, newScope); + return newScope; + }); + + return cachedScope; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/ScriptTranspiler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/ScriptTranspiler.java new file mode 100644 index 000000000..884b9cef4 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/compat/ScriptTranspiler.java @@ -0,0 +1,38 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.scripting.compat; + +import java.io.IOException; +import java.io.Reader; + +/** + * Transpile a script from one (version) of a language to another. + */ +public interface ScriptTranspiler { + + /** + * Given input {@code script}, return the transpiled script. + * + * @param script the script to transpile + * @return the new script + */ + Reader transpile(Reader script) throws IOException; + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java index 8421210e4..ba0e7fef9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/net/HttpRequest.java @@ -43,6 +43,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static com.google.common.base.Preconditions.checkState; + public class HttpRequest implements Closeable { private static final int CONNECT_TIMEOUT = 1000 * 5; @@ -200,6 +202,13 @@ public class HttpRequest implements Closeable { return conn.getResponseCode(); } + public String getSingleHeaderValue(String header) { + checkState(conn != null, "No connection has been made"); + + // maybe we should check for multi-header? + return conn.getHeaderField(header); + } + /** * Get the input stream. * @@ -214,9 +223,8 @@ public class HttpRequest implements Closeable { * * @return the buffered response * @throws java.io.IOException on I/O error - * @throws InterruptedException on interruption */ - public BufferedResponse returnContent() throws IOException, InterruptedException { + public BufferedResponse returnContent() throws IOException { if (inputStream == null) { throw new IllegalArgumentException("No input stream available"); } @@ -239,9 +247,8 @@ public class HttpRequest implements Closeable { * @param file the file * @return this object * @throws java.io.IOException on I/O error - * @throws InterruptedException on interruption */ - public HttpRequest saveContent(File file) throws IOException, InterruptedException { + public HttpRequest saveContent(File file) throws IOException { Closer closer = Closer.create(); try { @@ -262,9 +269,8 @@ public class HttpRequest implements Closeable { * @param out the output stream * @return this object * @throws java.io.IOException on I/O error - * @throws InterruptedException on interruption */ - public HttpRequest saveContent(OutputStream out) throws IOException, InterruptedException { + public HttpRequest saveContent(OutputStream out) throws IOException { BufferedInputStream bis; try { diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index 9441e7abb..23d52162d 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -88,10 +88,10 @@ tasks.named("shadowJar") { include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) include(dependency("de.schlichtherle:truezip")) include(dependency("net.java.truevfs:truevfs-profile-default_2.13")) - include(dependency("org.mozilla:rhino")) + include(dependency("org.mozilla:rhino-runtime")) } minimize { - exclude(dependency("org.mozilla:rhino")) + exclude(dependency("org.mozilla:rhino-runtime")) } }